add root_cert_ttl option for consul connect, vault ca providers (#11428)
* add root_cert_ttl option for consul connect, vault ca providers Signed-off-by: FFMMM <FFMMM@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Chris S. Kim <ckim@hashicorp.com> * add changelog, pr feedback Signed-off-by: FFMMM <FFMMM@users.noreply.github.com> * Update .changelog/11428.txt, more docs Co-authored-by: Daniel Nephin <dnephin@hashicorp.com> * Update website/content/docs/agent/options.mdx Co-authored-by: Kyle Havlovitz <kylehav@gmail.com> Co-authored-by: Chris S. Kim <ckim@hashicorp.com> Co-authored-by: Daniel Nephin <dnephin@hashicorp.com> Co-authored-by: Kyle Havlovitz <kylehav@gmail.com>
This commit is contained in:
parent
0ec2a804df
commit
27227c0fd2
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
ca: Add a configurable TTL for Connect CA root certificates. The configuration is supported by the Vault and Consul providers.
|
||||
```
|
|
@ -724,6 +724,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) {
|
|||
"csr_max_concurrent": "CSRMaxConcurrent",
|
||||
"private_key_type": "PrivateKeyType",
|
||||
"private_key_bits": "PrivateKeyBits",
|
||||
"root_cert_ttl": "RootCertTTL",
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1623,6 +1623,7 @@ func (c *RuntimeConfig) ConnectCAConfiguration() (*structs.CAConfiguration, erro
|
|||
Config: map[string]interface{}{
|
||||
"LeafCertTTL": structs.DefaultLeafCertTTL,
|
||||
"IntermediateCertTTL": structs.DefaultIntermediateCertTTL,
|
||||
"RootCertTTL": structs.DefaultRootCertTTL,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -3162,6 +3162,65 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
|||
}
|
||||
},
|
||||
})
|
||||
run(t, testCase{
|
||||
desc: "test connect vault provider configuration with root cert ttl",
|
||||
args: []string{
|
||||
`-data-dir=` + dataDir,
|
||||
},
|
||||
json: []string{`{
|
||||
"connect": {
|
||||
"enabled": true,
|
||||
"ca_provider": "vault",
|
||||
"ca_config": {
|
||||
"ca_file": "/capath/ca.pem",
|
||||
"ca_path": "/capath/",
|
||||
"cert_file": "/certpath/cert.pem",
|
||||
"key_file": "/certpath/key.pem",
|
||||
"tls_server_name": "server.name",
|
||||
"tls_skip_verify": true,
|
||||
"token": "abc",
|
||||
"root_pki_path": "consul-vault",
|
||||
"root_cert_ttl": "96360h",
|
||||
"intermediate_pki_path": "connect-intermediate"
|
||||
}
|
||||
}
|
||||
}`},
|
||||
hcl: []string{`
|
||||
connect {
|
||||
enabled = true
|
||||
ca_provider = "vault"
|
||||
ca_config {
|
||||
ca_file = "/capath/ca.pem"
|
||||
ca_path = "/capath/"
|
||||
cert_file = "/certpath/cert.pem"
|
||||
key_file = "/certpath/key.pem"
|
||||
tls_server_name = "server.name"
|
||||
tls_skip_verify = true
|
||||
root_pki_path = "consul-vault"
|
||||
token = "abc"
|
||||
intermediate_pki_path = "connect-intermediate"
|
||||
root_cert_ttl = "96360h"
|
||||
}
|
||||
}
|
||||
`},
|
||||
expected: func(rt *RuntimeConfig) {
|
||||
rt.DataDir = dataDir
|
||||
rt.ConnectEnabled = true
|
||||
rt.ConnectCAProvider = "vault"
|
||||
rt.ConnectCAConfig = map[string]interface{}{
|
||||
"CAFile": "/capath/ca.pem",
|
||||
"CAPath": "/capath/",
|
||||
"CertFile": "/certpath/cert.pem",
|
||||
"KeyFile": "/certpath/key.pem",
|
||||
"TLSServerName": "server.name",
|
||||
"TLSSkipVerify": true,
|
||||
"Token": "abc",
|
||||
"RootPKIPath": "consul-vault",
|
||||
"RootCertTTL": "96360h",
|
||||
"IntermediatePKIPath": "connect-intermediate",
|
||||
}
|
||||
},
|
||||
})
|
||||
run(t, testCase{
|
||||
desc: "Connect AWS CA provider configuration",
|
||||
args: []string{
|
||||
|
@ -5472,6 +5531,7 @@ func TestLoad_FullConfig(t *testing.T) {
|
|||
ConnectCAConfig: map[string]interface{}{
|
||||
"IntermediateCertTTL": "8760h",
|
||||
"LeafCertTTL": "1h",
|
||||
"RootCertTTL": "96360h",
|
||||
"CSRMaxPerSecond": float64(100),
|
||||
"CSRMaxConcurrent": float64(2),
|
||||
},
|
||||
|
@ -6651,7 +6711,8 @@ func TestConnectCAConfiguration(t *testing.T) {
|
|||
Provider: "consul",
|
||||
Config: map[string]interface{}{
|
||||
"LeafCertTTL": "72h",
|
||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||
"RootCertTTL": "87600h", // 365 * 10 * 24h
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -6667,7 +6728,8 @@ func TestConnectCAConfiguration(t *testing.T) {
|
|||
ClusterID: "adfe7697-09b4-413a-ac0a-fa81ed3a3001",
|
||||
Config: map[string]interface{}{
|
||||
"LeafCertTTL": "72h",
|
||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||
"RootCertTTL": "87600h", // 365 * 10 * 24h
|
||||
"cluster_id": "adfe7697-09b4-413a-ac0a-fa81ed3a3001",
|
||||
},
|
||||
},
|
||||
|
@ -6690,7 +6752,8 @@ func TestConnectCAConfiguration(t *testing.T) {
|
|||
Provider: "vault",
|
||||
Config: map[string]interface{}{
|
||||
"LeafCertTTL": "72h",
|
||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||
"RootCertTTL": "87600h", // 365 * 10 * 24h
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -6698,7 +6761,8 @@ func TestConnectCAConfiguration(t *testing.T) {
|
|||
config: RuntimeConfig{
|
||||
ConnectEnabled: true,
|
||||
ConnectCAConfig: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"foo": "bar",
|
||||
"RootCertTTL": "8761h", // 365 * 24h + 1
|
||||
},
|
||||
},
|
||||
expected: &structs.CAConfiguration{
|
||||
|
@ -6706,6 +6770,7 @@ func TestConnectCAConfiguration(t *testing.T) {
|
|||
Config: map[string]interface{}{
|
||||
"LeafCertTTL": "72h",
|
||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||
"RootCertTTL": "8761h", // 365 * 24h + 1
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -200,6 +200,7 @@ connect {
|
|||
ca_config {
|
||||
intermediate_cert_ttl = "8760h"
|
||||
leaf_cert_ttl = "1h"
|
||||
root_cert_ttl = "96360h"
|
||||
# hack float since json parses numbers as float and we have to
|
||||
# assert against the same thing
|
||||
csr_max_per_second = 100.0
|
||||
|
|
|
@ -200,6 +200,7 @@
|
|||
"connect": {
|
||||
"ca_provider": "consul",
|
||||
"ca_config": {
|
||||
"root_cert_ttl": "96360h",
|
||||
"intermediate_cert_ttl": "8760h",
|
||||
"leaf_cert_ttl": "1h",
|
||||
"csr_max_per_second": 100,
|
||||
|
|
|
@ -96,7 +96,7 @@ func (c *ConsulProvider) Configure(cfg ProviderConfig) error {
|
|||
fmt.Sprintf("%s,%s", config.PrivateKey, config.RootCert),
|
||||
}
|
||||
|
||||
// Check if there any entries with old ID schemes.
|
||||
// Check if there are any entries with old ID schemes.
|
||||
for _, oldID := range oldIDs {
|
||||
_, providerState, err = c.Delegate.State().CAProviderState(oldID)
|
||||
if err != nil {
|
||||
|
@ -194,7 +194,7 @@ func (c *ConsulProvider) GenerateRoot() error {
|
|||
return fmt.Errorf("error computing next serial number: %v", err)
|
||||
}
|
||||
|
||||
ca, err := c.generateCA(newState.PrivateKey, nextSerial)
|
||||
ca, err := c.generateCA(newState.PrivateKey, nextSerial, c.config.RootCertTTL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating CA: %v", err)
|
||||
}
|
||||
|
@ -616,7 +616,7 @@ func (c *ConsulProvider) incrementAndGetNextSerialNumber() (uint64, error) {
|
|||
}
|
||||
|
||||
// generateCA makes a new root CA using the current private key
|
||||
func (c *ConsulProvider) generateCA(privateKey string, sn uint64) (string, error) {
|
||||
func (c *ConsulProvider) generateCA(privateKey string, sn uint64, rootCertTTL time.Duration) (string, error) {
|
||||
stateStore := c.Delegate.State()
|
||||
_, config, err := stateStore.CAConfig(nil)
|
||||
if err != nil {
|
||||
|
@ -652,7 +652,7 @@ func (c *ConsulProvider) generateCA(privateKey string, sn uint64) (string, error
|
|||
x509.KeyUsageCRLSign |
|
||||
x509.KeyUsageDigitalSignature,
|
||||
IsCA: true,
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
NotAfter: time.Now().Add(rootCertTTL),
|
||||
NotBefore: time.Now(),
|
||||
AuthorityKeyId: keyId,
|
||||
SubjectKeyId: keyId,
|
||||
|
|
|
@ -52,5 +52,6 @@ func defaultCommonConfig() structs.CommonCAProviderConfig {
|
|||
IntermediateCertTTL: 24 * 365 * time.Hour,
|
||||
PrivateKeyType: connect.DefaultPrivateKeyType,
|
||||
PrivateKeyBits: connect.DefaultPrivateKeyBits,
|
||||
RootCertTTL: 10 * 24 * 365 * time.Hour,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,8 +43,9 @@ func testConsulCAConfig() *structs.CAConfiguration {
|
|||
Provider: "consul",
|
||||
Config: map[string]interface{}{
|
||||
// Tests duration parsing after msgpack type mangling during raft apply.
|
||||
"LeafCertTTL": []uint8("72h"),
|
||||
"IntermediateCertTTL": []uint8("288h"),
|
||||
"LeafCertTTL": []byte("72h"),
|
||||
"IntermediateCertTTL": []byte("288h"),
|
||||
"RootCertTTL": []byte("87600h"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +89,14 @@ func TestConsulCAProvider_Bootstrap(t *testing.T) {
|
|||
require.Equal(parsed.URIs[0].String(), fmt.Sprintf("spiffe://%s.consul", conf.ClusterID))
|
||||
requireNotEncoded(t, parsed.SubjectKeyId)
|
||||
requireNotEncoded(t, parsed.AuthorityKeyId)
|
||||
|
||||
// test that the root cert ttl is the same as the expected value
|
||||
// notice that we allow a margin of "error" of 10 minutes between the
|
||||
// generateCA() creation and this check
|
||||
defaultRootCertTTL, err := time.ParseDuration(structs.DefaultRootCertTTL)
|
||||
require.NoError(err)
|
||||
expectedNotAfter := time.Now().Add(defaultRootCertTTL).UTC()
|
||||
require.WithinDuration(expectedNotAfter, parsed.NotAfter, 10*time.Minute, "expected parsed cert ttl to be the same as the value configured")
|
||||
}
|
||||
|
||||
func TestConsulCAProvider_Bootstrap_WithCert(t *testing.T) {
|
||||
|
@ -95,7 +104,7 @@ func TestConsulCAProvider_Bootstrap_WithCert(t *testing.T) {
|
|||
|
||||
// Make sure setting a custom private key/root cert works.
|
||||
require := require.New(t)
|
||||
rootCA := connect.TestCA(t, nil)
|
||||
rootCA := connect.TestCAWithTTL(t, nil, 5*time.Hour)
|
||||
conf := testConsulCAConfig()
|
||||
conf.Config = map[string]interface{}{
|
||||
"PrivateKey": rootCA.SigningKey,
|
||||
|
@ -110,6 +119,18 @@ func TestConsulCAProvider_Bootstrap_WithCert(t *testing.T) {
|
|||
root, err := provider.ActiveRoot()
|
||||
require.NoError(err)
|
||||
require.Equal(root, rootCA.RootCert)
|
||||
|
||||
// Should be a valid cert
|
||||
parsed, err := connect.ParseCert(root)
|
||||
require.NoError(err)
|
||||
|
||||
// test that the default root cert ttl was not applied to the provided cert
|
||||
defaultRootCertTTL, err := time.ParseDuration(structs.DefaultRootCertTTL)
|
||||
require.NoError(err)
|
||||
defaultNotAfter := time.Now().Add(defaultRootCertTTL).UTC()
|
||||
// we can't compare given the "delta" between the time the cert is generated
|
||||
// and when we start the test; so just look at the years for now, given different years
|
||||
require.NotEqualf(defaultNotAfter.Year(), parsed.NotAfter.Year(), "parsed cert ttl expected to be different from default root cert ttl")
|
||||
}
|
||||
|
||||
func TestConsulCAProvider_SignLeaf(t *testing.T) {
|
||||
|
|
|
@ -34,6 +34,7 @@ func TestStructs_CAConfiguration_MsgpackEncodeDecode(t *testing.T) {
|
|||
CSRMaxConcurrent: 55,
|
||||
PrivateKeyType: "rsa",
|
||||
PrivateKeyBits: 4096,
|
||||
RootCertTTL: 10 * 24 * 365 * time.Hour,
|
||||
}
|
||||
|
||||
cases := map[string]testcase{
|
||||
|
|
|
@ -170,7 +170,11 @@ func (v *VaultProvider) GenerateRoot() error {
|
|||
Type: "pki",
|
||||
Description: "root CA backend for Consul Connect",
|
||||
Config: vaultapi.MountConfigInput{
|
||||
MaxLeaseTTL: "8760h",
|
||||
// the max lease ttl denotes the maximum ttl that secrets are created from the engine
|
||||
// the default lease ttl is the kind of ttl that will *reliably* set the ttl to v.config.RootCertTTL
|
||||
// https://www.vaultproject.io/docs/secrets/pki#configure-a-ca-certificate
|
||||
MaxLeaseTTL: v.config.RootCertTTL.String(),
|
||||
DefaultLeaseTTL: v.config.RootCertTTL.String(),
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -89,28 +89,51 @@ func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
|||
|
||||
SkipIfVaultNotPresent(t)
|
||||
|
||||
provider, testVault := testVaultProvider(t)
|
||||
defer testVault.Stop()
|
||||
client := testVault.client
|
||||
providerWDefaultRootCertTtl, testvault1 := testVaultProviderWithConfig(t, true, map[string]interface{}{
|
||||
"LeafCertTTL": "1h",
|
||||
})
|
||||
defer testvault1.Stop()
|
||||
client1 := testvault1.client
|
||||
|
||||
providerCustomRootCertTtl, testvault2 := testVaultProviderWithConfig(t, true, map[string]interface{}{
|
||||
"LeafCertTTL": "1h",
|
||||
"RootCertTTL": "8761h",
|
||||
})
|
||||
defer testvault2.Stop()
|
||||
client2 := testvault2.client
|
||||
|
||||
require := require.New(t)
|
||||
|
||||
cases := []struct {
|
||||
certFunc func() (string, error)
|
||||
backendPath string
|
||||
certFunc func() (string, error)
|
||||
backendPath string
|
||||
rootCaCreation bool
|
||||
provider *VaultProvider
|
||||
client *vaultapi.Client
|
||||
expectedRootCertTTL string
|
||||
}{
|
||||
{
|
||||
certFunc: provider.ActiveRoot,
|
||||
backendPath: "pki-root/",
|
||||
certFunc: providerWDefaultRootCertTtl.ActiveRoot,
|
||||
backendPath: "pki-root/",
|
||||
rootCaCreation: true,
|
||||
client: client1,
|
||||
provider: providerWDefaultRootCertTtl,
|
||||
expectedRootCertTTL: structs.DefaultRootCertTTL,
|
||||
},
|
||||
{
|
||||
certFunc: provider.ActiveIntermediate,
|
||||
backendPath: "pki-intermediate/",
|
||||
certFunc: providerCustomRootCertTtl.ActiveIntermediate,
|
||||
backendPath: "pki-intermediate/",
|
||||
rootCaCreation: false,
|
||||
provider: providerCustomRootCertTtl,
|
||||
client: client2,
|
||||
expectedRootCertTTL: "8761h",
|
||||
},
|
||||
}
|
||||
|
||||
// Verify the root and intermediate certs match the ones in the vault backends
|
||||
for _, tc := range cases {
|
||||
provider := tc.provider
|
||||
client := tc.client
|
||||
cert, err := tc.certFunc()
|
||||
require.NoError(err)
|
||||
req := client.NewRequest("GET", "/v1/"+tc.backendPath+"ca/pem")
|
||||
|
@ -126,6 +149,15 @@ func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
|||
require.True(parsed.IsCA)
|
||||
require.Len(parsed.URIs, 1)
|
||||
require.Equal(fmt.Sprintf("spiffe://%s.consul", provider.clusterID), parsed.URIs[0].String())
|
||||
|
||||
// test that the root cert ttl as applied
|
||||
if tc.rootCaCreation {
|
||||
rootCertTTL, err := time.ParseDuration(tc.expectedRootCertTTL)
|
||||
require.NoError(err)
|
||||
expectedNotAfter := time.Now().Add(rootCertTTL).UTC()
|
||||
|
||||
require.WithinDuration(expectedNotAfter, parsed.NotAfter, 10*time.Minute, "expected parsed cert ttl to be the same as the value configured")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ func makeConfig(kc KeyConfig) structs.CommonCAProviderConfig {
|
|||
return structs.CommonCAProviderConfig{
|
||||
LeafCertTTL: 3 * 24 * time.Hour,
|
||||
IntermediateCertTTL: 365 * 24 * time.Hour,
|
||||
RootCertTTL: 10 * 365 * 24 * time.Hour,
|
||||
PrivateKeyType: kc.keyType,
|
||||
PrivateKeyBits: kc.keyBits,
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ func (s *HTTPHandlers) ConnectCAConfiguration(resp http.ResponseWriter, req *htt
|
|||
}
|
||||
}
|
||||
|
||||
// GEt /v1/connect/ca/configuration
|
||||
// GET /v1/connect/ca/configuration
|
||||
func (s *HTTPHandlers) ConnectCAConfigurationGet(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
// Method is tested in ConnectCAConfiguration
|
||||
var args structs.DCSpecificRequest
|
||||
|
|
|
@ -494,6 +494,7 @@ func DefaultConfig() *Config {
|
|||
Config: map[string]interface{}{
|
||||
"LeafCertTTL": structs.DefaultLeafCertTTL,
|
||||
"IntermediateCertTTL": structs.DefaultIntermediateCertTTL,
|
||||
"RootCertTTL": structs.DefaultRootCertTTL,
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ import (
|
|||
|
||||
const (
|
||||
DefaultLeafCertTTL = "72h"
|
||||
DefaultIntermediateCertTTL = "8760h" // 365 * 24h
|
||||
DefaultIntermediateCertTTL = "8760h" // ~ 1 year = 365 * 24h
|
||||
DefaultRootCertTTL = "87600h" // ~ 10 years = 365 * 24h * 10
|
||||
)
|
||||
|
||||
// IndexedCARoots is the list of currently trusted CA Roots.
|
||||
|
@ -326,6 +327,7 @@ func (c *CAConfiguration) GetCommonConfig() (*CommonCAProviderConfig, error) {
|
|||
type CommonCAProviderConfig struct {
|
||||
LeafCertTTL time.Duration
|
||||
IntermediateCertTTL time.Duration
|
||||
RootCertTTL time.Duration
|
||||
|
||||
SkipValidate bool
|
||||
|
||||
|
@ -380,6 +382,12 @@ func (c CommonCAProviderConfig) Validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// it's sufficient to check that the root cert ttl >= intermediate cert ttl
|
||||
// since intermediate cert ttl >= 3* leaf cert ttl; so root cert ttl >= 3 * leaf cert ttl > leaf cert ttl
|
||||
if c.RootCertTTL < c.IntermediateCertTTL {
|
||||
return fmt.Errorf("root cert TTL is set and is not greater than intermediate cert ttl. root cert ttl: %s, intermediate cert ttl: %s", c.RootCertTTL, c.IntermediateCertTTL)
|
||||
}
|
||||
|
||||
if c.LeafCertTTL < MinLeafCertTTL {
|
||||
return fmt.Errorf("leaf cert TTL must be greater or equal than %s", MinLeafCertTTL)
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ func TestCAProviderConfig_Validate(t *testing.T) {
|
|||
cfg: &CommonCAProviderConfig{
|
||||
LeafCertTTL: 2 * time.Hour,
|
||||
IntermediateCertTTL: 4 * time.Hour,
|
||||
RootCertTTL: 5 * time.Hour,
|
||||
},
|
||||
wantErr: true,
|
||||
wantMsg: "Intermediate Cert TTL must be greater or equal than 3 * LeafCertTTL (>=6h0m0s).",
|
||||
|
@ -89,6 +90,7 @@ func TestCAProviderConfig_Validate(t *testing.T) {
|
|||
cfg: &CommonCAProviderConfig{
|
||||
LeafCertTTL: 5 * time.Hour,
|
||||
IntermediateCertTTL: 15*time.Hour - 1,
|
||||
RootCertTTL: 15 * time.Hour,
|
||||
},
|
||||
wantErr: true,
|
||||
wantMsg: "Intermediate Cert TTL must be greater or equal than 3 * LeafCertTTL (>=15h0m0s).",
|
||||
|
@ -98,6 +100,7 @@ func TestCAProviderConfig_Validate(t *testing.T) {
|
|||
cfg: &CommonCAProviderConfig{
|
||||
LeafCertTTL: 1 * time.Hour,
|
||||
IntermediateCertTTL: 4 * time.Hour,
|
||||
RootCertTTL: 5 * time.Hour,
|
||||
},
|
||||
wantErr: true,
|
||||
wantMsg: "private key type must be either 'ec' or 'rsa'",
|
||||
|
@ -107,6 +110,7 @@ func TestCAProviderConfig_Validate(t *testing.T) {
|
|||
cfg: &CommonCAProviderConfig{
|
||||
LeafCertTTL: 1 * time.Hour,
|
||||
IntermediateCertTTL: 4 * time.Hour,
|
||||
RootCertTTL: 5 * time.Hour,
|
||||
PrivateKeyType: "ec",
|
||||
},
|
||||
wantErr: true,
|
||||
|
@ -117,11 +121,36 @@ func TestCAProviderConfig_Validate(t *testing.T) {
|
|||
cfg: &CommonCAProviderConfig{
|
||||
LeafCertTTL: 1 * time.Hour,
|
||||
IntermediateCertTTL: 4 * time.Hour,
|
||||
RootCertTTL: 5 * time.Hour,
|
||||
PrivateKeyType: "ec",
|
||||
PrivateKeyBits: 256,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "good root cert/ intermediate TTLs",
|
||||
cfg: &CommonCAProviderConfig{
|
||||
LeafCertTTL: 1 * time.Hour,
|
||||
IntermediateCertTTL: 4 * time.Hour,
|
||||
RootCertTTL: 5 * time.Hour,
|
||||
PrivateKeyType: "ec",
|
||||
PrivateKeyBits: 256,
|
||||
},
|
||||
wantErr: false,
|
||||
wantMsg: "",
|
||||
},
|
||||
{
|
||||
name: "bad root cert/ intermediate TTLs",
|
||||
cfg: &CommonCAProviderConfig{
|
||||
LeafCertTTL: 1 * time.Hour,
|
||||
IntermediateCertTTL: 4 * time.Hour,
|
||||
RootCertTTL: 3 * time.Hour,
|
||||
PrivateKeyType: "ec",
|
||||
PrivateKeyBits: 256,
|
||||
},
|
||||
wantErr: true,
|
||||
wantMsg: "root cert TTL is set and is not greater than intermediate cert ttl. root cert ttl: 3h0m0s, intermediate cert ttl: 4h0m0s",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -38,6 +38,7 @@ type CAConfig struct {
|
|||
// CommonCAProviderConfig is the common options available to all CA providers.
|
||||
type CommonCAProviderConfig struct {
|
||||
LeafCertTTL time.Duration
|
||||
RootCertTTL time.Duration
|
||||
SkipValidate bool
|
||||
CSRMaxPerSecond float32
|
||||
CSRMaxConcurrent int
|
||||
|
|
|
@ -66,6 +66,7 @@ func TestAPI_ConnectCAConfig_get_set(t *testing.T) {
|
|||
IntermediateCertTTL: 365 * 24 * time.Hour,
|
||||
}
|
||||
expected.LeafCertTTL = 72 * time.Hour
|
||||
expected.RootCertTTL = 10 * 365 * 24 * time.Hour
|
||||
|
||||
// This fails occasionally if server doesn't have time to bootstrap CA so
|
||||
// retry
|
||||
|
@ -84,6 +85,7 @@ func TestAPI_ConnectCAConfig_get_set(t *testing.T) {
|
|||
// Change a config value and update
|
||||
conf.Config["PrivateKey"] = ""
|
||||
conf.Config["IntermediateCertTTL"] = 300 * 24 * time.Hour
|
||||
conf.Config["RootCertTTL"] = 11 * 365 * 24 * time.Hour
|
||||
|
||||
// Pass through some state as if the provider stored it so we can make sure
|
||||
// we can read it again.
|
||||
|
@ -95,6 +97,7 @@ func TestAPI_ConnectCAConfig_get_set(t *testing.T) {
|
|||
updated, _, err := connect.CAGetConfig(nil)
|
||||
r.Check(err)
|
||||
expected.IntermediateCertTTL = 300 * 24 * time.Hour
|
||||
expected.RootCertTTL = 11 * 365 * 24 * time.Hour
|
||||
parsed, err = ParseConsulCAConfig(updated.Config)
|
||||
r.Check(err)
|
||||
require.Equal(r, expected, parsed)
|
||||
|
|
|
@ -224,6 +224,7 @@ type TestServer struct {
|
|||
// callback function to modify the configuration. If there is an error
|
||||
// configuring or starting the server, the server will NOT be running when the
|
||||
// function returns (thus you do not need to stop it).
|
||||
// This function will call the `consul` binary in GOPATH.
|
||||
func NewTestServerConfigT(t TestingTB, cb ServerConfigCallback) (*TestServer, error) {
|
||||
path, err := exec.LookPath("consul")
|
||||
if err != nil || path == "" {
|
||||
|
|
|
@ -1267,6 +1267,18 @@ bind_addr = "{{ GetPrivateInterfaces | include \"network\" \"10.0.0.0/8\" | attr
|
|||
for more than twice the _current_ `leaf_cert_ttl`, it will be removed
|
||||
from the trusted list.
|
||||
|
||||
- `root_cert_ttl` ((#ca_root_cert_ttl)) The time to live (TTL) for a root certificate.
|
||||
Defaults to 10 years as `87600h`. This value, if provided, needs to be higher than the
|
||||
intermediate certificate TTL.
|
||||
|
||||
This setting currently applies only to the consul connect and Vault CA providers. It is
|
||||
ignored for the AWS acm pca provider. The value for root certificates issued by the AWS
|
||||
CA provider is 5 years and not configurable at this time.
|
||||
|
||||
For the Vault provider, this value is only used if the backend is not initialized at first.
|
||||
|
||||
This value is also applied on the `ca set-config` command.
|
||||
|
||||
- `private_key_type` ((#ca_private_key_type)) The type of key to generate
|
||||
for this CA. This is only used when the provider is generating a new key. If
|
||||
`private_key` is set for the Consul provider, or existing root or intermediate
|
||||
|
|
|
@ -35,6 +35,16 @@ The following configuration options are supported by all CA providers:
|
|||
for more than twice the _current_ `leaf_cert_ttl`, it will be removed
|
||||
from the trusted list.
|
||||
|
||||
- `RootCertTTL` / `root_cert_ttl` (`duration: "87600h"`) The time to live (TTL) for a root certificate.
|
||||
Defaults to 10 years as `87600h`. This value, if provided, needs to be higher than the
|
||||
intermediate certificate TTL.
|
||||
|
||||
This setting currently applies only to the consul connect and Vault CA providers. It is
|
||||
ignored for the AWS acm pca provider. The value for root certificates issued by the AWS
|
||||
CA provider is 5 years and not configurable at this time.
|
||||
|
||||
For the Vault provider, this value is only used if the backend is not initialized at first.
|
||||
|
||||
- `PrivateKeyType` / `private_key_type` (`string: "ec"`) - The type of key to generate
|
||||
for this CA. This is only used when the provider is generating a new key. If
|
||||
`private_key` is set for the Consul provider, or existing root or intermediate
|
||||
|
|
Loading…
Reference in New Issue