Skip to content

Commit

Permalink
connect: check if intermediate cert needs to be renewed. (#6835)
Browse files Browse the repository at this point in the history
Currently when using the built-in CA provider for Connect, root certificates are valid for 10 years, however secondary DCs get intermediates that are valid for only 1 year. There is no mechanism currently short of rotating the root in the primary that will cause the secondary DCs to renew their intermediates.
This PR adds a check that renews the cert if it is half way through its validity period.

In order to be able to test these changes, a new configuration option was added: IntermediateCertTTL which is set extremely low in the tests.
  • Loading branch information
hanshasselberg authored Jan 17, 2020
1 parent 87f32c8 commit 804eb17
Show file tree
Hide file tree
Showing 25 changed files with 474 additions and 132 deletions.
7 changes: 4 additions & 3 deletions agent/config/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,10 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
if connectCAConfig != nil {
lib.TranslateKeys(connectCAConfig, map[string]string{
// Consul CA config
"private_key": "PrivateKey",
"root_cert": "RootCert",
"rotation_period": "RotationPeriod",
"private_key": "PrivateKey",
"root_cert": "RootCert",
"rotation_period": "RotationPeriod",
"intermediate_cert_ttl": "IntermediateCertTTL",

// Vault CA config
"address": "Address",
Expand Down
11 changes: 7 additions & 4 deletions agent/config/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3766,6 +3766,7 @@ func TestFullConfig(t *testing.T) {
"ca_provider": "consul",
"ca_config": {
"rotation_period": "90h",
"intermediate_cert_ttl": "8760h",
"leaf_cert_ttl": "1h",
"csr_max_per_second": 100,
"csr_max_concurrent": 2
Expand Down Expand Up @@ -4367,6 +4368,7 @@ func TestFullConfig(t *testing.T) {
ca_provider = "consul"
ca_config {
rotation_period = "90h"
intermediate_cert_ttl = "8760h"
leaf_cert_ttl = "1h"
# hack float since json parses numbers as float and we have to
# assert against the same thing
Expand Down Expand Up @@ -5079,10 +5081,11 @@ func TestFullConfig(t *testing.T) {
ExposeMaxPort: 2222,
ConnectCAProvider: "consul",
ConnectCAConfig: map[string]interface{}{
"RotationPeriod": "90h",
"LeafCertTTL": "1h",
"CSRMaxPerSecond": float64(100),
"CSRMaxConcurrent": float64(2),
"RotationPeriod": "90h",
"IntermediateCertTTL": "8760h",
"LeafCertTTL": "1h",
"CSRMaxPerSecond": float64(100),
"CSRMaxConcurrent": float64(2),
},
DNSAddrs: []net.Addr{tcpAddr("93.95.95.81:7001"), udpAddr("93.95.95.81:7001")},
DNSARecordLimit: 29907,
Expand Down
2 changes: 1 addition & 1 deletion agent/connect/ca/provider_consul.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ func (c *ConsulProvider) SignIntermediate(csr *x509.CertificateRequest) (string,
x509.KeyUsageDigitalSignature,
IsCA: true,
MaxPathLenZero: true,
NotAfter: effectiveNow.AddDate(1, 0, 0),
NotAfter: effectiveNow.Add(c.config.IntermediateCertTTL),
NotBefore: effectiveNow,
SubjectKeyId: subjectKeyID,
}
Expand Down
3 changes: 2 additions & 1 deletion agent/connect/ca/provider_consul_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ func testConsulCAConfig() *structs.CAConfiguration {
Provider: "consul",
Config: map[string]interface{}{
// Tests duration parsing after msgpack type mangling during raft apply.
"LeafCertTTL": []uint8("72h"),
"LeafCertTTL": []uint8("72h"),
"IntermediateCertTTL": []uint8("72h"),
},
}
}
Expand Down
7 changes: 4 additions & 3 deletions agent/connect/testing_ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,9 +361,10 @@ func testCAConfigSet(t testing.T, a TestAgentRPC,
newConfig := &structs.CAConfiguration{
Provider: "consul",
Config: map[string]interface{}{
"PrivateKey": ca.SigningKey,
"RootCert": ca.RootCert,
"RotationPeriod": 180 * 24 * time.Hour,
"PrivateKey": ca.SigningKey,
"RootCert": ca.RootCert,
"RotationPeriod": 180 * 24 * time.Hour,
"IntermediateCertTTL": 72 * time.Hour,
},
}
args := &structs.CARequest{
Expand Down
23 changes: 22 additions & 1 deletion agent/connect_ca_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,28 @@ func TestConnectCAConfig(t *testing.T) {
},
},
},
{
name: "basic with IntermediateCertTTL",
body: `
{
"Provider": "consul",
"Config": {
"LeafCertTTL": "72h",
"RotationPeriod": "1h",
"IntermediateCertTTL": "2h"
}
}`,
wantErr: false,
wantCfg: structs.CAConfiguration{
Provider: "consul",
ClusterID: connect.TestClusterID,
Config: map[string]interface{}{
"LeafCertTTL": "72h",
"RotationPeriod": "1h",
"IntermediateCertTTL": "2h",
},
},
},
{
name: "force without cross sign CamelCase",
body: `
Expand Down Expand Up @@ -211,7 +233,6 @@ func TestConnectCAConfig(t *testing.T) {
}
require.NoError(err)
}

// The config should be updated now.
{
req, _ := http.NewRequest("GET", "/v1/connect/ca/configuration", nil)
Expand Down
5 changes: 3 additions & 2 deletions agent/consul/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,9 @@ func DefaultConfig() *Config {
CAConfig: &structs.CAConfiguration{
Provider: "consul",
Config: map[string]interface{}{
"RotationPeriod": "2160h",
"LeafCertTTL": "72h",
"RotationPeriod": "2160h",
"LeafCertTTL": "72h",
"IntermediateCertTTL": "8760h", // 365 * 24h
},
},

Expand Down
10 changes: 7 additions & 3 deletions agent/consul/fsm/commands_oss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1280,9 +1280,10 @@ func TestFSM_CAConfig(t *testing.T) {
Config: &structs.CAConfiguration{
Provider: "consul",
Config: map[string]interface{}{
"PrivateKey": "asdf",
"RootCert": "qwer",
"RotationPeriod": 90 * 24 * time.Hour,
"PrivateKey": "asdf",
"RootCert": "qwer",
"RotationPeriod": 90 * 24 * time.Hour,
"IntermediateCertTTL": 365 * 24 * time.Hour,
},
},
}
Expand Down Expand Up @@ -1314,6 +1315,9 @@ func TestFSM_CAConfig(t *testing.T) {
if got, want := conf.RotationPeriod, 90*24*time.Hour; got != want {
t.Fatalf("got %v, want %v", got, want)
}
if got, want := conf.IntermediateCertTTL, 365*24*time.Hour; got != want {
t.Fatalf("got %v, want %v", got, want)
}

// Now use CAS and provide an old index
req.Config.Provider = "static"
Expand Down
Loading

0 comments on commit 804eb17

Please sign in to comment.