From a287b3cd3a1ade244b1759dd47c425228bd64d2e Mon Sep 17 00:00:00 2001 From: "Chris S. Kim" Date: Wed, 12 Jul 2023 14:54:55 -0400 Subject: [PATCH] Fix bug with Vault CA provider where updating RootPKIPath but not IntermediatePKIPath would not update leaf signing certs with the new root. --- agent/connect/ca/mock_Provider.go | 48 +++++------ agent/connect/ca/provider.go | 2 +- agent/connect/ca/provider_aws.go | 10 +-- agent/connect/ca/provider_consul.go | 18 ++--- agent/connect/ca/provider_vault.go | 31 +++----- agent/consul/leader_connect_ca.go | 70 +++++++++++++---- agent/consul/leader_connect_ca_test.go | 105 ++++++++++++++++++++----- agent/consul/leader_connect_test.go | 10 ++- agent/structs/connect_ca.go | 8 +- 9 files changed, 198 insertions(+), 104 deletions(-) diff --git a/agent/connect/ca/mock_Provider.go b/agent/connect/ca/mock_Provider.go index 0c9725f5ee086..0a745ad9bb3f9 100644 --- a/agent/connect/ca/mock_Provider.go +++ b/agent/connect/ca/mock_Provider.go @@ -89,14 +89,13 @@ func (_m *MockProvider) CrossSignCA(_a0 *x509.Certificate) (string, error) { return r0, r1 } -// GenerateIntermediateCSR provides a mock function with given fields: -func (_m *MockProvider) GenerateIntermediateCSR() (string, string, error) { +// GenerateCAChain provides a mock function with given fields: +func (_m *MockProvider) GenerateCAChain() (string, error) { ret := _m.Called() var r0 string - var r1 string - var r2 error - if rf, ok := ret.Get(0).(func() (string, string, error)); ok { + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { return rf() } if rf, ok := ret.Get(0).(func() string); ok { @@ -105,43 +104,44 @@ func (_m *MockProvider) GenerateIntermediateCSR() (string, string, error) { r0 = ret.Get(0).(string) } - if rf, ok := ret.Get(1).(func() string); ok { + if rf, ok := ret.Get(1).(func() error); ok { r1 = rf() } else { - r1 = ret.Get(1).(string) - } - - if rf, ok := ret.Get(2).(func() error); ok { - r2 = rf() - } else { - r2 = ret.Error(2) + r1 = ret.Error(1) } - return r0, r1, r2 + return r0, r1 } -// GenerateCAChain provides a mock function with given fields: -func (_m *MockProvider) GenerateCAChain() (CAChainResult, error) { +// GenerateIntermediateCSR provides a mock function with given fields: +func (_m *MockProvider) GenerateIntermediateCSR() (string, string, error) { ret := _m.Called() - var r0 CAChainResult - var r1 error - if rf, ok := ret.Get(0).(func() (CAChainResult, error)); ok { + var r0 string + var r1 string + var r2 error + if rf, ok := ret.Get(0).(func() (string, string, error)); ok { return rf() } - if rf, ok := ret.Get(0).(func() CAChainResult); ok { + if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() } else { - r0 = ret.Get(0).(CAChainResult) + r0 = ret.Get(0).(string) } - if rf, ok := ret.Get(1).(func() error); ok { + if rf, ok := ret.Get(1).(func() string); ok { r1 = rf() } else { - r1 = ret.Error(1) + r1 = ret.Get(1).(string) } - return r0, r1 + if rf, ok := ret.Get(2).(func() error); ok { + r2 = rf() + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 } // SetIntermediate provides a mock function with given fields: intermediatePEM, rootPEM, opaque diff --git a/agent/connect/ca/provider.go b/agent/connect/ca/provider.go index 25d0deae35955..6f40e7b97f8e0 100644 --- a/agent/connect/ca/provider.go +++ b/agent/connect/ca/provider.go @@ -137,7 +137,7 @@ type PrimaryProvider interface { // Depending on the provider and its configuration, GenerateCAChain may return // a single root certificate or a chain of certs. The provider should return an // existing CA chain if one exists or generate a new one and return it. - GenerateCAChain() (CAChainResult, error) + GenerateCAChain() (string, error) // SignIntermediate will validate the CSR to ensure the trust domain in the // URI SAN matches the local one and that basic constraints for a CA diff --git a/agent/connect/ca/provider_aws.go b/agent/connect/ca/provider_aws.go index b7808edf94809..d45f3295a8e74 100644 --- a/agent/connect/ca/provider_aws.go +++ b/agent/connect/ca/provider_aws.go @@ -140,19 +140,19 @@ func (a *AWSProvider) State() (map[string]string, error) { } // GenerateCAChain implements Provider -func (a *AWSProvider) GenerateCAChain() (CAChainResult, error) { +func (a *AWSProvider) GenerateCAChain() (string, error) { if !a.isPrimary { - return CAChainResult{}, fmt.Errorf("provider is not the root certificate authority") + return "", fmt.Errorf("provider is not the root certificate authority") } if err := a.ensureCA(); err != nil { - return CAChainResult{}, err + return "", err } if a.rootPEM == "" { - return CAChainResult{}, fmt.Errorf("AWS CA provider not fully Initialized") + return "", fmt.Errorf("AWS CA provider not fully Initialized") } - return CAChainResult{PEM: a.rootPEM}, nil + return a.rootPEM, nil } // ensureCA loads the CA resource to check it exists if configured by User or in diff --git a/agent/connect/ca/provider_consul.go b/agent/connect/ca/provider_consul.go index b35800c6da4cb..01c4987e07d81 100644 --- a/agent/connect/ca/provider_consul.go +++ b/agent/connect/ca/provider_consul.go @@ -155,17 +155,17 @@ func (c *ConsulProvider) State() (map[string]string, error) { } // GenerateCAChain initializes a new root certificate and private key if needed. -func (c *ConsulProvider) GenerateCAChain() (CAChainResult, error) { +func (c *ConsulProvider) GenerateCAChain() (string, error) { providerState, err := c.getState() if err != nil { - return CAChainResult{}, err + return "", err } if !c.isPrimary { - return CAChainResult{}, fmt.Errorf("provider is not the root certificate authority") + return "", fmt.Errorf("provider is not the root certificate authority") } if providerState.RootCert != "" { - return CAChainResult{PEM: providerState.RootCert}, nil + return providerState.RootCert, nil } // Generate a private key if needed @@ -173,7 +173,7 @@ func (c *ConsulProvider) GenerateCAChain() (CAChainResult, error) { if c.config.PrivateKey == "" { _, pk, err := connect.GeneratePrivateKeyWithConfig(c.config.PrivateKeyType, c.config.PrivateKeyBits) if err != nil { - return CAChainResult{}, err + return "", err } newState.PrivateKey = pk } else { @@ -184,12 +184,12 @@ func (c *ConsulProvider) GenerateCAChain() (CAChainResult, error) { if c.config.RootCert == "" { nextSerial, err := c.incrementAndGetNextSerialNumber() if err != nil { - return CAChainResult{}, fmt.Errorf("error computing next serial number: %v", err) + return "", fmt.Errorf("error computing next serial number: %v", err) } ca, err := c.generateCA(newState.PrivateKey, nextSerial, c.config.RootCertTTL) if err != nil { - return CAChainResult{}, fmt.Errorf("error generating CA: %v", err) + return "", fmt.Errorf("error generating CA: %v", err) } newState.RootCert = ca } else { @@ -202,10 +202,10 @@ func (c *ConsulProvider) GenerateCAChain() (CAChainResult, error) { ProviderState: &newState, } if _, err := c.Delegate.ApplyCARequest(args); err != nil { - return CAChainResult{}, err + return "", err } - return CAChainResult{PEM: newState.RootCert}, nil + return newState.RootCert, nil } // GenerateIntermediateCSR creates a private key and generates a CSR diff --git a/agent/connect/ca/provider_vault.go b/agent/connect/ca/provider_vault.go index 89350d87df3e4..59b983dbecc4f 100644 --- a/agent/connect/ca/provider_vault.go +++ b/agent/connect/ca/provider_vault.go @@ -280,9 +280,9 @@ func (v *VaultProvider) State() (map[string]string, error) { } // GenerateCAChain mounts and initializes a new root PKI backend if needed. -func (v *VaultProvider) GenerateCAChain() (CAChainResult, error) { +func (v *VaultProvider) GenerateCAChain() (string, error) { if !v.isPrimary { - return CAChainResult{}, fmt.Errorf("provider is not the root certificate authority") + return "", fmt.Errorf("provider is not the root certificate authority") } // Set up the root PKI backend if necessary. @@ -302,7 +302,7 @@ func (v *VaultProvider) GenerateCAChain() (CAChainResult, error) { }, }) if err != nil { - return CAChainResult{}, fmt.Errorf("failed to mount root CA backend: %w", err) + return "", fmt.Errorf("failed to mount root CA backend: %w", err) } // We want to initialize afterwards @@ -310,7 +310,7 @@ func (v *VaultProvider) GenerateCAChain() (CAChainResult, error) { case ErrBackendNotInitialized: uid, err := connect.CompactUID() if err != nil { - return CAChainResult{}, err + return "", err } resp, err := v.writeNamespaced(v.config.RootPKINamespace, v.config.RootPKIPath+"root/generate/internal", map[string]interface{}{ "common_name": connect.CACN("vault", uid, v.clusterID, v.isPrimary), @@ -319,23 +319,23 @@ func (v *VaultProvider) GenerateCAChain() (CAChainResult, error) { "key_bits": v.config.PrivateKeyBits, }) if err != nil { - return CAChainResult{}, fmt.Errorf("failed to initialize root CA: %w", err) + return "", fmt.Errorf("failed to initialize root CA: %w", err) } var ok bool rootPEM, ok = resp.Data["certificate"].(string) if !ok { - return CAChainResult{}, fmt.Errorf("unexpected response from Vault: %v", resp.Data["certificate"]) + return "", fmt.Errorf("unexpected response from Vault: %v", resp.Data["certificate"]) } default: if err != nil { - return CAChainResult{}, fmt.Errorf("unexpected error while setting root PKI backend: %w", err) + return "", fmt.Errorf("unexpected error while setting root PKI backend: %w", err) } } rootChain, err := v.getCAChain(v.config.RootPKINamespace, v.config.RootPKIPath) if err != nil { - return CAChainResult{}, err + return "", err } // Workaround for a bug in the Vault PKI API. @@ -344,18 +344,7 @@ func (v *VaultProvider) GenerateCAChain() (CAChainResult, error) { rootChain = rootPEM } - intermediate, err := v.ActiveLeafSigningCert() - if err != nil { - return CAChainResult{}, fmt.Errorf("error fetching active intermediate: %w", err) - } - if intermediate == "" { - intermediate, err = v.GenerateLeafSigningCert() - if err != nil { - return CAChainResult{}, fmt.Errorf("error generating intermediate: %w", err) - } - } - - return CAChainResult{PEM: rootChain, IntermediatePEM: intermediate}, nil + return rootChain, nil } // GenerateIntermediateCSR creates a private key and generates a CSR @@ -582,7 +571,7 @@ func (v *VaultProvider) getCAChain(namespace, path string) (string, error) { return root, nil } -// GenerateIntermediate mounts the configured intermediate PKI backend if +// GenerateLeafSigningCert mounts the configured intermediate PKI backend if // necessary, then generates and signs a new CA CSR using the root PKI backend // and updates the intermediate backend to use that new certificate. func (v *VaultProvider) GenerateLeafSigningCert() (string, error) { diff --git a/agent/consul/leader_connect_ca.go b/agent/consul/leader_connect_ca.go index c8c63c8874aad..717c9ff0b2544 100644 --- a/agent/consul/leader_connect_ca.go +++ b/agent/consul/leader_connect_ca.go @@ -258,8 +258,8 @@ func (c *CAManager) initializeCAConfig() (*structs.CAConfiguration, error) { } // newCARoot returns a filled-in structs.CARoot from a raw PEM value. -func newCARoot(rootResult ca.CAChainResult, provider, clusterID string) (*structs.CARoot, error) { - primaryCert, err := connect.ParseCert(rootResult.PEM) +func newCARoot(caPem, provider, clusterID string) (*structs.CARoot, error) { + primaryCert, err := connect.ParseCert(caPem) if err != nil { return nil, err } @@ -275,17 +275,12 @@ func newCARoot(rootResult ca.CAChainResult, provider, clusterID string) (*struct ExternalTrustDomain: clusterID, NotBefore: primaryCert.NotBefore, NotAfter: primaryCert.NotAfter, - RootCert: lib.EnsureTrailingNewline(rootResult.PEM), + RootCert: lib.EnsureTrailingNewline(caPem), PrivateKeyType: keyType, PrivateKeyBits: keyBits, Active: true, } - if rootResult.IntermediatePEM == "" { - return caRoot, nil - } - if err := setLeafSigningCert(caRoot, rootResult.IntermediatePEM); err != nil { - return nil, fmt.Errorf("error setting leaf signing cert: %w", err) - } + return caRoot, nil } @@ -518,6 +513,19 @@ func (c *CAManager) primaryInitialize(provider ca.Provider, conf *structs.CAConf return err } + // provider may use intermediates for leaf signing in which case + // we need to generate a leaf signing CA. + if usesIntermediate, ok := provider.(ca.PrimaryUsesIntermediate); ok { + leafPem, err := usesIntermediate.GenerateLeafSigningCert() + if err != nil { + return fmt.Errorf("error generating new leaf signing cert: %w", err) + } + + if err := setLeafSigningCert(rootCA, leafPem); err != nil { + return fmt.Errorf("error setting leaf signing cert: %w", err) + } + } + var rootUpdateRequired bool if len(rootCA.IntermediateCerts) > 0 { rootUpdateRequired = true @@ -764,7 +772,6 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error) return err } - // Exit early if it's a no-op change state := c.delegate.State() _, config, err := state.CAConfig(nil) if err != nil { @@ -780,6 +787,8 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error) // Don't allow users to change the ClusterID. args.Config.ClusterID = config.ClusterID + + // Exit early if it's a no-op change if args.Config.Provider == config.Provider && reflect.DeepEqual(args.Config.Config, config.Config) { return nil } @@ -866,26 +875,53 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C } args.Config.State = pState - providerRoot, err := newProvider.GenerateCAChain() + caPEM, err := newProvider.GenerateCAChain() if err != nil { return fmt.Errorf("error generating CA root certificate: %v", err) } - newRootPEM := providerRoot.PEM - newActiveRoot, err := newCARoot(providerRoot, args.Config.Provider, args.Config.ClusterID) + newActiveRoot, err := newCARoot(caPEM, args.Config.Provider, args.Config.ClusterID) if err != nil { return err } + // Fetch the existing root CA to compare with the current one. state := c.delegate.State() - // Compare the new provider's root CA ID to the current one. If they - // match, just update the existing provider with the new config. - // If they don't match, begin the root rotation process. _, root, err := state.CARootActive(nil) if err != nil { return err } + // provider may use intermediates for leaf signing in which case + // we may need to generate a leaf signing CA if the root has changed. + if usesIntermediate, ok := newProvider.(ca.PrimaryUsesIntermediate); ok { + var leafPemFunc func() (string, error) + if root != nil && root.ID == newActiveRoot.ID { + // If Root ID is the same, we can reuse the existing leaf signing cert + leafPemFunc = newProvider.ActiveLeafSigningCert + } else { + // If Root ID is different, we need to generate a new leaf signing cert + // else the trust chain will break when the old root expires. + leafPemFunc = usesIntermediate.GenerateLeafSigningCert + } + leafPem, err := leafPemFunc() + if err != nil { + return fmt.Errorf("error fetching leaf signing cert: %w", err) + } + // newProvider.ActiveLeafSigningCert may return a blank leafPem so we + // fall back to generating a new one just in case. + if leafPem == "" { + leafPem, err = usesIntermediate.GenerateLeafSigningCert() + if err != nil { + return fmt.Errorf("error generating new leaf signing cert: %w", err) + } + } + + if err := setLeafSigningCert(newActiveRoot, leafPem); err != nil { + return fmt.Errorf("error setting leaf signing cert: %w", err) + } + } + // If the root didn't change, just update the config and return. if root != nil && root.ID == newActiveRoot.ID { args.Op = structs.CAOpSetConfig @@ -919,7 +955,7 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C // 3. Take the active root for the new provider and append the intermediate from step 2 // to its list of intermediates. // TODO: this cert is already parsed once in newCARoot, could we remove the second parse? - newRoot, err := connect.ParseCert(newRootPEM) + newRoot, err := connect.ParseCert(caPEM) if err != nil { return err } diff --git a/agent/consul/leader_connect_ca_test.go b/agent/consul/leader_connect_ca_test.go index a8ca93101e447..e1c2cf8506c29 100644 --- a/agent/consul/leader_connect_ca_test.go +++ b/agent/consul/leader_connect_ca_test.go @@ -259,8 +259,8 @@ type mockCAProvider struct { func (m *mockCAProvider) Configure(cfg ca.ProviderConfig) error { return nil } func (m *mockCAProvider) State() (map[string]string, error) { return nil, nil } -func (m *mockCAProvider) GenerateCAChain() (ca.CAChainResult, error) { - return ca.CAChainResult{PEM: m.rootPEM}, nil +func (m *mockCAProvider) GenerateCAChain() (string, error) { + return m.rootPEM, nil } func (m *mockCAProvider) GenerateIntermediateCSR() (string, string, error) { m.callbackCh <- "provider/GenerateIntermediateCSR" @@ -624,7 +624,7 @@ func TestCAManager_UpdateConfiguration_Vault_Primary(t *testing.T) { require.Equal(t, connect.HexString(cert.SubjectKeyId), origRoot.SigningKeyID) t.Run("update config without changing root", func(t *testing.T) { - err = s1.caManager.UpdateConfiguration(&structs.CARequest{ + require.NoError(t, s1.caManager.UpdateConfiguration(&structs.CARequest{ Config: &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ @@ -635,50 +635,117 @@ func TestCAManager_UpdateConfiguration_Vault_Primary(t *testing.T) { "CSRMaxPerSecond": 100, }, }, - }) - require.NoError(t, err) - _, sameRoot, err := s1.fsm.State().CARootActive(nil) + })) + + _, newRoot, err := s1.fsm.State().CARootActive(nil) require.NoError(t, err) - require.Len(t, sameRoot.IntermediateCerts, 1) - sameRoot.CreateIndex = s1.caManager.providerRoot.CreateIndex - sameRoot.ModifyIndex = s1.caManager.providerRoot.ModifyIndex + require.Len(t, newRoot.IntermediateCerts, 1) + newRoot.CreateIndex = s1.caManager.providerRoot.CreateIndex + newRoot.ModifyIndex = s1.caManager.providerRoot.ModifyIndex - cert, err := connect.ParseCert(s1.caManager.getLeafSigningCertFromRoot(sameRoot)) + orig, err := connect.ParseCert(s1.caManager.getLeafSigningCertFromRoot(newRoot)) require.NoError(t, err) - require.Equal(t, connect.HexString(cert.SubjectKeyId), sameRoot.SigningKeyID) + require.Equal(t, connect.HexString(orig.SubjectKeyId), newRoot.SigningKeyID) - require.Equal(t, origRoot, sameRoot) - require.Equal(t, sameRoot, s1.caManager.providerRoot) + require.Equal(t, origRoot, newRoot) + require.Equal(t, newRoot, s1.caManager.providerRoot) }) - t.Run("update config and change root", func(t *testing.T) { + t.Run("update config and change root only", func(t *testing.T) { + // Read the active leaf CA + provider, _ := s1.caManager.getCAProvider() + + before, err := provider.ActiveLeafSigningCert() + require.NoError(t, err) + vaultToken2 := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ RootPath: "pki-root-2", - IntermediatePath: "pki-intermediate-2", + IntermediatePath: "pki-intermediate", ConsulManaged: true, + WithSudo: true, }) - err = s1.caManager.UpdateConfiguration(&structs.CARequest{ + require.NoError(t, s1.caManager.UpdateConfiguration(&structs.CARequest{ Config: &structs.CAConfiguration{ Provider: "vault", Config: map[string]interface{}{ "Address": vault.Addr, "Token": vaultToken2, "RootPKIPath": "pki-root-2/", - "IntermediatePKIPath": "pki-intermediate-2/", + "IntermediatePKIPath": "pki-intermediate/", + }, + }, + })) + + // fetch the new root from the state store to check that + // raft apply has occurred. + _, newRoot, err := s1.fsm.State().CARootActive(nil) + require.NoError(t, err) + require.Len(t, newRoot.IntermediateCerts, 2, + "expected one cross-sign cert and one local leaf sign cert") + + // Refresh provider + provider, _ = s1.caManager.getCAProvider() + + // Leaf signing cert should have been updated + after, err := provider.ActiveLeafSigningCert() + require.NoError(t, err) + + require.NotEqual(t, before, after, + "expected leaf signing cert to be changed after RootPKIPath was changed") + + cert, err = connect.ParseCert(after) + require.NoError(t, err) + + require.Equal(t, connect.HexString(cert.SubjectKeyId), newRoot.SigningKeyID) + }) + + t.Run("update config, change root and intermediate", func(t *testing.T) { + // Read the active leaf CA + provider, _ := s1.caManager.getCAProvider() + + before, err := provider.ActiveLeafSigningCert() + require.NoError(t, err) + + vaultToken3 := ca.CreateVaultTokenWithAttrs(t, vault.Client(), &ca.VaultTokenAttributes{ + RootPath: "pki-root-3", + IntermediatePath: "pki-intermediate-3", + ConsulManaged: true, + }) + + err = s1.caManager.UpdateConfiguration(&structs.CARequest{ + Config: &structs.CAConfiguration{ + Provider: "vault", + Config: map[string]interface{}{ + "Address": vault.Addr, + "Token": vaultToken3, + "RootPKIPath": "pki-root-3/", + "IntermediatePKIPath": "pki-intermediate-3/", }, }, }) require.NoError(t, err) + // fetch the new root from the state store to check that + // raft apply has occurred. _, newRoot, err := s1.fsm.State().CARootActive(nil) require.NoError(t, err) require.Len(t, newRoot.IntermediateCerts, 2, "expected one cross-sign cert and one local leaf sign cert") - require.NotEqual(t, origRoot.ID, newRoot.ID) - cert, err = connect.ParseCert(s1.caManager.getLeafSigningCertFromRoot(newRoot)) + // Refresh provider + provider, _ = s1.caManager.getCAProvider() + + // Leaf signing cert should have been updated + after, err := provider.ActiveLeafSigningCert() require.NoError(t, err) + + require.NotEqual(t, before, after, + "expected leaf signing cert to be changed after RootPKIPath and IntermediatePKIPath were changed") + + cert, err = connect.ParseCert(after) + require.NoError(t, err) + require.Equal(t, connect.HexString(cert.SubjectKeyId), newRoot.SigningKeyID) }) } diff --git a/agent/consul/leader_connect_test.go b/agent/consul/leader_connect_test.go index 105bf317bdfde..539226b297d3d 100644 --- a/agent/consul/leader_connect_test.go +++ b/agent/consul/leader_connect_test.go @@ -1362,10 +1362,12 @@ func TestNewCARoot(t *testing.T) { } run := func(t *testing.T, tc testCase) { - root, err := newCARoot(ca.CAChainResult{ - PEM: tc.pem, - IntermediatePEM: tc.intermediatePem, - }, "provider-name", "cluster-id") + root, err := newCARoot( + tc.pem, + "provider-name", "cluster-id") + if tc.intermediatePem != "" { + setLeafSigningCert(root, tc.intermediatePem) + } if tc.expectedErr != "" { testutil.RequireErrorContains(t, err, tc.expectedErr) return diff --git a/agent/structs/connect_ca.go b/agent/structs/connect_ca.go index c8a7cea1df8ae..63543fd87e1d3 100644 --- a/agent/structs/connect_ca.go +++ b/agent/structs/connect_ca.go @@ -17,8 +17,8 @@ import ( ) const ( - DefaultLeafCertTTL = "72h" - DefaultIntermediateCertTTL = "8760h" // ~ 1 year = 365 * 24h + DefaultLeafCertTTL = "15min" + DefaultIntermediateCertTTL = "1h" // ~ 1 year = 365 * 24h DefaultRootCertTTL = "87600h" // ~ 10 years = 365 * 24h * 10 ) @@ -433,12 +433,12 @@ type CommonCAProviderConfig struct { PrivateKeyBits int } -var MinLeafCertTTL = time.Hour +var MinLeafCertTTL = time.Minute var MaxLeafCertTTL = 365 * 24 * time.Hour // intermediateCertRenewInterval is the interval at which the expiration // of the intermediate cert is checked and renewed if necessary. -var IntermediateCertRenewInterval = time.Hour +var IntermediateCertRenewInterval = 30 * time.Minute func (c CommonCAProviderConfig) Validate() error { if c.SkipValidate {