Merge pull request #69991 from agunnerson-ibm/issue-69471

certificate_manager: Check that template differs from current cert before rotation

Kubernetes-commit: d96f235051d85143193c6158d1efdffb4daa3081
This commit is contained in:
Kubernetes Publisher 2018-10-24 21:35:09 -07:00
commit 045bdd8bd8
3 changed files with 299 additions and 105 deletions

168
Godeps/Godeps.json generated
View File

@ -280,339 +280,339 @@
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/apps/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/apps/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/apps/v1beta2",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/auditregistration/v1alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/authentication/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/authentication/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/authorization/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/authorization/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/autoscaling/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/autoscaling/v2beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/autoscaling/v2beta2",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/batch/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/batch/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/batch/v2alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/certificates/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/coordination/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/core/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/events/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/extensions/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/imagepolicy/v1alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/networking/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/policy/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/rbac/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/rbac/v1alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/rbac/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/scheduling/v1alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/scheduling/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/settings/v1alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/storage/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/storage/v1alpha1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/api/storage/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/fuzzer",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/roundtrip",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/naming",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "323bac2d03757f0b097eaf318f1d5423d3e2b1d0"
"Rev": "951fda697f98f8cc9ae840764118a024d7c484d8"
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",

View File

@ -274,7 +274,7 @@ func (m *manager) Start() {
if m.dynamicTemplate {
go wait.Forever(func() {
// check if the current template matches what we last requested
if !reflect.DeepEqual(m.getLastRequest(), m.getTemplate()) {
if !m.certSatisfiesTemplate() && !reflect.DeepEqual(m.getLastRequest(), m.getTemplate()) {
// if the template is different, queue up an interrupt of the rotation deadline loop.
// if we've requested a CSR that matches the new template by the time the interrupt is handled, the interrupt is disregarded.
templateChanged <- struct{}{}
@ -389,35 +389,30 @@ func (m *manager) rotateCerts() (bool, error) {
return true, nil
}
// nextRotationDeadline returns a value for the threshold at which the
// current certificate should be rotated, 80%+/-10% of the expiration of the
// certificate.
func (m *manager) nextRotationDeadline() time.Time {
// forceRotation is not protected by locks
if m.forceRotation {
m.forceRotation = false
return time.Now()
}
m.certAccessLock.RLock()
defer m.certAccessLock.RUnlock()
// Check that the current certificate on disk satisfies the requests from the
// current template.
//
// Note that extra items in the certificate's SAN or orgs that don't exist in
// the template will not trigger a renewal.
//
// Requires certAccessLock to be locked.
func (m *manager) certSatisfiesTemplateLocked() bool {
if m.cert == nil {
return time.Now()
return false
}
// Ensure the currently held certificate satisfies the requested subject CN and SANs
if template := m.getTemplate(); template != nil {
if template.Subject.CommonName != m.cert.Leaf.Subject.CommonName {
glog.V(2).Infof("Current certificate CN (%s) does not match requested CN (%s), rotating now", m.cert.Leaf.Subject.CommonName, template.Subject.CommonName)
return time.Now()
glog.V(2).Infof("Current certificate CN (%s) does not match requested CN (%s)", m.cert.Leaf.Subject.CommonName, template.Subject.CommonName)
return false
}
currentDNSNames := sets.NewString(m.cert.Leaf.DNSNames...)
desiredDNSNames := sets.NewString(template.DNSNames...)
missingDNSNames := desiredDNSNames.Difference(currentDNSNames)
if len(missingDNSNames) > 0 {
glog.V(2).Infof("Current certificate is missing requested DNS names %v, rotating now", missingDNSNames.List())
return time.Now()
glog.V(2).Infof("Current certificate is missing requested DNS names %v", missingDNSNames.List())
return false
}
currentIPs := sets.NewString()
@ -430,9 +425,43 @@ func (m *manager) nextRotationDeadline() time.Time {
}
missingIPs := desiredIPs.Difference(currentIPs)
if len(missingIPs) > 0 {
glog.V(2).Infof("Current certificate is missing requested IP addresses %v, rotating now", missingIPs.List())
glog.V(2).Infof("Current certificate is missing requested IP addresses %v", missingIPs.List())
return false
}
currentOrgs := sets.NewString(m.cert.Leaf.Subject.Organization...)
desiredOrgs := sets.NewString(template.Subject.Organization...)
missingOrgs := desiredOrgs.Difference(currentOrgs)
if len(missingOrgs) > 0 {
glog.V(2).Infof("Current certificate is missing requested orgs %v", missingOrgs.List())
return false
}
}
return true
}
func (m *manager) certSatisfiesTemplate() bool {
m.certAccessLock.RLock()
defer m.certAccessLock.RUnlock()
return m.certSatisfiesTemplateLocked()
}
// nextRotationDeadline returns a value for the threshold at which the
// current certificate should be rotated, 80%+/-10% of the expiration of the
// certificate.
func (m *manager) nextRotationDeadline() time.Time {
// forceRotation is not protected by locks
if m.forceRotation {
m.forceRotation = false
return time.Now()
}
m.certAccessLock.RLock()
defer m.certAccessLock.RUnlock()
if !m.certSatisfiesTemplateLocked() {
return time.Now()
}
notAfter := m.cert.Leaf.NotAfter

View File

@ -22,6 +22,7 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"net"
"strings"
"testing"
"time"
@ -212,6 +213,170 @@ func TestSetRotationDeadline(t *testing.T) {
}
}
func TestCertSatisfiesTemplate(t *testing.T) {
testCases := []struct {
name string
cert *x509.Certificate
template *x509.CertificateRequest
shouldSatisfy bool
}{
{
name: "No certificate, no template",
cert: nil,
template: nil,
shouldSatisfy: false,
},
{
name: "No certificate",
cert: nil,
template: &x509.CertificateRequest{},
shouldSatisfy: false,
},
{
name: "No template",
cert: &x509.Certificate{
Subject: pkix.Name{
CommonName: "system:node:fake-node-name",
},
},
template: nil,
shouldSatisfy: true,
},
{
name: "Mismatched common name",
cert: &x509.Certificate{
Subject: pkix.Name{
CommonName: "system:node:fake-node-name-2",
},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "system:node:fake-node-name",
},
},
shouldSatisfy: false,
},
{
name: "Missing orgs in certificate",
cert: &x509.Certificate{
Subject: pkix.Name{
Organization: []string{"system:nodes"},
},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{
Organization: []string{"system:nodes", "foobar"},
},
},
shouldSatisfy: false,
},
{
name: "Extra orgs in certificate",
cert: &x509.Certificate{
Subject: pkix.Name{
Organization: []string{"system:nodes", "foobar"},
},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{
Organization: []string{"system:nodes"},
},
},
shouldSatisfy: true,
},
{
name: "Missing DNS names in certificate",
cert: &x509.Certificate{
Subject: pkix.Name{},
DNSNames: []string{"foo.example.com"},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{},
DNSNames: []string{"foo.example.com", "bar.example.com"},
},
shouldSatisfy: false,
},
{
name: "Extra DNS names in certificate",
cert: &x509.Certificate{
Subject: pkix.Name{},
DNSNames: []string{"foo.example.com", "bar.example.com"},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{},
DNSNames: []string{"foo.example.com"},
},
shouldSatisfy: true,
},
{
name: "Missing IP addresses in certificate",
cert: &x509.Certificate{
Subject: pkix.Name{},
IPAddresses: []net.IP{net.ParseIP("192.168.1.1")},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{},
IPAddresses: []net.IP{net.ParseIP("192.168.1.1"), net.ParseIP("192.168.1.2")},
},
shouldSatisfy: false,
},
{
name: "Extra IP addresses in certificate",
cert: &x509.Certificate{
Subject: pkix.Name{},
IPAddresses: []net.IP{net.ParseIP("192.168.1.1"), net.ParseIP("192.168.1.2")},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{},
IPAddresses: []net.IP{net.ParseIP("192.168.1.1")},
},
shouldSatisfy: true,
},
{
name: "Matching certificate",
cert: &x509.Certificate{
Subject: pkix.Name{
CommonName: "system:node:fake-node-name",
Organization: []string{"system:nodes"},
},
DNSNames: []string{"foo.example.com"},
IPAddresses: []net.IP{net.ParseIP("192.168.1.1")},
},
template: &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "system:node:fake-node-name",
Organization: []string{"system:nodes"},
},
DNSNames: []string{"foo.example.com"},
IPAddresses: []net.IP{net.ParseIP("192.168.1.1")},
},
shouldSatisfy: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var tlsCert *tls.Certificate
if tc.cert != nil {
tlsCert = &tls.Certificate{
Leaf: tc.cert,
}
}
m := manager{
cert: tlsCert,
getTemplate: func() *x509.CertificateRequest { return tc.template },
}
result := m.certSatisfiesTemplate()
if result != tc.shouldSatisfy {
t.Errorf("cert: %+v, template: %+v, certSatisfiesTemplate returned %v, want %v", m.cert, tc.template, result, tc.shouldSatisfy)
}
})
}
}
func TestRotateCertCreateCSRError(t *testing.T) {
now := time.Now()
m := manager{