feat: Include entire certificate chain if provided
Allow a user to provide an entire certificate chain to the ca issuer. Include that chain in all generated certificates Signed-off-by: Mike Bryant <m@ocado.com>
This commit is contained in:
parent
018f3642e9
commit
4fa6d9775c
@ -70,7 +70,7 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get a copy of the CA certificate named on the Issuer
|
// get a copy of the CA certificate named on the Issuer
|
||||||
caCert, caKey, err := kube.SecretTLSKeyPair(c.secretsLister, c.resourceNamespace, c.issuer.GetSpec().CA.SecretName)
|
caCerts, caKey, err := kube.SecretTLSKeyPair(c.secretsLister, c.resourceNamespace, c.issuer.GetSpec().CA.SecretName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Error getting signing CA for Issuer: %v", err)
|
glog.Errorf("Error getting signing CA for Issuer: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -83,6 +83,8 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
caCert := caCerts[0]
|
||||||
|
|
||||||
// sign and encode the certificate
|
// sign and encode the certificate
|
||||||
certPem, _, err := pki.SignCertificate(template, caCert, signeePublicKey, caKey)
|
certPem, _, err := pki.SignCertificate(template, caCert, signeePublicKey, caKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -90,6 +92,15 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encode the chain
|
||||||
|
// TODO: replace caCerts with caCerts[1:]?
|
||||||
|
chainPem, err := pki.EncodeX509Chain(caCerts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
certPem = append(certPem, chainPem)
|
||||||
|
|
||||||
// Encode output private key and CA cert ready for return
|
// Encode output private key and CA cert ready for return
|
||||||
keyPem, err := pki.EncodePrivateKey(signeeKey)
|
keyPem, err := pki.EncodePrivateKey(signeeKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -98,7 +109,7 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// encode the CA certificate to be bundled in the output
|
// encode the CA certificate to be bundled in the output
|
||||||
caPem, err := pki.EncodeX509(caCert)
|
caPem, err := pki.EncodeX509(caCerts[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Recorder.Eventf(crt, corev1.EventTypeWarning, "ErrorSigning", "Error encoding certificate: %v", err)
|
c.Recorder.Eventf(crt, corev1.EventTypeWarning, "ErrorSigning", "Error encoding certificate: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -56,7 +56,7 @@ func SecretTLSKey(secretLister corelisters.SecretLister, namespace, name string)
|
|||||||
return SecretTLSKeyRef(secretLister, namespace, name, api.TLSPrivateKeyKey)
|
return SecretTLSKeyRef(secretLister, namespace, name, api.TLSPrivateKeyKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string) (*x509.Certificate, error) {
|
func SecretTLSCertChain(secretLister corelisters.SecretLister, namespace, name string) ([]*x509.Certificate, error) {
|
||||||
secret, err := secretLister.Secrets(namespace).Get(name)
|
secret, err := secretLister.Secrets(namespace).Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -64,9 +64,9 @@ func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string
|
|||||||
|
|
||||||
certBytes, ok := secret.Data[api.TLSCertKey]
|
certBytes, ok := secret.Data[api.TLSCertKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("no data for %q in secret '%s/%s'", api.TLSCertKey, namespace, name)
|
return nil, errors.NewInvalidData("no data for %q in secret '%s/%s'", api.TLSCertKey, namespace, name)
|
||||||
}
|
}
|
||||||
cert, err := pki.DecodeX509CertificateBytes(certBytes)
|
cert, err := pki.DecodeX509CertificateChainBytes(certBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cert, errors.NewInvalidData(err.Error())
|
return cert, errors.NewInvalidData(err.Error())
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string
|
|||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SecretTLSKeyPair(secretLister corelisters.SecretLister, namespace, name string) (*x509.Certificate, crypto.Signer, error) {
|
func SecretTLSKeyPair(secretLister corelisters.SecretLister, namespace, name string) ([]*x509.Certificate, crypto.Signer, error) {
|
||||||
secret, err := secretLister.Secrets(namespace).Get(name)
|
secret, err := secretLister.Secrets(namespace).Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -93,10 +93,19 @@ func SecretTLSKeyPair(secretLister corelisters.SecretLister, namespace, name str
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, key, errors.NewInvalidData("no certificate data for %q in secret '%s/%s'", api.TLSCertKey, namespace, name)
|
return nil, key, errors.NewInvalidData("no certificate data for %q in secret '%s/%s'", api.TLSCertKey, namespace, name)
|
||||||
}
|
}
|
||||||
cert, err := pki.DecodeX509CertificateBytes(certBytes)
|
cert, err := pki.DecodeX509CertificateChainBytes(certBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, key, errors.NewInvalidData(err.Error())
|
return nil, key, errors.NewInvalidData(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return cert, key, nil
|
return cert, key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string) (*x509.Certificate, error) {
|
||||||
|
certs, err := SecretTLSCertChain(secretLister, namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return certs[0], nil
|
||||||
|
}
|
||||||
|
|||||||
@ -193,16 +193,6 @@ func SignCertificate(template *x509.Certificate, issuerCert *x509.Certificate, p
|
|||||||
return nil, nil, fmt.Errorf("error encoding certificate PEM: %s", err.Error())
|
return nil, nil, fmt.Errorf("error encoding certificate PEM: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't bundle the CA for selfsigned certificates
|
|
||||||
// TODO: better comparison method here? for now we can just compare pointers.
|
|
||||||
if issuerCert != template {
|
|
||||||
// bundle the CA
|
|
||||||
err = pem.Encode(pemBytes, &pem.Block{Type: "CERTIFICATE", Bytes: issuerCert.Raw})
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("error encoding issuer cetificate PEM: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pemBytes.Bytes(), cert, err
|
return pemBytes.Bytes(), cert, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +218,23 @@ func EncodeX509(cert *x509.Certificate) ([]byte, error) {
|
|||||||
return caPem.Bytes(), nil
|
return caPem.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeX509Chain will encode an *x509.Certificate chain into PEM format.
|
||||||
|
func EncodeX509Chain(certs []*x509.Certificate) ([]byte, error) {
|
||||||
|
caPem := bytes.NewBuffer([]byte{})
|
||||||
|
for _, cert := range certs {
|
||||||
|
if bytes.Equal(cert.RawIssuer, cert.RawSubject) {
|
||||||
|
// Don't include self-signed certificate
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := pem.Encode(caPem, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return caPem.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// SignatureAlgorithm will determine the appropriate signature algorithm for
|
// SignatureAlgorithm will determine the appropriate signature algorithm for
|
||||||
// the given certificate.
|
// the given certificate.
|
||||||
// Adapted from https://github.com/cloudflare/cfssl/blob/master/csr/csr.go#L102
|
// Adapted from https://github.com/cloudflare/cfssl/blob/master/csr/csr.go#L102
|
||||||
|
|||||||
@ -78,18 +78,40 @@ func DecodePKCS1PrivateKeyBytes(keyBytes []byte) (*rsa.PrivateKey, error) {
|
|||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeX509CertificateBytes will decode a PEM encoded x509 Certificate.
|
// DecodeX509CertificateChainBytes will decode a PEM encoded x509 Certificate chain.
|
||||||
func DecodeX509CertificateBytes(certBytes []byte) (*x509.Certificate, error) {
|
func DecodeX509CertificateChainBytes(certBytes []byte) ([]*x509.Certificate, error) {
|
||||||
// decode the tls certificate pem
|
certs := []*x509.Certificate{}
|
||||||
block, _ := pem.Decode(certBytes)
|
|
||||||
if block == nil {
|
var block *pem.Block
|
||||||
return nil, errors.NewInvalidData("error decoding cert PEM block")
|
|
||||||
}
|
for {
|
||||||
// parse the tls certificate
|
// decode the tls certificate pem
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
block, certBytes = pem.Decode(certBytes)
|
||||||
if err != nil {
|
if block == nil {
|
||||||
return nil, errors.NewInvalidData("error parsing TLS certificate: %s", err.Error())
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the tls certificate
|
||||||
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.NewInvalidData("error parsing TLS certificate: %s", err.Error())
|
||||||
|
}
|
||||||
|
certs = append(certs, cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cert, nil
|
if len(certs) == 0 {
|
||||||
|
return nil, errors.NewInvalidData("error decoding cert PEM block")
|
||||||
|
}
|
||||||
|
|
||||||
|
return certs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeX509CertificateBytes will decode a PEM encoded x509 Certificate.
|
||||||
|
func DecodeX509CertificateBytes(certBytes []byte) (*x509.Certificate, error) {
|
||||||
|
certs, err := DecodeX509CertificateChainBytes(certBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return certs[0], nil
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user