diff --git a/factory/gen.go b/factory/gen.go index e620c5f..abe860e 100644 --- a/factory/gen.go +++ b/factory/gen.go @@ -15,6 +15,7 @@ import ( "regexp" "sort" "strings" + "time" "github.com/rancher/dynamiclistener/cert" "github.com/sirupsen/logrus" @@ -72,7 +73,8 @@ func collectCNs(secret *v1.Secret) (domains []string, ips []net.IP, err error) { // Merge combines the SAN lists from the target and additional Secrets, and // returns a potentially modified Secret, along with a bool indicating if the -// returned Secret is not the same as the target Secret. +// returned Secret is not the same as the target Secret. Secrets with expired +// certificates will never be returned. // // If the merge would not add any CNs to the additional Secret, the additional // Secret is returned, to allow for certificate rotation/regeneration. @@ -93,17 +95,17 @@ func (t *TLS) Merge(target, additional *v1.Secret) (*v1.Secret, bool, error) { // if the additional secret already has all the CNs, use it in preference to the // current one. This behavior is required to allow for renewal or regeneration. - if !NeedsUpdate(0, additional, mergedCNs...) { + if !NeedsUpdate(0, additional, mergedCNs...) && !IsExpired(additional) { return additional, true, nil } // if the target secret already has all the CNs, continue using it. The additional // cert had only a subset of the current CNs, so nothing needs to be added. - if !NeedsUpdate(0, target, mergedCNs...) { + if !NeedsUpdate(0, target, mergedCNs...) && !IsExpired(target) { return target, false, nil } - // neither cert currently has all the necessary CNs; generate a new one. + // neither cert currently has all the necessary CNs or is unexpired; generate a new one. return t.generateCert(target, mergedCNs...) } @@ -191,6 +193,20 @@ func (t *TLS) generateCert(secret *v1.Secret, cn ...string) (*v1.Secret, bool, e return secret, true, nil } +func IsExpired(secret *v1.Secret) bool { + certsPem := secret.Data[v1.TLSCertKey] + if len(certsPem) == 0 { + return false + } + + certificates, err := cert.ParseCertsPEM(certsPem) + if err != nil || len(certificates) == 0 { + return false + } + + return time.Now().After(certificates[0].NotAfter) +} + func (t *TLS) Verify(secret *v1.Secret) error { certsPem := secret.Data[v1.TLSCertKey] if len(certsPem) == 0 {