diff --git a/ca/certificates.go b/ca/certificates.go index c0b6ddfef6..c355d274fd 100644 --- a/ca/certificates.go +++ b/ca/certificates.go @@ -57,19 +57,17 @@ const ( RootCAExpiration = "630720000s" // DefaultNodeCertExpiration represents the default expiration for node certificates (3 months) DefaultNodeCertExpiration = 2160 * time.Hour + // CertBackdate represents the amount of time each certificate is backdated to try to avoid + // clock drift issues. + CertBackdate = -1 * time.Hour // CertLowerRotationRange represents the minimum fraction of time that we will wait when randomly // choosing our next certificate rotation CertLowerRotationRange = 0.5 // CertUpperRotationRange represents the maximum fraction of time that we will wait when randomly // choosing our next certificate rotation CertUpperRotationRange = 0.8 - // MinNodeCertExpiration represents the minimum expiration for node certificates (25 + 5 minutes) - // X - 5 > CertUpperRotationRange * X <=> X < 5/(1 - CertUpperRotationRange) - // Since we're issuing certificates 5 minutes in the past to get around clock drifts, and - // we're selecting a random rotation distribution range from CertLowerRotationRange to - // CertUpperRotationRange, we need to ensure that we don't accept an expiration time that will - // make a node able to randomly choose the next rotation after the expiration of the certificate. - MinNodeCertExpiration = 30 * time.Minute + // MinNodeCertExpiration represents the minimum expiration for node certificates + MinNodeCertExpiration = 1 * time.Hour ) // ErrNoLocalRootCA is an error type used to indicate that the local root CA diff --git a/ca/certificates_test.go b/ca/certificates_test.go index 8ac00060ff..76768228ef 100644 --- a/ca/certificates_test.go +++ b/ca/certificates_test.go @@ -534,12 +534,12 @@ func TestNewRootCANonDefaultExpiry(t *testing.T) { parsedCerts, err := helpers.ParseCertificatesPEM(cert) assert.NoError(t, err) assert.Len(t, parsedCerts, 2) - assert.True(t, time.Now().Add(time.Minute*50).Before(parsedCerts[0].NotAfter)) - assert.True(t, time.Now().Add(time.Hour).After(parsedCerts[0].NotAfter)) + assert.True(t, time.Now().Add(time.Minute*59).Before(parsedCerts[0].NotAfter)) + assert.True(t, time.Now().Add(time.Hour).Add(time.Minute).After(parsedCerts[0].NotAfter)) - // Sign the same CSR again, this time with a 29 Minute expiration RootCA (under the 30 minute minimum). + // Sign the same CSR again, this time with a 59 Minute expiration RootCA (under the 60 minute minimum). // This should use the default of 3 months - newRootCA, err = ca.NewRootCA(rootCA.Cert, rootCA.Key, 29*time.Minute) + newRootCA, err = ca.NewRootCA(rootCA.Cert, rootCA.Key, 59*time.Minute) assert.NoError(t, err) cert, err = newRootCA.ParseValidateAndSignCSR(csr, "CN", ca.ManagerRole, "ORG") diff --git a/ca/config.go b/ca/config.go index e8a03a419e..68e1d182d5 100644 --- a/ca/config.go +++ b/ca/config.go @@ -124,10 +124,16 @@ func SigningPolicy(certExpiry time.Duration) *cfconfig.Signing { certExpiry = DefaultNodeCertExpiration } + now := time.Now() + notBefore := now.Round(time.Minute).Add(CertBackdate).UTC() + notAfter := now.Round(time.Minute).Add(certExpiry).UTC() + return &cfconfig.Signing{ Default: &cfconfig.SigningProfile{ - Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, - Expiry: certExpiry, + Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, + Expiry: certExpiry, + NotBefore: notBefore, + NotAfter: notAfter, // Only trust the key components from the CSR. Everything else should // come directly from API call params. CSRWhitelist: &cfconfig.CSRWhitelist{