diff --git a/pkg/cert/legobridge/certificate.go b/pkg/cert/legobridge/certificate.go index 73acd298..2943c196 100644 --- a/pkg/cert/legobridge/certificate.go +++ b/pkg/cert/legobridge/certificate.go @@ -66,7 +66,7 @@ type ObtainInput struct { // IsCA is used to request a self-signed certificate IsCA bool // Duration is the lifetime of the certificate - Duration time.Duration + Duration *time.Duration } // DNSControllerSettings are the settings for the DNSController. @@ -165,7 +165,6 @@ func obtainForDomains(client *lego.Client, domains []string, input ObtainInput) AlwaysDeactivateAuthorizations: input.AlwaysDeactivateAuthorizations, PreferredChain: input.PreferredChain, PrivateKey: privateKey, - NotAfter: time.Now().Add(input.Duration), } return client.Certificate.Obtain(request) } @@ -282,7 +281,6 @@ func obtainForCSR(client *lego.Client, csr []byte, input ObtainInput) (*certific Bundle: true, AlwaysDeactivateAuthorizations: input.AlwaysDeactivateAuthorizations, PreferredChain: input.PreferredChain, - NotAfter: time.Now().Add(input.Duration), }) } @@ -608,7 +606,7 @@ func newCASignedCertFromInput(input ObtainInput) (*certificate.Resource, error) // newCASignedCertFromCertReq returns a new Certificate signed by a CA based on // an x509.CertificateRequest and a CA key pair. A private key will be generated. -func newCASignedCertFromCertReq(csr *x509.CertificateRequest, CAKeyPair *TLSKeyPair, duration time.Duration) (*certificate.Resource, error) { +func newCASignedCertFromCertReq(csr *x509.CertificateRequest, CAKeyPair *TLSKeyPair, duration *time.Duration) (*certificate.Resource, error) { pubKeySize := pubKeySize(csr.PublicKey) if pubKeySize == 0 { pubKeySize = defaultKeySize(csr.PublicKeyAlgorithm) diff --git a/pkg/cert/legobridge/pki.go b/pkg/cert/legobridge/pki.go index 7c57e8d5..c77d6bfa 100644 --- a/pkg/cert/legobridge/pki.go +++ b/pkg/cert/legobridge/pki.go @@ -62,7 +62,7 @@ const ( ) // issueSignedCert does all the Certificate Issuing. -func issueSignedCert(csr *x509.CertificateRequest, isCA bool, privKey crypto.Signer, privKeyPEM []byte, signerKeyPair *TLSKeyPair, duration time.Duration) (*certificate.Resource, error) { +func issueSignedCert(csr *x509.CertificateRequest, isCA bool, privKey crypto.Signer, privKeyPEM []byte, signerKeyPair *TLSKeyPair, duration *time.Duration) (*certificate.Resource, error) { csrPEM, err := generateCSRPEM(csr, privKey) if err != nil { return nil, err @@ -183,7 +183,7 @@ func generateCSRPEM(csr *x509.CertificateRequest, privateKey crypto.Signer) ([]b } // generateCertFromCSR generates an x509.Certificate based on a PEM encoded CSR. -func generateCertFromCSR(csrPEM []byte, duration time.Duration, isCA bool) (*x509.Certificate, error) { +func generateCertFromCSR(csrPEM []byte, duration *time.Duration, isCA bool) (*x509.Certificate, error) { var serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) csr, err := extractCertificateRequest(csrPEM) @@ -217,7 +217,7 @@ func generateCertFromCSR(csrPEM []byte, duration time.Duration, isCA bool) (*x50 IsCA: isCA, Subject: csr.Subject, NotBefore: time.Now(), - NotAfter: time.Now().Add(duration), + NotAfter: time.Now().Add(*duration), KeyUsage: ku, ExtKeyUsage: DefaultCertExtKeyUsage, DNSNames: csr.DNSNames, @@ -244,7 +244,7 @@ func newSelfSignedCertInPEMFormat( }, DNSNames: input.DNSNames, NotBefore: time.Now(), - NotAfter: time.Now().Add(input.Duration), + NotAfter: time.Now().Add(*input.Duration), KeyUsage: keyUsage, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, IsCA: true, diff --git a/pkg/controller/issuer/certificate/reconciler.go b/pkg/controller/issuer/certificate/reconciler.go index b853593b..93c7c618 100644 --- a/pkg/controller/issuer/certificate/reconciler.go +++ b/pkg/controller/issuer/certificate/reconciler.go @@ -30,6 +30,7 @@ import ( apierrrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/utils/ptr" api "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1" "github.com/gardener/cert-management/pkg/cert/legobridge" @@ -409,9 +410,11 @@ func (r *certReconciler) obtainCertificateAndPendingACME(logctx logger.LogContex if err != nil { return r.failed(logctx, obj, api.StateError, err) } - duration, err := r.getDuration(cert) - if err != nil { - return r.failedStop(logctx, obj, api.StateError, err) + if cert.Spec.Duration != nil { + return r.failedStop(logctx, obj, api.StateError, fmt.Errorf("duration cannot be set for ACME certificate")) + } + if cert.Spec.IsCA != nil { + return r.failedStop(logctx, obj, api.StateError, fmt.Errorf("isCA cannot be set for ACME certificate")) } err = r.validateDomainsAndCsr(&cert.Spec, issuer.Spec.ACME.Domains, issuerKey) if err != nil { @@ -511,7 +514,6 @@ func (r *certReconciler) obtainCertificateAndPendingACME(logctx logger.LogContex AlwaysDeactivateAuthorizations: r.alwaysDeactivateAuthorizations, PreferredChain: preferredChain, KeyType: keyType, - Duration: duration, } err = r.obtainer.Obtain(input) @@ -568,6 +570,10 @@ func (r *certReconciler) obtainCertificateSelfSigned(logctx logger.LogContext, o if err != nil { return r.failedStop(logctx, obj, api.StateError, err) } + if duration == nil { + defaultDuration := legobridge.DefaultCertDuration + duration = &defaultDuration + } err = r.validateDomainsAndCsr(&cert.Spec, nil, issuerKey) if err != nil { return r.failedStop(logctx, obj, api.StateError, err) @@ -623,14 +629,22 @@ func (r *certReconciler) obtainCertificateSelfSigned(logctx logger.LogContext, o func (r *certReconciler) obtainCertificateCA(logctx logger.LogContext, obj resources.Object, renew bool, cert *api.Certificate, issuerKey utils.IssuerKey, issuer *api.Issuer) reconcile.Status { + if cert.Spec.IsCA != nil { + return r.failedStop(logctx, obj, api.StateError, fmt.Errorf("isCA cannot be set for CA certificate")) + } CAKeyPair, err := r.restoreCA(issuerKey, issuer) if err != nil { return r.failed(logctx, obj, api.StateError, err) } + duration, err := r.getDuration(cert) if err != nil { return r.failedStop(logctx, obj, api.StateError, err) } + if duration == nil { + defaultDuration := 2 * legobridge.DefaultCertDuration + duration = &defaultDuration + } err = r.validateCertDuration(duration, CAKeyPair) if err != nil { return r.failedStop(logctx, obj, api.StateError, err) @@ -723,22 +737,22 @@ func (r *certReconciler) checkDomainRangeRestriction(issuerDomains *api.DNSSelec return nil } -func (r *certReconciler) getDuration(cert *api.Certificate) (time.Duration, error) { - duration := legobridge.DefaultCertDuration - if cert.Spec.Duration != nil { - duration = cert.Spec.Duration.Duration - if duration < 2*r.renewalWindow { - return 0, fmt.Errorf("certificate duration must be greater than %v", 2*r.renewalWindow) - } +func (r *certReconciler) getDuration(cert *api.Certificate) (*time.Duration, error) { + if cert.Spec.Duration == nil { + return nil, nil + } + duration := cert.Spec.Duration.Duration + if duration < 2*r.renewalWindow { + return nil, fmt.Errorf("certificate duration must be greater than %v", 2*r.renewalWindow) } - return duration, nil + return ptr.To(duration), nil } -func (r *certReconciler) validateCertDuration(duration time.Duration, caKeyPair *legobridge.TLSKeyPair) error { +func (r *certReconciler) validateCertDuration(duration *time.Duration, caKeyPair *legobridge.TLSKeyPair) error { caNotAfter := caKeyPair.Cert.NotAfter now := time.Now() - if now.Add(duration).After(caNotAfter) { - return fmt.Errorf("certificate lifetime (%v) is longer than the lifetime of the CA certificate (%v)", now.Add(duration), caNotAfter) + if now.Add(*duration).After(caNotAfter) { + return fmt.Errorf("certificate lifetime (%v) is longer than the lifetime of the CA certificate (%v)", now.Add(*duration), caNotAfter) } return nil }