mirror of https://github.com/status-im/consul.git
ca: examine the full chain in newCARoot
make TestNewCARoot much more strict compare the full result instead of only a few fields. add a test case with 2 and 3 certificates in the pem
This commit is contained in:
parent
71f3ae04e2
commit
42ec34d101
|
@ -135,6 +135,7 @@ type PrimaryProvider interface {
|
||||||
// the active intermediate. If multiple intermediates are needed to complete
|
// the active intermediate. If multiple intermediates are needed to complete
|
||||||
// the chain from the signing certificate back to the active root, they should
|
// the chain from the signing certificate back to the active root, they should
|
||||||
// all by bundled here.
|
// all by bundled here.
|
||||||
|
// TODO: replace with GenerateLeafSigningCert
|
||||||
GenerateIntermediate() (string, error)
|
GenerateIntermediate() (string, error)
|
||||||
|
|
||||||
// SignIntermediate will validate the CSR to ensure the trust domain in the
|
// SignIntermediate will validate the CSR to ensure the trust domain in the
|
||||||
|
@ -193,7 +194,12 @@ type SecondaryProvider interface {
|
||||||
//
|
//
|
||||||
// TODO: rename this struct
|
// TODO: rename this struct
|
||||||
type RootResult struct {
|
type RootResult struct {
|
||||||
// PEM encoded certificate that will be used as the primary CA.
|
// PEM encoded bundle of CA certificates. The first certificate must be the
|
||||||
|
// primary CA used to sign intermediates for secondary datacenters, and the
|
||||||
|
// last certificate must be the trusted CA.
|
||||||
|
//
|
||||||
|
// If there is only a single certificate in the bundle then it will be used
|
||||||
|
// as both the primary CA and the trusted CA.
|
||||||
PEM string
|
PEM string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return RootResult{}, err
|
return RootResult{}, err
|
||||||
}
|
}
|
||||||
_, err = v.client.Logical().Write(v.config.RootPKIPath+"root/generate/internal", map[string]interface{}{
|
resp, err := v.client.Logical().Write(v.config.RootPKIPath+"root/generate/internal", map[string]interface{}{
|
||||||
"common_name": connect.CACN("vault", uid, v.clusterID, v.isPrimary),
|
"common_name": connect.CACN("vault", uid, v.clusterID, v.isPrimary),
|
||||||
"uri_sans": v.spiffeID.URI().String(),
|
"uri_sans": v.spiffeID.URI().String(),
|
||||||
"key_type": v.config.PrivateKeyType,
|
"key_type": v.config.PrivateKeyType,
|
||||||
|
@ -288,12 +288,10 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return RootResult{}, err
|
return RootResult{}, err
|
||||||
}
|
}
|
||||||
|
var ok bool
|
||||||
// retrieve the newly generated cert so that we can return it
|
rootPEM, ok = resp.Data["certificate"].(string)
|
||||||
// TODO: is this already available from the Local().Write() above?
|
if !ok {
|
||||||
rootPEM, err = v.getCA(v.config.RootPKIPath)
|
return RootResult{}, fmt.Errorf("unexpected response from Vault: %v", resp.Data["certificate"])
|
||||||
if err != nil {
|
|
||||||
return RootResult{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -302,7 +300,18 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RootResult{PEM: rootPEM}, nil
|
rootChain, err := v.getCAChain(v.config.RootPKIPath)
|
||||||
|
if err != nil {
|
||||||
|
return RootResult{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for a bug in the Vault PKI API.
|
||||||
|
// See https://github.com/hashicorp/vault/issues/13489
|
||||||
|
if rootChain == "" {
|
||||||
|
rootChain = rootPEM
|
||||||
|
}
|
||||||
|
|
||||||
|
return RootResult{PEM: rootChain}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateIntermediateCSR creates a private key and generates a CSR
|
// GenerateIntermediateCSR creates a private key and generates a CSR
|
||||||
|
@ -467,6 +476,29 @@ func (v *VaultProvider) getCA(path string) (string, error) {
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor to remove duplication with getCA
|
||||||
|
func (v *VaultProvider) getCAChain(path string) (string, error) {
|
||||||
|
req := v.client.NewRequest("GET", "/v1/"+path+"/ca_chain")
|
||||||
|
resp, err := v.client.RawRequest(req)
|
||||||
|
if resp != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||||
|
return "", ErrBackendNotMounted
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := EnsureTrailingNewline(string(raw))
|
||||||
|
return root, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GenerateIntermediate mounts the configured intermediate PKI backend if
|
// GenerateIntermediate mounts the configured intermediate PKI backend if
|
||||||
// necessary, then generates and signs a new CA CSR using the root PKI backend
|
// necessary, then generates and signs a new CA CSR using the root PKI backend
|
||||||
// and updates the intermediate backend to use that new certificate.
|
// and updates the intermediate backend to use that new certificate.
|
||||||
|
@ -571,6 +603,7 @@ func (v *VaultProvider) SignIntermediate(csr *x509.CertificateRequest) (string,
|
||||||
// CrossSignCA takes a CA certificate and cross-signs it to form a trust chain
|
// CrossSignCA takes a CA certificate and cross-signs it to form a trust chain
|
||||||
// back to our active root.
|
// back to our active root.
|
||||||
func (v *VaultProvider) CrossSignCA(cert *x509.Certificate) (string, error) {
|
func (v *VaultProvider) CrossSignCA(cert *x509.Certificate) (string, error) {
|
||||||
|
// TODO: is this necessary? Doesn't vault check this for us?
|
||||||
rootPEM, err := v.getCA(v.config.RootPKIPath)
|
rootPEM, err := v.getCA(v.config.RootPKIPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -20,11 +20,11 @@ const (
|
||||||
DefaultIntermediateCertTTL = 24 * 365 * time.Hour
|
DefaultIntermediateCertTTL = 24 * 365 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
func pemEncodeKey(key []byte, blockType string) (string, error) {
|
func pemEncode(value []byte, blockType string) (string, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
if err := pem.Encode(&buf, &pem.Block{Type: blockType, Bytes: key}); err != nil {
|
if err := pem.Encode(&buf, &pem.Block{Type: blockType, Bytes: value}); err != nil {
|
||||||
return "", fmt.Errorf("error encoding private key: %s", err)
|
return "", fmt.Errorf("error encoding value %v: %s", blockType, err)
|
||||||
}
|
}
|
||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ func generateRSAKey(keyBits int) (crypto.Signer, string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bs := x509.MarshalPKCS1PrivateKey(pk)
|
bs := x509.MarshalPKCS1PrivateKey(pk)
|
||||||
pemBlock, err := pemEncodeKey(bs, "RSA PRIVATE KEY")
|
pemBlock, err := pemEncode(bs, "RSA PRIVATE KEY")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func generateECDSAKey(keyBits int) (crypto.Signer, string, error) {
|
||||||
return nil, "", fmt.Errorf("error marshaling ECDSA private key: %s", err)
|
return nil, "", fmt.Errorf("error marshaling ECDSA private key: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pemBlock, err := pemEncodeKey(bs, "EC PRIVATE KEY")
|
pemBlock, err := pemEncode(bs, "EC PRIVATE KEY")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,21 @@ func ParseLeafCerts(pemValue string) (*x509.Certificate, *x509.CertPool, error)
|
||||||
return leaf, intermediates, nil
|
return leaf, intermediates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CertSubjects can be used in debugging to return the subject of each
|
||||||
|
// certificate in the PEM bundle. Each subject is separated by a newline.
|
||||||
|
func CertSubjects(pem string) string {
|
||||||
|
certs, err := parseCerts(pem)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
var buf strings.Builder
|
||||||
|
for _, cert := range certs {
|
||||||
|
buf.WriteString(cert.Subject.String())
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
// ParseCerts parses the all x509 certificates from a PEM-encoded value.
|
// ParseCerts parses the all x509 certificates from a PEM-encoded value.
|
||||||
// The first returned cert is a leaf cert and any other ones are intermediates.
|
// The first returned cert is a leaf cert and any other ones are intermediates.
|
||||||
//
|
//
|
||||||
|
@ -90,21 +105,10 @@ func parseCerts(pemValue string) ([]*x509.Certificate, error) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateCertFingerprint parses the x509 certificate from a PEM-encoded value
|
// CalculateCertFingerprint calculates the SHA-1 fingerprint from the cert bytes.
|
||||||
// and calculates the SHA-1 fingerprint.
|
func CalculateCertFingerprint(cert []byte) string {
|
||||||
func CalculateCertFingerprint(pemValue string) (string, error) {
|
hash := sha1.Sum(cert)
|
||||||
// The _ result below is not an error but the remaining PEM bytes.
|
return HexString(hash[:])
|
||||||
block, _ := pem.Decode([]byte(pemValue))
|
|
||||||
if block == nil {
|
|
||||||
return "", fmt.Errorf("no PEM-encoded data found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if block.Type != "CERTIFICATE" {
|
|
||||||
return "", fmt.Errorf("first PEM-block should be CERTIFICATE type")
|
|
||||||
}
|
|
||||||
|
|
||||||
hash := sha1.Sum(block.Bytes)
|
|
||||||
return HexString(hash[:]), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseSigner parses a crypto.Signer from a PEM-encoded key. The private key
|
// ParseSigner parses a crypto.Signer from a PEM-encoded key. The private key
|
||||||
|
|
|
@ -112,10 +112,7 @@ func testCA(t testing.T, xc *structs.CARoot, keyType string, keyBits int, ttl ti
|
||||||
t.Fatalf("error encoding private key: %s", err)
|
t.Fatalf("error encoding private key: %s", err)
|
||||||
}
|
}
|
||||||
result.RootCert = buf.String()
|
result.RootCert = buf.String()
|
||||||
result.ID, err = CalculateCertFingerprint(result.RootCert)
|
result.ID = CalculateCertFingerprint(bs)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error generating CA ID fingerprint: %s", err)
|
|
||||||
}
|
|
||||||
result.SerialNumber = uint64(sn.Int64())
|
result.SerialNumber = uint64(sn.Int64())
|
||||||
result.NotBefore = template.NotBefore.UTC()
|
result.NotBefore = template.NotBefore.UTC()
|
||||||
result.NotAfter = template.NotAfter.UTC()
|
result.NotAfter = template.NotAfter.UTC()
|
||||||
|
|
|
@ -253,28 +253,24 @@ func (c *CAManager) initializeCAConfig() (*structs.CAConfiguration, error) {
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseCARoot returns a filled-in structs.CARoot from a raw PEM value.
|
// newCARoot returns a filled-in structs.CARoot from a raw PEM value.
|
||||||
func parseCARoot(pemValue, provider, clusterID string) (*structs.CARoot, error) {
|
func newCARoot(pemValue, provider, clusterID string) (*structs.CARoot, error) {
|
||||||
id, err := connect.CalculateCertFingerprint(pemValue)
|
primaryCert, err := connect.ParseCert(pemValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing root fingerprint: %v", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
rootCert, err := connect.ParseCert(pemValue)
|
keyType, keyBits, err := connect.KeyInfoFromCert(primaryCert)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing root cert: %v", err)
|
|
||||||
}
|
|
||||||
keyType, keyBits, err := connect.KeyInfoFromCert(rootCert)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error extracting root key info: %v", err)
|
return nil, fmt.Errorf("error extracting root key info: %v", err)
|
||||||
}
|
}
|
||||||
return &structs.CARoot{
|
return &structs.CARoot{
|
||||||
ID: id,
|
ID: connect.CalculateCertFingerprint(primaryCert.Raw),
|
||||||
Name: fmt.Sprintf("%s CA Root Cert", strings.Title(provider)),
|
Name: fmt.Sprintf("%s CA Primary Cert", strings.Title(provider)),
|
||||||
SerialNumber: rootCert.SerialNumber.Uint64(),
|
SerialNumber: primaryCert.SerialNumber.Uint64(),
|
||||||
SigningKeyID: connect.EncodeSigningKeyID(rootCert.SubjectKeyId),
|
SigningKeyID: connect.EncodeSigningKeyID(primaryCert.SubjectKeyId),
|
||||||
ExternalTrustDomain: clusterID,
|
ExternalTrustDomain: clusterID,
|
||||||
NotBefore: rootCert.NotBefore,
|
NotBefore: primaryCert.NotBefore,
|
||||||
NotAfter: rootCert.NotAfter,
|
NotAfter: primaryCert.NotAfter,
|
||||||
RootCert: pemValue,
|
RootCert: pemValue,
|
||||||
PrivateKeyType: keyType,
|
PrivateKeyType: keyType,
|
||||||
PrivateKeyBits: keyBits,
|
PrivateKeyBits: keyBits,
|
||||||
|
@ -435,7 +431,7 @@ func (c *CAManager) secondaryInitialize(provider ca.Provider, conf *structs.CACo
|
||||||
}
|
}
|
||||||
var roots structs.IndexedCARoots
|
var roots structs.IndexedCARoots
|
||||||
if err := c.delegate.forwardDC("ConnectCA.Roots", c.serverConf.PrimaryDatacenter, &args, &roots); err != nil {
|
if err := c.delegate.forwardDC("ConnectCA.Roots", c.serverConf.PrimaryDatacenter, &args, &roots); err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to get CA roots from primary DC: %w", err)
|
||||||
}
|
}
|
||||||
c.secondarySetPrimaryRoots(roots)
|
c.secondarySetPrimaryRoots(roots)
|
||||||
|
|
||||||
|
@ -487,12 +483,12 @@ func (c *CAManager) primaryInitialize(provider ca.Provider, conf *structs.CAConf
|
||||||
return fmt.Errorf("error generating CA root certificate: %v", err)
|
return fmt.Errorf("error generating CA root certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCA, err := parseCARoot(root.PEM, conf.Provider, conf.ClusterID)
|
rootCA, err := newCARoot(root.PEM, conf.Provider, conf.ClusterID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also create the intermediate CA, which is the one that actually signs leaf certs
|
// TODO: delete this
|
||||||
interPEM, err := provider.GenerateIntermediate()
|
interPEM, err := provider.GenerateIntermediate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error generating intermediate cert: %v", err)
|
return fmt.Errorf("error generating intermediate cert: %v", err)
|
||||||
|
@ -887,7 +883,7 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C
|
||||||
}
|
}
|
||||||
|
|
||||||
newRootPEM := providerRoot.PEM
|
newRootPEM := providerRoot.PEM
|
||||||
newActiveRoot, err := parseCARoot(newRootPEM, args.Config.Provider, args.Config.ClusterID)
|
newActiveRoot, err := newCARoot(newRootPEM, args.Config.Provider, args.Config.ClusterID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -940,7 +936,7 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C
|
||||||
// get a cross-signed certificate.
|
// get a cross-signed certificate.
|
||||||
// 3. Take the active root for the new provider and append the intermediate from step 2
|
// 3. Take the active root for the new provider and append the intermediate from step 2
|
||||||
// to its list of intermediates.
|
// to its list of intermediates.
|
||||||
// TODO: this cert is already parsed once in parseCARoot, could we remove the second parse?
|
// TODO: this cert is already parsed once in newCARoot, could we remove the second parse?
|
||||||
newRoot, err := connect.ParseCert(newRootPEM)
|
newRoot, err := connect.ParseCert(newRootPEM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -980,6 +976,7 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: delete this
|
||||||
intermediate, err := newProvider.GenerateIntermediate()
|
intermediate, err := newProvider.GenerateIntermediate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -618,7 +618,7 @@ func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) {
|
||||||
generateExternalRootCA(t, vclient)
|
generateExternalRootCA(t, vclient)
|
||||||
|
|
||||||
meshRootPath := "pki-root"
|
meshRootPath := "pki-root"
|
||||||
primaryCert := setupPrimaryCA(t, vclient, meshRootPath)
|
primaryCert := setupPrimaryCA(t, vclient, meshRootPath, "")
|
||||||
|
|
||||||
_, s1 := testServerWithConfig(t, func(c *Config) {
|
_, s1 := testServerWithConfig(t, func(c *Config) {
|
||||||
c.CAConfig = &structs.CAConfiguration{
|
c.CAConfig = &structs.CAConfiguration{
|
||||||
|
@ -635,7 +635,6 @@ func TestCAManager_Initialize_Vault_WithIntermediateAsPrimaryCA(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
defer s1.Shutdown()
|
|
||||||
|
|
||||||
runStep(t, "check primary DC", func(t *testing.T) {
|
runStep(t, "check primary DC", func(t *testing.T) {
|
||||||
testrpc.WaitForTestAgent(t, s1.RPC, "dc1")
|
testrpc.WaitForTestAgent(t, s1.RPC, "dc1")
|
||||||
|
@ -704,10 +703,90 @@ func getLeafCert(t *testing.T, codec rpc.ClientCodec, trustDomain string, dc str
|
||||||
cert := structs.IssuedCert{}
|
cert := structs.IssuedCert{}
|
||||||
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Sign", &req, &cert)
|
err = msgpackrpc.CallWithCodec(codec, "ConnectCA.Sign", &req, &cert)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return cert.CertPEM
|
return cert.CertPEM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCAManager_Initialize_Vault_WithExternalTrustedCA(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
ca.SkipIfVaultNotPresent(t)
|
||||||
|
|
||||||
|
vault := ca.NewTestVaultServer(t)
|
||||||
|
vclient := vault.Client()
|
||||||
|
rootPEM := generateExternalRootCA(t, vclient)
|
||||||
|
|
||||||
|
primaryCAPath := "pki-primary"
|
||||||
|
primaryCert := setupPrimaryCA(t, vclient, primaryCAPath, rootPEM)
|
||||||
|
|
||||||
|
_, s1 := testServerWithConfig(t, func(c *Config) {
|
||||||
|
c.CAConfig = &structs.CAConfiguration{
|
||||||
|
Provider: "vault",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"Address": vault.Addr,
|
||||||
|
"Token": vault.RootToken,
|
||||||
|
"RootPKIPath": primaryCAPath,
|
||||||
|
"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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
runStep(t, "check primary DC", func(t *testing.T) {
|
||||||
|
testrpc.WaitForTestAgent(t, s1.RPC, "dc1")
|
||||||
|
|
||||||
|
codec := rpcClient(t, s1)
|
||||||
|
roots := structs.IndexedCARoots{}
|
||||||
|
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, roots.Roots, 1)
|
||||||
|
require.Equal(t, primaryCert, roots.Roots[0].RootCert)
|
||||||
|
|
||||||
|
leafCertPEM := getLeafCert(t, codec, roots.TrustDomain, "dc1")
|
||||||
|
verifyLeafCert(t, roots.Roots[0], leafCertPEM)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: renew primary leaf signing cert
|
||||||
|
// TODO: rotate root
|
||||||
|
|
||||||
|
runStep(t, "run secondary DC", func(t *testing.T) {
|
||||||
|
_, sDC2 := testServerWithConfig(t, func(c *Config) {
|
||||||
|
c.Datacenter = "dc2"
|
||||||
|
c.PrimaryDatacenter = "dc1"
|
||||||
|
c.CAConfig = &structs.CAConfiguration{
|
||||||
|
Provider: "vault",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"Address": vault.Addr,
|
||||||
|
"Token": vault.RootToken,
|
||||||
|
"RootPKIPath": primaryCAPath,
|
||||||
|
"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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer sDC2.Shutdown()
|
||||||
|
joinWAN(t, sDC2, s1)
|
||||||
|
testrpc.WaitForActiveCARoot(t, sDC2.RPC, "dc2", nil)
|
||||||
|
|
||||||
|
codec := rpcClient(t, sDC2)
|
||||||
|
roots := structs.IndexedCARoots{}
|
||||||
|
err := msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", &structs.DCSpecificRequest{}, &roots)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, roots.Roots, 1)
|
||||||
|
|
||||||
|
leafCertPEM := getLeafCert(t, codec, roots.TrustDomain, "dc2")
|
||||||
|
verifyLeafCert(t, roots.Roots[0], leafCertPEM)
|
||||||
|
|
||||||
|
// TODO: renew secondary leaf signing cert
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func generateExternalRootCA(t *testing.T, client *vaultapi.Client) string {
|
func generateExternalRootCA(t *testing.T, client *vaultapi.Client) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
err := client.Sys().Mount("corp", &vaultapi.MountInput{
|
err := client.Sys().Mount("corp", &vaultapi.MountInput{
|
||||||
|
@ -725,10 +804,10 @@ func generateExternalRootCA(t *testing.T, client *vaultapi.Client) string {
|
||||||
"ttl": "2400h",
|
"ttl": "2400h",
|
||||||
})
|
})
|
||||||
require.NoError(t, err, "failed to generate root")
|
require.NoError(t, err, "failed to generate root")
|
||||||
return resp.Data["certificate"].(string)
|
return ca.EnsureTrailingNewline(resp.Data["certificate"].(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupPrimaryCA(t *testing.T, client *vaultapi.Client, path string) string {
|
func setupPrimaryCA(t *testing.T, client *vaultapi.Client, path string, rootPEM string) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
err := client.Sys().Mount(path, &vaultapi.MountInput{
|
err := client.Sys().Mount(path, &vaultapi.MountInput{
|
||||||
Type: "pki",
|
Type: "pki",
|
||||||
|
|
|
@ -15,11 +15,13 @@ import (
|
||||||
msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc"
|
msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc"
|
||||||
uuid "github.com/hashicorp/go-uuid"
|
uuid "github.com/hashicorp/go-uuid"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/connect"
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
"github.com/hashicorp/consul/agent/connect/ca"
|
"github.com/hashicorp/consul/agent/connect/ca"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
"github.com/hashicorp/consul/agent/token"
|
"github.com/hashicorp/consul/agent/token"
|
||||||
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
"github.com/hashicorp/consul/sdk/testutil/retry"
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
||||||
"github.com/hashicorp/consul/testrpc"
|
"github.com/hashicorp/consul/testrpc"
|
||||||
)
|
)
|
||||||
|
@ -1246,74 +1248,122 @@ func TestConnectCA_ConfigurationSet_PersistsRoots(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseCARoot(t *testing.T) {
|
func TestNewCARoot(t *testing.T) {
|
||||||
type test struct {
|
type testCase struct {
|
||||||
name string
|
name string
|
||||||
pem string
|
pem string
|
||||||
wantSerial uint64
|
expected *structs.CARoot
|
||||||
wantSigningKeyID string
|
expectedErr string
|
||||||
wantKeyType string
|
|
||||||
wantKeyBits int
|
|
||||||
wantErr bool
|
|
||||||
}
|
}
|
||||||
// Test certs generated with
|
|
||||||
// go run connect/certgen/certgen.go -out-dir /tmp/connect-certs -key-type ec -key-bits 384
|
run := func(t *testing.T, tc testCase) {
|
||||||
// for various key types. This does limit the exposure to formats that might
|
root, err := newCARoot(tc.pem, "provider-name", "cluster-id")
|
||||||
// exist in external certificates which can be used as Connect CAs.
|
if tc.expectedErr != "" {
|
||||||
// Specifically many other certs will have serial numbers that don't fit into
|
testutil.RequireErrorContains(t, err, tc.expectedErr)
|
||||||
// 64 bits but for reasons we truncate down to 64 bits which means our
|
|
||||||
// `SerialNumber` will not match the one reported by openssl. We should
|
|
||||||
// probably fix that at some point as it seems like a big footgun but it would
|
|
||||||
// be a breaking API change to change the type to not be a JSON number and
|
|
||||||
// JSON numbers don't even support the full range of a uint64...
|
|
||||||
tests := []test{
|
|
||||||
{"no cert", "", 0, "", "", 0, true},
|
|
||||||
{
|
|
||||||
name: "default cert",
|
|
||||||
// Watchout for indentations they will break PEM format
|
|
||||||
pem: readTestData(t, "cert-with-ec-256-key.pem"),
|
|
||||||
// Based on `openssl x509 -noout -text` report from the cert
|
|
||||||
wantSerial: 8341954965092507701,
|
|
||||||
wantSigningKeyID: "97:4D:17:81:64:F8:B4:AF:05:E8:6C:79:C5:40:3B:0E:3E:8B:C0:AE:38:51:54:8A:2F:05:DB:E3:E8:E4:24:EC",
|
|
||||||
wantKeyType: "ec",
|
|
||||||
wantKeyBits: 256,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ec 384 cert",
|
|
||||||
// Watchout for indentations they will break PEM format
|
|
||||||
pem: readTestData(t, "cert-with-ec-384-key.pem"),
|
|
||||||
// Based on `openssl x509 -noout -text` report from the cert
|
|
||||||
wantSerial: 2935109425518279965,
|
|
||||||
wantSigningKeyID: "0B:A0:88:9B:DC:95:31:51:2E:3D:D4:F9:42:D0:6A:A0:62:46:82:D2:7C:22:E7:29:A9:AA:E8:A5:8C:CF:C7:42",
|
|
||||||
wantKeyType: "ec",
|
|
||||||
wantKeyBits: 384,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "rsa 4096 cert",
|
|
||||||
// Watchout for indentations they will break PEM format
|
|
||||||
pem: readTestData(t, "cert-with-rsa-4096-key.pem"),
|
|
||||||
// Based on `openssl x509 -noout -text` report from the cert
|
|
||||||
wantSerial: 5186695743100577491,
|
|
||||||
wantSigningKeyID: "92:FA:CC:97:57:1E:31:84:A2:33:DD:9B:6A:A8:7C:FC:BE:E2:94:CA:AC:B3:33:17:39:3B:B8:67:9B:DC:C1:08",
|
|
||||||
wantKeyType: "rsa",
|
|
||||||
wantKeyBits: 4096,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
root, err := parseCARoot(tt.pem, "consul", "cluster")
|
|
||||||
if tt.wantErr {
|
|
||||||
require.Error(t, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tt.wantSerial, root.SerialNumber)
|
assert.DeepEqual(t, root, tc.expected)
|
||||||
require.Equal(t, strings.ToLower(tt.wantSigningKeyID), root.SigningKeyID)
|
}
|
||||||
require.Equal(t, tt.wantKeyType, root.PrivateKeyType)
|
|
||||||
require.Equal(t, tt.wantKeyBits, root.PrivateKeyBits)
|
// Test certs can be generated with
|
||||||
|
// go run connect/certgen/certgen.go -out-dir /tmp/connect-certs -key-type ec -key-bits 384
|
||||||
|
// serial generated with:
|
||||||
|
// openssl x509 -noout -text
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
name: "no cert",
|
||||||
|
expectedErr: "no PEM-encoded data found",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "type=ec bits=256",
|
||||||
|
pem: readTestData(t, "cert-with-ec-256-key.pem"),
|
||||||
|
expected: &structs.CARoot{
|
||||||
|
ID: "c9:1b:24:e0:89:63:1a:ba:22:01:f4:cf:bc:f1:c0:36:b2:6b:6c:3d",
|
||||||
|
Name: "Provider-Name CA Primary Cert",
|
||||||
|
SerialNumber: 8341954965092507701,
|
||||||
|
SigningKeyID: "97:4d:17:81:64:f8:b4:af:05:e8:6c:79:c5:40:3b:0e:3e:8b:c0:ae:38:51:54:8a:2f:05:db:e3:e8:e4:24:ec",
|
||||||
|
ExternalTrustDomain: "cluster-id",
|
||||||
|
NotBefore: time.Date(2019, 10, 17, 11, 46, 29, 0, time.UTC),
|
||||||
|
NotAfter: time.Date(2029, 10, 17, 11, 46, 29, 0, time.UTC),
|
||||||
|
RootCert: readTestData(t, "cert-with-ec-256-key.pem"),
|
||||||
|
Active: true,
|
||||||
|
PrivateKeyType: "ec",
|
||||||
|
PrivateKeyBits: 256,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "type=ec bits=384",
|
||||||
|
pem: readTestData(t, "cert-with-ec-384-key.pem"),
|
||||||
|
expected: &structs.CARoot{
|
||||||
|
ID: "29:69:c4:0f:aa:8f:bd:07:31:0d:51:3b:45:62:3d:c0:b2:fc:c6:3f",
|
||||||
|
Name: "Provider-Name CA Primary Cert",
|
||||||
|
SerialNumber: 2935109425518279965,
|
||||||
|
SigningKeyID: "0b:a0:88:9b:dc:95:31:51:2e:3d:d4:f9:42:d0:6a:a0:62:46:82:d2:7c:22:e7:29:a9:aa:e8:a5:8c:cf:c7:42",
|
||||||
|
ExternalTrustDomain: "cluster-id",
|
||||||
|
NotBefore: time.Date(2019, 10, 17, 11, 55, 18, 0, time.UTC),
|
||||||
|
NotAfter: time.Date(2029, 10, 17, 11, 55, 18, 0, time.UTC),
|
||||||
|
RootCert: readTestData(t, "cert-with-ec-384-key.pem"),
|
||||||
|
Active: true,
|
||||||
|
PrivateKeyType: "ec",
|
||||||
|
PrivateKeyBits: 384,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "type=rsa bits=4096",
|
||||||
|
pem: readTestData(t, "cert-with-rsa-4096-key.pem"),
|
||||||
|
expected: &structs.CARoot{
|
||||||
|
ID: "3a:6a:e3:e2:2d:44:85:5a:e9:44:3b:ef:d2:90:78:83:7f:61:a2:84",
|
||||||
|
Name: "Provider-Name CA Primary Cert",
|
||||||
|
SerialNumber: 5186695743100577491,
|
||||||
|
SigningKeyID: "92:fa:cc:97:57:1e:31:84:a2:33:dd:9b:6a:a8:7c:fc:be:e2:94:ca:ac:b3:33:17:39:3b:b8:67:9b:dc:c1:08",
|
||||||
|
ExternalTrustDomain: "cluster-id",
|
||||||
|
NotBefore: time.Date(2019, 10, 17, 11, 53, 15, 0, time.UTC),
|
||||||
|
NotAfter: time.Date(2029, 10, 17, 11, 53, 15, 0, time.UTC),
|
||||||
|
RootCert: readTestData(t, "cert-with-rsa-4096-key.pem"),
|
||||||
|
Active: true,
|
||||||
|
PrivateKeyType: "rsa",
|
||||||
|
PrivateKeyBits: 4096,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two certs in pem",
|
||||||
|
pem: readTestData(t, "pem-with-two-certs.pem"),
|
||||||
|
expected: &structs.CARoot{
|
||||||
|
ID: "42:43:10:1f:71:6b:21:21:d1:10:49:d1:f0:41:78:8c:0a:77:ef:c0",
|
||||||
|
Name: "Provider-Name CA Primary Cert",
|
||||||
|
SerialNumber: 17692800288680335732,
|
||||||
|
SigningKeyID: "9d:5c:27:43:ce:58:7b:ca:3e:7d:c4:fb:b6:2e:b7:13:e9:a1:68:3e",
|
||||||
|
ExternalTrustDomain: "cluster-id",
|
||||||
|
NotBefore: time.Date(2022, 1, 5, 23, 22, 12, 0, time.UTC),
|
||||||
|
NotAfter: time.Date(2022, 4, 7, 15, 22, 42, 0, time.UTC),
|
||||||
|
RootCert: readTestData(t, "pem-with-two-certs.pem"),
|
||||||
|
Active: true,
|
||||||
|
PrivateKeyType: "ec",
|
||||||
|
PrivateKeyBits: 256,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "three certs in pem",
|
||||||
|
pem: readTestData(t, "pem-with-three-certs.pem"),
|
||||||
|
expected: &structs.CARoot{
|
||||||
|
ID: "42:43:10:1f:71:6b:21:21:d1:10:49:d1:f0:41:78:8c:0a:77:ef:c0",
|
||||||
|
Name: "Provider-Name CA Primary Cert",
|
||||||
|
SerialNumber: 17692800288680335732,
|
||||||
|
SigningKeyID: "9d:5c:27:43:ce:58:7b:ca:3e:7d:c4:fb:b6:2e:b7:13:e9:a1:68:3e",
|
||||||
|
ExternalTrustDomain: "cluster-id",
|
||||||
|
NotBefore: time.Date(2022, 1, 5, 23, 22, 12, 0, time.UTC),
|
||||||
|
NotAfter: time.Date(2022, 4, 7, 15, 22, 42, 0, time.UTC),
|
||||||
|
RootCert: readTestData(t, "pem-with-three-certs.pem"),
|
||||||
|
Active: true,
|
||||||
|
PrivateKeyType: "ec",
|
||||||
|
PrivateKeyBits: 256,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
run(t, tc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICUjCCATqgAwIBAgIUQjOIDzaM7bGW8bU69Yl0H0C4WXQwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwFzEVMBMGA1UEAxMMY29ycG9yYXRlIENBMB4XDTIyMDEwNTIzMjIxMloXDTIy
|
||||||
|
MDQwNzE1MjI0MlowFTETMBEGA1UEAxMKcHJpbWFyeSBDQTBZMBMGByqGSM49AgEG
|
||||||
|
CCqGSM49AwEHA0IABEIcOmVSobge9pLDGh6rfyFg2+ilTFmo2ICv5vrgUfIZhi8O
|
||||||
|
fwYz5WGb7qBPRdMw9kP8BWH/lCrn2W3Ax3x2E+2jYzBhMA4GA1UdDwEB/wQEAwIB
|
||||||
|
BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSdXCdDzlh7yj59xPu2LrcT6aFo
|
||||||
|
PjAfBgNVHSMEGDAWgBS+x+IFMFb+hCJy1OQzcdzJuwDVhDANBgkqhkiG9w0BAQsF
|
||||||
|
AAOCAQEAWWBBoygbjUEtoueGuC+jHAlr+VOBwiQPJLQA+xtbCvWSn8yIx/M1RyhY
|
||||||
|
0/6WLMzhYA1lQAIze8CgKzqoGXXIcHif3PRZ3mRUMNdV/qGUv0oHZBzTKZVySOIm
|
||||||
|
MLIoq7WvyVdVNxyvRalhHxiQA1Hrh+zQKjXhVPM6dpG0duTNYit9kJCCeNDzRjWc
|
||||||
|
a/GgFyeeYMTheU3eBR6Vp2A8hy2h5xw82ul8YLwX0bCtcP12XAUzj3jFqwt6RLxW
|
||||||
|
Wc7rvsLfgimEfulQwo2WLPWZw8bJdnPvNcUFX8f2Zvqy0Jg6fELnxO+AdHnAnI9J
|
||||||
|
WtJr0ImA95Hw8gGTzmXOddYVGHuGLA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDHzCCAgegAwIBAgIUDaEOI5nsEt9abNBbJibbQt+VZQIwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwFzEVMBMGA1UEAxMMY29ycG9yYXRlIENBMB4XDTIyMDEwNTIzMjIxMloXDTIy
|
||||||
|
MDQxNTIzMjI0MlowFzEVMBMGA1UEAxMMY29ycG9yYXRlIENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAut/Gbr3MvypzEmRDTl7HGaSoVIydNEZNPqDD
|
||||||
|
jh1lqMFywB4DujTmkWLYcPJJ0RTT2NsSakteti/e1DHCuBSU0t3Q3K1paTh8aVLx
|
||||||
|
eK0IKNlCWqX5d1aYzCNZsRjJuQgPX6p/xcNGS+RS27jmRWPpvm6n1JfMvYRa7fF+
|
||||||
|
HnKhGNO+hDbhkQO4s0V1U+unNhshKDhTW3mBLmAEb2OHLOEaUZtYSbqr1E9tYXgU
|
||||||
|
DiYRkeWUpQXJ6pE91fmcaZFG0SxkqWnhe7GUa6wbb/vROWph4A1ZVHympBtOYwoJ
|
||||||
|
eibcJjBZLrugZdix8kl8NDI7SuIM/P0x0m9WkNfhJ9vSgQXlaQIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUvsfiBTBW
|
||||||
|
/oQictTkM3HcybsA1YQwHwYDVR0jBBgwFoAUvsfiBTBW/oQictTkM3HcybsA1YQw
|
||||||
|
DQYJKoZIhvcNAQELBQADggEBALUJWitOV4xAvfNB8Z20AQ+/hdXkWVgj1VBbd++v
|
||||||
|
+X88q1TnueKAExU5o87MCjh9jMxalZqSVN9MUbQ4Xa+tmkjayizdpFaw6TbbaMIB
|
||||||
|
Tgqq5ATXMnOdZd46QC764Po9R9+k9hk4dNIr5gk1ifXZDMy/7jSOVARvpwzr0cTx
|
||||||
|
flRCTgZbcK10freoU7a74/YjEpG0wggGlR4aRWfm90Im9JM3aI55zAYQFzduf56c
|
||||||
|
HXJDLgBtbOx/ceqVrkPdvYwP9Q34tKAMiheQ0G3tTxP3Xc87gh4UEDV02oHhcbqw
|
||||||
|
WSm+8zTfGUlchowPRdqKE66urWTep+BA9c8zUqDdoq5lE9s=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICGTCCAZ+gAwIBAgIIJhC6ZZyZ/lQwCgYIKoZIzj0EAwMwFDESMBAGA1UEAxMJ
|
||||||
|
VGVzdCBDQSAxMB4XDTIyMDEwNTIzNDMyNVoXDTMyMDEwNTIzNDMyNVowFDESMBAG
|
||||||
|
A1UEAxMJVGVzdCBDQSAxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETEyAhuLLOcxy
|
||||||
|
z2UHI7ePcB5AXL1o6mLwVfzyeaGfqUevzrFcLQ7WPiypZJW1KhOW5Q2bRgcjE8y3
|
||||||
|
fN+B8D+KT4fPtaRLtUVX6aZ0LCROFdgWjVo2DCvCq5VQnCGjW8r0o4G9MIG6MA4G
|
||||||
|
A1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBU/reewmUW
|
||||||
|
iduB8xxfW5clyUmrMewrWwtJuWPA/tFvTTArBgNVHSMEJDAigCBU/reewmUWiduB
|
||||||
|
8xxfW5clyUmrMewrWwtJuWPA/tFvTTA/BgNVHREEODA2hjRzcGlmZmU6Ly8xMTEx
|
||||||
|
MTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqGSM49
|
||||||
|
BAMDA2gAMGUCMA4V/Iemelne4ZB+0glmxoKV6OPQ64oKkkrcy+vo1t1RZ+7jntRx
|
||||||
|
mxAnY3S2m35boQIxAOARpY+qfR3U3JM+vMW9KO0/KqM+y1/uvIaOA0bQex2w8bfN
|
||||||
|
V+QjFUDmjTT1dLpc7A==
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,34 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICUjCCATqgAwIBAgIUQjOIDzaM7bGW8bU69Yl0H0C4WXQwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwFzEVMBMGA1UEAxMMY29ycG9yYXRlIENBMB4XDTIyMDEwNTIzMjIxMloXDTIy
|
||||||
|
MDQwNzE1MjI0MlowFTETMBEGA1UEAxMKcHJpbWFyeSBDQTBZMBMGByqGSM49AgEG
|
||||||
|
CCqGSM49AwEHA0IABEIcOmVSobge9pLDGh6rfyFg2+ilTFmo2ICv5vrgUfIZhi8O
|
||||||
|
fwYz5WGb7qBPRdMw9kP8BWH/lCrn2W3Ax3x2E+2jYzBhMA4GA1UdDwEB/wQEAwIB
|
||||||
|
BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSdXCdDzlh7yj59xPu2LrcT6aFo
|
||||||
|
PjAfBgNVHSMEGDAWgBS+x+IFMFb+hCJy1OQzcdzJuwDVhDANBgkqhkiG9w0BAQsF
|
||||||
|
AAOCAQEAWWBBoygbjUEtoueGuC+jHAlr+VOBwiQPJLQA+xtbCvWSn8yIx/M1RyhY
|
||||||
|
0/6WLMzhYA1lQAIze8CgKzqoGXXIcHif3PRZ3mRUMNdV/qGUv0oHZBzTKZVySOIm
|
||||||
|
MLIoq7WvyVdVNxyvRalhHxiQA1Hrh+zQKjXhVPM6dpG0duTNYit9kJCCeNDzRjWc
|
||||||
|
a/GgFyeeYMTheU3eBR6Vp2A8hy2h5xw82ul8YLwX0bCtcP12XAUzj3jFqwt6RLxW
|
||||||
|
Wc7rvsLfgimEfulQwo2WLPWZw8bJdnPvNcUFX8f2Zvqy0Jg6fELnxO+AdHnAnI9J
|
||||||
|
WtJr0ImA95Hw8gGTzmXOddYVGHuGLA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDHzCCAgegAwIBAgIUDaEOI5nsEt9abNBbJibbQt+VZQIwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwFzEVMBMGA1UEAxMMY29ycG9yYXRlIENBMB4XDTIyMDEwNTIzMjIxMloXDTIy
|
||||||
|
MDQxNTIzMjI0MlowFzEVMBMGA1UEAxMMY29ycG9yYXRlIENBMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAut/Gbr3MvypzEmRDTl7HGaSoVIydNEZNPqDD
|
||||||
|
jh1lqMFywB4DujTmkWLYcPJJ0RTT2NsSakteti/e1DHCuBSU0t3Q3K1paTh8aVLx
|
||||||
|
eK0IKNlCWqX5d1aYzCNZsRjJuQgPX6p/xcNGS+RS27jmRWPpvm6n1JfMvYRa7fF+
|
||||||
|
HnKhGNO+hDbhkQO4s0V1U+unNhshKDhTW3mBLmAEb2OHLOEaUZtYSbqr1E9tYXgU
|
||||||
|
DiYRkeWUpQXJ6pE91fmcaZFG0SxkqWnhe7GUa6wbb/vROWph4A1ZVHympBtOYwoJ
|
||||||
|
eibcJjBZLrugZdix8kl8NDI7SuIM/P0x0m9WkNfhJ9vSgQXlaQIDAQABo2MwYTAO
|
||||||
|
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUvsfiBTBW
|
||||||
|
/oQictTkM3HcybsA1YQwHwYDVR0jBBgwFoAUvsfiBTBW/oQictTkM3HcybsA1YQw
|
||||||
|
DQYJKoZIhvcNAQELBQADggEBALUJWitOV4xAvfNB8Z20AQ+/hdXkWVgj1VBbd++v
|
||||||
|
+X88q1TnueKAExU5o87MCjh9jMxalZqSVN9MUbQ4Xa+tmkjayizdpFaw6TbbaMIB
|
||||||
|
Tgqq5ATXMnOdZd46QC764Po9R9+k9hk4dNIr5gk1ifXZDMy/7jSOVARvpwzr0cTx
|
||||||
|
flRCTgZbcK10freoU7a74/YjEpG0wggGlR4aRWfm90Im9JM3aI55zAYQFzduf56c
|
||||||
|
HXJDLgBtbOx/ceqVrkPdvYwP9Q34tKAMiheQ0G3tTxP3Xc87gh4UEDV02oHhcbqw
|
||||||
|
WSm+8zTfGUlchowPRdqKE66urWTep+BA9c8zUqDdoq5lE9s=
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -66,14 +66,15 @@ func (r IndexedCARoots) Active() *CARoot {
|
||||||
|
|
||||||
// CARoot represents a root CA certificate that is trusted.
|
// CARoot represents a root CA certificate that is trusted.
|
||||||
type CARoot struct {
|
type CARoot struct {
|
||||||
// ID is a globally unique ID (UUID) representing this CA root.
|
// ID is a globally unique ID (UUID) representing this CA chain. It is
|
||||||
|
// calculated from the SHA1 of the primary CA certificate.
|
||||||
ID string
|
ID string
|
||||||
|
|
||||||
// Name is a human-friendly name for this CA root. This value is
|
// Name is a human-friendly name for this CA root. This value is
|
||||||
// opaque to Consul and is not used for anything internally.
|
// opaque to Consul and is not used for anything internally.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// SerialNumber is the x509 serial number of the certificate.
|
// SerialNumber is the x509 serial number of the primary CA certificate.
|
||||||
SerialNumber uint64
|
SerialNumber uint64
|
||||||
|
|
||||||
// SigningKeyID is the connect.HexString encoded id of the public key that
|
// SigningKeyID is the connect.HexString encoded id of the public key that
|
||||||
|
@ -96,8 +97,11 @@ type CARoot struct {
|
||||||
// future flexibility.
|
// future flexibility.
|
||||||
ExternalTrustDomain string
|
ExternalTrustDomain string
|
||||||
|
|
||||||
// Time validity bounds.
|
// NotBefore is the x509.Certificate.NotBefore value of the primary CA
|
||||||
|
// certificate. This value should generally be a time in the past.
|
||||||
NotBefore time.Time
|
NotBefore time.Time
|
||||||
|
// NotAfter is the x509.Certificate.NotAfter value of the primary CA
|
||||||
|
// certificate. This is the time when the certificate will expire.
|
||||||
NotAfter time.Time
|
NotAfter time.Time
|
||||||
|
|
||||||
// RootCert is the PEM-encoded public certificate for the root CA. The
|
// RootCert is the PEM-encoded public certificate for the root CA. The
|
||||||
|
|
Loading…
Reference in New Issue