Don't merge expired certs over the top of an unexpired cert

Fixes an issue where an expired Kubernetes secret would replace the renewed locally-cached cert after cluster startup.

Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
This commit is contained in:
Brad Davidson 2022-07-19 15:45:06 -07:00 committed by Brad Davidson
parent 7b5997cee9
commit fdf983a935

View File

@ -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 {