ca: add test cases for rotating external trusted CA
This commit is contained in:
parent
aacc40012f
commit
0abaf29c10
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
ca: support using an external root CA with the vault CA provider
|
||||||
|
```
|
|
@ -98,14 +98,25 @@ func TestCAManager_Initialize_Vault_Secondary_SharedVault(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyLeafCert(t *testing.T, root *structs.CARoot, leafCertPEM string) {
|
func verifyLeafCert(t *testing.T, root *structs.CARoot, leafCertPEM string) {
|
||||||
|
t.Helper()
|
||||||
|
roots := structs.IndexedCARoots{
|
||||||
|
ActiveRootID: root.ID,
|
||||||
|
Roots: []*structs.CARoot{root},
|
||||||
|
}
|
||||||
|
verifyLeafCertWithRoots(t, roots, leafCertPEM)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyLeafCertWithRoots(t *testing.T, roots structs.IndexedCARoots, leafCertPEM string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
leaf, intermediates, err := connect.ParseLeafCerts(leafCertPEM)
|
leaf, intermediates, err := connect.ParseLeafCerts(leafCertPEM)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pool := x509.NewCertPool()
|
pool := x509.NewCertPool()
|
||||||
ok := pool.AppendCertsFromPEM([]byte(root.RootCert))
|
for _, r := range roots.Roots {
|
||||||
if !ok {
|
ok := pool.AppendCertsFromPEM([]byte(r.RootCert))
|
||||||
t.Fatalf("Failed to add root CA PEM to cert pool")
|
if !ok {
|
||||||
|
t.Fatalf("Failed to add root CA PEM to cert pool")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify with intermediates from leaf CertPEM
|
// verify with intermediates from leaf CertPEM
|
||||||
|
@ -118,10 +129,12 @@ func verifyLeafCert(t *testing.T, root *structs.CARoot, leafCertPEM string) {
|
||||||
|
|
||||||
// verify with intermediates from the CARoot
|
// verify with intermediates from the CARoot
|
||||||
intermediates = x509.NewCertPool()
|
intermediates = x509.NewCertPool()
|
||||||
for _, intermediate := range root.IntermediateCerts {
|
for _, r := range roots.Roots {
|
||||||
c, err := connect.ParseCert(intermediate)
|
for _, intermediate := range r.IntermediateCerts {
|
||||||
require.NoError(t, err)
|
c, err := connect.ParseCert(intermediate)
|
||||||
intermediates.AddCert(c)
|
require.NoError(t, err)
|
||||||
|
intermediates.AddCert(c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = leaf.Verify(x509.VerifyOptions{
|
_, err = leaf.Verify(x509.VerifyOptions{
|
||||||
|
@ -628,10 +641,6 @@ func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) {
|
||||||
"Token": vault.RootToken,
|
"Token": vault.RootToken,
|
||||||
"RootPKIPath": meshRootPath,
|
"RootPKIPath": meshRootPath,
|
||||||
"IntermediatePKIPath": "pki-intermediate/",
|
"IntermediatePKIPath": "pki-intermediate/",
|
||||||
// TODO: there are failures to init the CA system if these are not set
|
|
||||||
// to the values of the already initialized CA.
|
|
||||||
"PrivateKeyType": "ec",
|
|
||||||
"PrivateKeyBits": 256,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -664,10 +673,6 @@ func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) {
|
||||||
"Token": vault.RootToken,
|
"Token": vault.RootToken,
|
||||||
"RootPKIPath": meshRootPath,
|
"RootPKIPath": meshRootPath,
|
||||||
"IntermediatePKIPath": "pki-secondary/",
|
"IntermediatePKIPath": "pki-secondary/",
|
||||||
// TODO: there are failures to init the CA system if these are not set
|
|
||||||
// to the values of the already initialized CA.
|
|
||||||
"PrivateKeyType": "ec",
|
|
||||||
"PrivateKeyBits": 256,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -727,10 +732,6 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) {
|
||||||
"Token": vault.RootToken,
|
"Token": vault.RootToken,
|
||||||
"RootPKIPath": primaryCAPath,
|
"RootPKIPath": primaryCAPath,
|
||||||
"IntermediatePKIPath": "pki-intermediate/",
|
"IntermediatePKIPath": "pki-intermediate/",
|
||||||
// TODO: there are failures to init the CA system if these are not set
|
|
||||||
// to the values of the already initialized CA.
|
|
||||||
"PrivateKeyType": "ec",
|
|
||||||
"PrivateKeyBits": 256,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -765,15 +766,12 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: renew primary leaf signing cert
|
|
||||||
// TODO: rotate root
|
|
||||||
|
|
||||||
runStep(t, "start secondary DC", func(t *testing.T) {
|
runStep(t, "start secondary DC", func(t *testing.T) {
|
||||||
joinWAN(t, serverDC2, serverDC1)
|
joinWAN(t, serverDC2, serverDC1)
|
||||||
testrpc.WaitForActiveCARoot(t, serverDC2.RPC, "dc2", nil)
|
testrpc.WaitForActiveCARoot(t, serverDC2.RPC, "dc2", nil)
|
||||||
|
|
||||||
codec := rpcClient(t, serverDC2)
|
codec := rpcClient(t, serverDC2)
|
||||||
roots := structs.IndexedCARoots{}
|
roots = structs.IndexedCARoots{}
|
||||||
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, roots.Roots, 1)
|
require.Len(t, roots.Roots, 1)
|
||||||
|
@ -788,6 +786,7 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) {
|
||||||
renewLeafSigningCert(t, serverDC1.caManager, serverDC1.caManager.primaryRenewIntermediate)
|
renewLeafSigningCert(t, serverDC1.caManager, serverDC1.caManager.primaryRenewIntermediate)
|
||||||
|
|
||||||
codec := rpcClient(t, serverDC1)
|
codec := rpcClient(t, serverDC1)
|
||||||
|
roots = structs.IndexedCARoots{}
|
||||||
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, roots.Roots, 1)
|
require.Len(t, roots.Roots, 1)
|
||||||
|
@ -809,6 +808,7 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) {
|
||||||
renewLeafSigningCert(t, serverDC2.caManager, serverDC2.caManager.secondaryRequestNewSigningCert)
|
renewLeafSigningCert(t, serverDC2.caManager, serverDC2.caManager.secondaryRequestNewSigningCert)
|
||||||
|
|
||||||
codec := rpcClient(t, serverDC2)
|
codec := rpcClient(t, serverDC2)
|
||||||
|
roots = structs.IndexedCARoots{}
|
||||||
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, roots.Roots, 1)
|
require.Len(t, roots.Roots, 1)
|
||||||
|
@ -824,6 +824,68 @@ func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) {
|
||||||
// original certs from old signing cert should still verify
|
// original certs from old signing cert should still verify
|
||||||
verifyLeafCert(t, roots.Roots[0], origLeaf)
|
verifyLeafCert(t, roots.Roots[0], origLeaf)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
runStep(t, "rotate root by changing the provider", func(t *testing.T) {
|
||||||
|
codec := rpcClient(t, serverDC1)
|
||||||
|
req := &structs.CARequest{
|
||||||
|
Op: structs.CAOpSetConfig,
|
||||||
|
Config: &structs.CAConfiguration{
|
||||||
|
Provider: "consul",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var resp error
|
||||||
|
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.ConfigurationSet", req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, resp)
|
||||||
|
|
||||||
|
roots = structs.IndexedCARoots{}
|
||||||
|
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, roots.Roots, 2)
|
||||||
|
active := roots.Active()
|
||||||
|
require.Len(t, active.IntermediateCerts, 1)
|
||||||
|
|
||||||
|
leafPEM := getLeafCert(t, codec, roots.TrustDomain, "dc1")
|
||||||
|
verifyLeafCert(t, roots.Active(), leafPEM)
|
||||||
|
|
||||||
|
// original certs from old root cert should still verify
|
||||||
|
verifyLeafCertWithRoots(t, roots, origLeaf)
|
||||||
|
})
|
||||||
|
|
||||||
|
runStep(t, "rotate to a different external root", func(t *testing.T) {
|
||||||
|
setupPrimaryCA(t, vclient, "pki-primary-2/", rootPEM)
|
||||||
|
|
||||||
|
codec := rpcClient(t, serverDC1)
|
||||||
|
req := &structs.CARequest{
|
||||||
|
Op: structs.CAOpSetConfig,
|
||||||
|
Config: &structs.CAConfiguration{
|
||||||
|
Provider: "vault",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"Address": vault.Addr,
|
||||||
|
"Token": vault.RootToken,
|
||||||
|
"RootPKIPath": "pki-primary-2/",
|
||||||
|
"IntermediatePKIPath": "pki-intermediate-2/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var resp error
|
||||||
|
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.ConfigurationSet", req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, resp)
|
||||||
|
|
||||||
|
roots = structs.IndexedCARoots{}
|
||||||
|
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, roots.Roots, 3)
|
||||||
|
active := roots.Active()
|
||||||
|
require.Len(t, active.IntermediateCerts, 2)
|
||||||
|
|
||||||
|
leafPEM := getLeafCert(t, codec, roots.TrustDomain, "dc1")
|
||||||
|
verifyLeafCert(t, roots.Active(), leafPEM)
|
||||||
|
|
||||||
|
// original certs from old root cert should still verify
|
||||||
|
verifyLeafCertWithRoots(t, roots, origLeaf)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// renewLeafSigningCert mimics RenewIntermediate. This is unfortunate, but
|
// renewLeafSigningCert mimics RenewIntermediate. This is unfortunate, but
|
||||||
|
|
Loading…
Reference in New Issue