Documentation
¶
Overview ¶
Package certs provides helpers around certificates.
Index ¶
- Constants
- Variables
- func GenerateKey(kty string) crypto.PrivateKey
- func GetSAN(c *x509.Certificate) ([]string, error)
- func GetSANRequest(req *http.Request) ([]string, error)
- func IDFromCert(c []*x509.Certificate) string
- func IDFromPublicKeyBytes(m []byte) string
- func MarshalPrivateKeyPEM(priv crypto.PrivateKey) []byte
- func MarshalPublicKey(key crypto.PublicKey) []byte
- func Pub2ID(pub []byte) uint64
- func Pub2VIP(pub []byte) net.IP
- func PublicKey(key crypto.PrivateKey) crypto.PublicKey
- func PublicKeyBase32SHA(key crypto.PublicKey) string
- func RawToCertChain(rawCerts [][]byte) ([]*x509.Certificate, error)
- func SPKIFingerprint(key crypto.PublicKey) string
- func SignCertDER(template *x509.Certificate, pub crypto.PublicKey, caPrivate crypto.PrivateKey, ...) ([]byte, error)
- func TLSA(key crypto.PublicKey) string
- func VerifyChain(chain []*x509.Certificate) (crypto.PublicKey, error)
- type Cert
- func (ca *Cert) CertTemplate(org string, urlSAN string, sans ...string) *x509.Certificate
- func (cert *Cert) GenerateTLSConfigServer(trust *MeshTrust) *tls.Config
- func (cert *Cert) InitSelfSignedKey(privk crypto.PrivateKey)
- func (cert *Cert) InitSelfSignedPEMKey(keyPEM string)
- func (cert *Cert) Leaf() *x509.Certificate
- func (cert *Cert) PrivateKeyPEM() string
- func (cert *Cert) Provision(ctx context.Context) error
- func (cert *Cert) PubB32() string
- func (cert *Cert) PublicKey() []byte
- func (cert *Cert) PublicKeyPEM() string
- func (cert *Cert) Save(ctx context.Context, dir string) error
- func (cert *Cert) SetCertPEM(privatePEM string, chainPEMCat string) error
- func (cert *Cert) SignCert(priv crypto.PrivateKey, ca crypto.PrivateKey, sans ...string) (tls.Certificate, []byte, []byte)
- func (cert *Cert) SignCertDER(pub crypto.PublicKey, caPrivate crypto.PrivateKey, sans ...string) []byte
- func (cert *Cert) Spiffee() (*url.URL, string, string, string)
- func (cert *Cert) TLSClient(ctx context.Context, nc net.Conn, dest *Trust, mt *MeshTrust, ...) (*tls.Conn, error)
- func (cert *Cert) TLSClientConf(dest *Trust, sni string, remotePub32 string, rootT *MeshTrust) *tls.Config
- type Certs
- func (certs *Certs) DialTLS(nc net.Conn, addr string) (*tls.Conn, error)
- func (certs *Certs) FromEnv() error
- func (certs *Certs) GetCertificate(ctx context.Context, sni string) (*tls.Certificate, error)
- func (certs *Certs) GetCerts() map[string]*tls.Certificate
- func (ca *Certs) Init(dir string) error
- func (certs *Certs) InitSelfSigned(kty string, fqdn string) *Cert
- func (certs *Certs) InitSelfSignedFromPEMKey(keyPEM string, fqdn string) *Cert
- func (certs *Certs) InitSelfSignedKeyRaw(privk crypto.PrivateKey, fqdn string) *Cert
- func (ca *Certs) NewID(ns, sa string, dns []string) *Cert
- func (ca *Certs) NewIntermediaryCA(trust, cluster string) *Certs
- func (ca *Certs) NewTLSCert(ns, sa string, dns []string) (*tls.Certificate, []byte, []byte)
- func (certs *Certs) Provision(ctx context.Context) error
- func (ca *Certs) Save(ctx context.Context, dir string) error
- func (ca *Certs) SetCert(privPEM, certPEM []byte) error
- func (c *Certs) SignCertificate(template *x509.Certificate, pub crypto.PublicKey) string
- type MeshTrust
- type Trust
Constants ¶
const ( BlockTypeECPrivateKey = "EC PRIVATE KEY" BlockTypeRSAPrivateKey = "RSA PRIVATE KEY" // PKCS#1 private key BlockTypePKCS8PrivateKey = "PRIVATE KEY" // PKCS#8 plain private key BlockTypeCertificate = "CERTIFICATE" )
Variables ¶
var (
MESH_NETWORK = []byte{0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0x00}
)
Functions ¶
func GenerateKey ¶
func GenerateKey(kty string) crypto.PrivateKey
func IDFromCert ¶
func IDFromCert(c []*x509.Certificate) string
func IDFromPublicKeyBytes ¶
func MarshalPrivateKeyPEM ¶
func MarshalPrivateKeyPEM(priv crypto.PrivateKey) []byte
MarshalPrivateKeyPEM returns the PEM encoding of the key
func MarshalPublicKey ¶
Convert a PublicKey to a marshalled format - in the raw format. - 32 byte ED25519 - 65 bytes EC256 ( 0x04 prefix ) - DER RSA key (PKCS1)
Normally the key is available from request or response TLS.PeerCertificate[0]
func Pub2VIP ¶
Convert a public key to a VIP. This is the primary WorkloadID of the nodes. Primary format is the 64-byte EC256 public key.
For RSA, the ASN.1 format of the byte[] is used. For ED, the 32-byte raw encoding.
func PublicKeyBase32SHA ¶
PublicKeyBase32SHA returns a node WorkloadID based on the public key of the node - 52 bytes base32 for EC256 keys
func RawToCertChain ¶
func RawToCertChain(rawCerts [][]byte) ([]*x509.Certificate, error)
func SPKIFingerprint ¶
Return the SPKI fingerprint of the key https://www.rfc-editor.org/rfc/rfc7469#section-2.4
"An SPKI Fingerprint is defined as the output of a known cryptographic
hash algorithm whose input is the DER-encoded ASN.1 representation of the Subject Public Key Info (SPKI) of an X.509 certificate"
"The SPKI Fingerprint is encoded in base 64 for use in an HTTP header
[RFC4648]"
Can be used with "ignore-certificate-errors-spki-list" in chrome, for cert pinning.
User-installed roots can bypass the pins.
openssl x509 -pubkey -noout -in <path to PEM cert> | openssl pkey -pubin -outform der \ | openssl dgst -sha256 -binary | openssl base32Enc -base64
sha256/BASE64
func SignCertDER ¶
func SignCertDER(template *x509.Certificate, pub crypto.PublicKey, caPrivate crypto.PrivateKey, parent *x509.Certificate) ([]byte, error)
SignCertDER uses caPrivate to sign a tlsCrt, returns the DER format. Used primarily for tests with self-signed tlsCrt.
func TLSA ¶
TLSA records have many types - this is for the Selector=1 (SubjectPublicKeyInfo == public key DER) matching=1 (SHA256 - same as in SPKI). CertUsage can be 0/2 (root certificate - must be in the chain, doesn't need basicConstraints), or 1/3 (Leaf/end certificate). Note that 0,1 require a trustChain root, while 2,3 don't.
Example: _443._tcp.www.example.com. IN TLSA (
2 1 1 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971)
DNS canonical representation is hex, but the record is binary.
func VerifyChain ¶
func VerifyChain(chain []*x509.Certificate) (crypto.PublicKey, error)
VerifySelfSigned verifies the certificate chain and extract the remote's public key. The last element in the chain is expected to be the root - which should be checked against DANE or static config.
Types ¶
type Cert ¶
type Cert struct {
// Cert is the loaded certificate.
*tls.Certificate `json:"-"`
// Org will be set in the CN field - should be the TrustDomain for mesh.
Org string
Name string
Domain string
DNSSANs []string
SPIFFE string
CA bool
// If Base is set, cert will be loaded, and error generated if missing.
// If not set and no other initialization is performed, a
// self-signed certificate is generated.
Base string `json:"base,omitempty"`
// Certificates signing the private key.
// First is the cert signing the public key, followed by any
// certs signing previous certs. It is not required to include to
// 'top level' root that signed the entire chain (which should be
// in the trust roots).
ChainPEM []byte `json:"chainPEM,omitempty"`
KeyPEM []byte `json:"keyPEM,omitempty"`
}
A Cert is a private key and an associated certificate chain.
The certificate chain includes X509 signatures on the public key and associated data, and is equivalent with a signed token.
A Cert can issue and verify tokens.
func (*Cert) CertTemplate ¶
func (*Cert) GenerateTLSConfigServer ¶
GenerateTLSConfigServer is used to provide the server tls.Config for handshakes.
Will use the workload identity and do basic checks on client certs. It does not require client certs - but asks for them, and if found verifies.
If allowMeshExternal is set, will skip verification for certs with different trust domain.
The GetCertificate method can be replaced with one that handles multiple domains.
func (*Cert) InitSelfSignedKey ¶
func (cert *Cert) InitSelfSignedKey(privk crypto.PrivateKey)
func (*Cert) InitSelfSignedPEMKey ¶
func (*Cert) Leaf ¶
func (cert *Cert) Leaf() *x509.Certificate
Leaf returns the leaf certificate from the loaded cert, or a new template based on the Cert fields.
func (*Cert) PrivateKeyPEM ¶
func (*Cert) PublicKeyPEM ¶
func (*Cert) SignCert ¶
func (cert *Cert) SignCert(priv crypto.PrivateKey, ca crypto.PrivateKey, sans ...string) (tls.Certificate, []byte, []byte)
SignCert will create a tls.Certificate and the PEM encoding of the certificate, using the fields in Cert.
func (*Cert) SignCertDER ¶
func (*Cert) TLSClient ¶
func (cert *Cert) TLSClient(ctx context.Context, nc net.Conn, dest *Trust, mt *MeshTrust, remotePub32 string) (*tls.Conn, error)
GenerateTLSConfigDest returns a custom tls config for a Dest and a context holder. This should be used with a single
func (*Cert) TLSClientConf ¶
func (cert *Cert) TLSClientConf(dest *Trust, sni string, remotePub32 string, rootT *MeshTrust) *tls.Config
TLSClientConf returns a TLS config using this certificate as client cert
sni can override the cluster sni remotePub32 is the cert-baseed identity of a specific endpoint.
On the returned config, you can override "NextProtos" (defaults
to h2), and ServerName (defaults to the dest FQDN)
type Certs ¶
type Certs struct {
// Local dir. If set, private key and certificates are saved there.
// If not set, they will be loaded from SecretFS (keys), or auto-generated
// ephemeral key are used.
BaseDir string `json:"base,omitempty"`
// Private key for the workload, used for signing.
// The associated public key should be used to configure trust in this
// workload and any identities it may use (impersonate) or delegate.
Private crypto.PrivateKey `json:"-"`
// CACert is a certificate associated with the private key, with the
// CA bit set. Used to generate certificates signed by this workload.
CACert *x509.Certificate `json:"-"`
// FQDN is the FQDN of the workload.
//
// In Istio, the constant 'cluster.local' is
// used for the mesh CA, which indicates a custom location is
// used for the root key and use of SPIFFE certificates.
//
// Default to 'hostname' or env HOST and DOMAIN
// The second component is treated as 'namespace'.
FQDN string `json:"trustDomain,omitempty"`
// The CA Certificate may be signed by multiple intermediaries
// They need to be included in chains.
// May include the top-level root - but this is not required.
IntermediatesPEM []byte `json:"chainPEM,omitempty"`
// For self-signed cert ('root'), this is the cert corresponding to
// the private key. This needs to be added to the trust store.
// This is NOT included in Intermediates - which are signatures by
// other CAs that MUST be included in generated chains, so clients
// can find a path to the other CAs.
//
// This is used if this CA is the top-level CA, signing other CAs - and
// MUST be added to the trust store of each client.
//
// Since it is self-signed, the CA can re-generated this file.
// For the chain, the signing CA (provider) must issue them again.
CACertPEM []byte `json:"selfPEM,omitempty"`
LoadTime time.Time `json:"-"`
// Trust configures private CA roots as 'trusted'.
// If no CA root is found, default is to trust the internal CA and
// public roots.
//
// Each peer must have a valid certificate. If Trust is defined, the
// cert must have a signature from one of the defined public keys.
// This field includes CA-style keys, valid for all identities.
Trust *MeshTrust `json:"trust"`
// A filesystem interface for loading private keys. May also include
// configs and certificates.
SecretsFS fs.FS
// A filesystem holding server certificates and configs. Loaded on-demand.
// If a cert is not found - the internal CA will generate one.
ConfigFS fs.FS
// Cert is the workload certificate - should encode the primary FQDN of
// the node.
*Cert
// Private key as a string (base64). EC256 is 33 bytes, ED25519 16 bytes,
// and RSA encoded as PEM.
PrivateString string `json:"key"`
}
Certs handles certificate and trust management, and is built around a primary private key.
It incorporates as private CA that can sign additional certs for subdomains, a filesystem for loading secrets, a filesystem for loading configs for client connections and an optional directory for local files and cache.
func (*Certs) GetCertificate ¶
GetCertificate is typically called during handshake, both server and client. "sni" will be empty for client certificates, and set for server certificates - if not set, workload id is returned.
ctx is the handshake context - may include additional metadata about the operation.
func (*Certs) GetCerts ¶
func (certs *Certs) GetCerts() map[string]*tls.Certificate
Get all known certificates from local files. This is used to support lego certificates and istio.
"istio" is a special name, set if istio certs are found
func (*Certs) InitSelfSignedFromPEMKey ¶
InitSelfSignedFromPEMKey will use the private key (EC PEM) and generate a self signed certificate, using the config (name.domain)
func (*Certs) InitSelfSignedKeyRaw ¶
func (certs *Certs) InitSelfSignedKeyRaw(privk crypto.PrivateKey, fqdn string) *Cert
func (*Certs) NewIntermediaryCA ¶
NewIntermediaryCA creates a cert for an intermediary CA.
func (*Certs) NewTLSCert ¶
NewTLSCert creates a new cert from this CA.
func (*Certs) Save ¶
Save will save: - private key as tls.key (PEM) - CA certificate as ca.pem - certificate chain
func (*Certs) SetCert ¶
SetCert will init CA from PEM bytes. For example loading it from a K8S Secret or files.
func (*Certs) SignCertificate ¶
Signs and return a PEM-encoded certificate. The result includes the root CACertPEM files (intermediaries), but does not include the CA root or other trusted CAs.
type MeshTrust ¶
type MeshTrust struct {
// Used by mesh clients, for tickets.
ClientSessionCache tls.ClientSessionCache `json:"-"`
RootsPEM string `json:"roots,omitempty"`
// This is the 'trust domain' for Istio-style certs, also
// can be used with SERVICE.NAMESPACE.svc.DOMAIN or POD.NAMESPACE.DOMAIN
//
// If not set, '.local' and '.internal' are used.
Domain []string `json:"domain"`
// If set, limits the namespaces that are allowed to connect.
// Same namespace and 'istio-system' are allowed by default.
//
// If set, no external certificates are allowed for clients.
// Public certs for servers continue to be allowed (block internet
// egress using network rules, not cert rules).
AllowedNamespaces []string
// AllowMeshExternal indicates that client certificates not signed by
// a certPool certificare - but valid - will be allowed. The server
// can inspect the cert chain in the connection and make
// decisions based on the signers.
AllowMeshExternal bool `json:"-"`
// contains filtered or unexported fields
}
MeshTrust configures mesh-style trust, where all identities signed by a set of CAs are trusted.
Trust allow per-identity configuration, and is loaded on-demand from the config store (or DNS)
func NewMeshTrust ¶
func NewMeshTrust() *MeshTrust
func (*MeshTrust) AddRootDER ¶
Add a list of certificates in DER format to the root. The top signer of the workload certificate is added by default.
func (*MeshTrust) AddRoots ¶
AddRoots will process a PEM file containing multiple concatenated certificates.
func (*MeshTrust) VerifyClientCert ¶
func (mesh *MeshTrust) VerifyClientCert(allowMeshExternal bool, rawCerts [][]byte, _ [][]*x509.Certificate) error
VerifyClientCert is specific to servers accepting connections. Only used if 'request certificat' is set in the tls.Config, and if a certificate is provided by client.
type Trust ¶
type Trust struct {
Domain string
Namespace string
RootsPEM string `json:"roots,omitempty"`
// List of base32(public_key) to be trusted.
RootPub32 []string
AllowedNamespaces []string
// If set to true, allow connections from clients not signed by the
// trusted roots, and allow connections to servers not signed by trusted
// roots or root CAs.
//
// The certificate public key will be verified out-of-band, using TOFU or
// DNS or other mechanisms.
AllowMeshExternal bool
// If empty, the cluster is using system certs or SPIFFE CAs - as configured in
// Mesh.
//
// Otherwise, it's the configured root certs list, in PEM format.
// May include multiple concatenated roots.
//
// TODO: allow root SHA only.
// TODO: move to trust config
CACertPEM string `json:"ca_cert,omitempty"`
// Expected SANs - if not set, the DNS host in the address is used.
// For mesh FQDNs, the namespace will be checked ( second part of the FQDN )
DNSSANs []string `json:"dns_san,omitempty"`
//IPSANs []string `json:"ip_san,omitempty"`
URLSANs []string `json:"url_san,omitempty"`
// SNI to use when making the request. Defaults to hostname in Addr
SNI string `json:"sni,omitempty"`
ALPN []string `json:"alpn,omitempty"`
// Associated with a trust, used by clients.
ClientSessionCache tls.ClientSessionCache `json:"-"`
// contains filtered or unexported fields
}
Trust configures the verification (authentication) of the peers.
This can be used for mesh (using namespaces and 'trust domain') or for client overrides (custom SNI, ALPN - and trust servers with specific SANs or hash of public keys).
It does include small elements of authorization: - deny if the peer is not part of the mesh - allow only specific namespaces or domains (for Spiffe or DNS)
It can represent the 'default mesh' root of trust or per-domain verification.
This is similar to JWT verification: a set of signing keys and restrictions on what claims can be set.