Connect CA Primary Provider refactor (#16749)
* Rename Intermediate cert references to LeafSigningCert Within the Consul CA subsystem, the term "Intermediate" is confusing because the meaning changes depending on provider and datacenter (primary vs secondary). For example, when using the Consul CA the "ActiveIntermediate" may return the root certificate in a primary datacenter. At a high level, we are interested in knowing which CA is responsible for signing leaf certs, regardless of its position in a certificate chain. This rename makes the intent clearer. * Move provider state check earlier * Remove calls to GenerateLeafSigningCert GenerateLeafSigningCert (formerly known as GenerateIntermediate) is vestigial in non-Vault providers, as it simply returns the root certificate in primary datacenters. By folding Vault's intermediate cert logic into `GenerateRoot` we can encapsulate the intermediate cert handling within `newCARoot`. * Move GenerateLeafSigningCert out of PrimaryProvidder Now that the Vault Provider calls GenerateLeafSigningCert within GenerateRoot, we can remove the method from all other providers that never used it in a meaningful way. * Add test for IntermediatePEM * Rename GenerateRoot to GenerateCAChain "Root" was being overloaded in the Consul CA context, as different providers and configs resulted in a single root certificate or a chain originating from an external trusted CA. Since the Vault provider also generates intermediates, it seems more accurate to call this a CAChain.
This commit is contained in:
parent
f8d6cce902
commit
8671448b73
|
@ -1,4 +1,4 @@
|
|||
// Code generated by mockery v2.15.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.20.0. DO NOT EDIT.
|
||||
|
||||
package ca
|
||||
|
||||
|
@ -13,18 +13,21 @@ type MockProvider struct {
|
|||
mock.Mock
|
||||
}
|
||||
|
||||
// ActiveIntermediate provides a mock function with given fields:
|
||||
func (_m *MockProvider) ActiveIntermediate() (string, error) {
|
||||
// ActiveLeafSigningCert provides a mock function with given fields:
|
||||
func (_m *MockProvider) ActiveLeafSigningCert() (string, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (string, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
|
@ -67,13 +70,16 @@ func (_m *MockProvider) CrossSignCA(_a0 *x509.Certificate) (string, error) {
|
|||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*x509.Certificate) (string, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*x509.Certificate) string); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*x509.Certificate) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
|
@ -83,46 +89,28 @@ func (_m *MockProvider) CrossSignCA(_a0 *x509.Certificate) (string, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GenerateIntermediate provides a mock function with given fields:
|
||||
func (_m *MockProvider) GenerateIntermediate() (string, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GenerateIntermediateCSR provides a mock function with given fields:
|
||||
func (_m *MockProvider) GenerateIntermediateCSR() (string, 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 {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 string
|
||||
if rf, ok := ret.Get(1).(func() string); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Get(1).(string)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func() error); ok {
|
||||
r2 = rf()
|
||||
} else {
|
||||
|
@ -132,18 +120,21 @@ func (_m *MockProvider) GenerateIntermediateCSR() (string, string, error) {
|
|||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// GenerateRoot provides a mock function with given fields:
|
||||
func (_m *MockProvider) GenerateRoot() (RootResult, error) {
|
||||
// GenerateCAChain provides a mock function with given fields:
|
||||
func (_m *MockProvider) GenerateCAChain() (CAChainResult, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 RootResult
|
||||
if rf, ok := ret.Get(0).(func() RootResult); ok {
|
||||
var r0 CAChainResult
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (CAChainResult, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() CAChainResult); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(RootResult)
|
||||
r0 = ret.Get(0).(CAChainResult)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
|
@ -172,13 +163,16 @@ func (_m *MockProvider) Sign(_a0 *x509.CertificateRequest) (string, error) {
|
|||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) (string, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) string); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*x509.CertificateRequest) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
|
@ -193,13 +187,16 @@ func (_m *MockProvider) SignIntermediate(_a0 *x509.CertificateRequest) (string,
|
|||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) (string, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) string); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*x509.CertificateRequest) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
|
@ -214,6 +211,10 @@ func (_m *MockProvider) State() (map[string]string, error) {
|
|||
ret := _m.Called()
|
||||
|
||||
var r0 map[string]string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (map[string]string, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() map[string]string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
|
@ -222,7 +223,6 @@ func (_m *MockProvider) State() (map[string]string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
|
@ -237,13 +237,16 @@ func (_m *MockProvider) SupportsCrossSigning() (bool, error) {
|
|||
ret := _m.Called()
|
||||
|
||||
var r0 bool
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (bool, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() bool); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
|
|
|
@ -17,12 +17,16 @@ import (
|
|||
// on servers and CA provider.
|
||||
var ErrRateLimited = errors.New("operation rate limited by CA provider")
|
||||
|
||||
// PrimaryUsesIntermediate is an optional interface that CA providers may implement
|
||||
// PrimaryUsesIntermediate is an optional interface that CA providers may implement
|
||||
// to indicate that they use an intermediate cert in the primary datacenter as
|
||||
// well as the secondary. This is used when determining whether to run the
|
||||
// intermediate renewal routine in the primary.
|
||||
type PrimaryUsesIntermediate interface {
|
||||
PrimaryUsesIntermediate()
|
||||
// GenerateLeafSigningCert returns a new intermediate signing cert and sets it to
|
||||
// the active intermediate. If multiple intermediates are needed to complete
|
||||
// the chain from the signing certificate back to the active root, they should
|
||||
// all by bundled here.
|
||||
GenerateLeafSigningCert() (string, error)
|
||||
}
|
||||
|
||||
// ProviderConfig encapsulates all the data Consul passes to `Configure` on a
|
||||
|
@ -87,12 +91,12 @@ type Provider interface {
|
|||
// in the Provider struct so it won't change after being returned.
|
||||
State() (map[string]string, error)
|
||||
|
||||
// ActiveIntermediate returns the current signing cert used by this provider
|
||||
// ActiveLeafSigningCert returns the current signing cert used by this provider
|
||||
// for generating SPIFFE leaf certs. Note that this must not change except
|
||||
// when Consul requests the change via GenerateIntermediate. Changing the
|
||||
// when Consul requests the change via GenerateLeafSigningCert. Changing the
|
||||
// signing cert will break Consul's assumptions about which validation paths
|
||||
// are active.
|
||||
ActiveIntermediate() (string, error)
|
||||
ActiveLeafSigningCert() (string, error)
|
||||
|
||||
// Sign signs a leaf certificate used by Connect proxies from a CSR. The PEM
|
||||
// returned should include only the leaf certificate as all Intermediates
|
||||
|
@ -121,25 +125,19 @@ type Provider interface {
|
|||
}
|
||||
|
||||
type PrimaryProvider interface {
|
||||
// GenerateRoot is called:
|
||||
// GenerateCAChain is called:
|
||||
// * to initialize the CA system when a server is elected as a raft leader
|
||||
// * when the CA configuration is updated in a way that might require
|
||||
// generating a new root certificate.
|
||||
//
|
||||
// In both cases GenerateRoot is always called on a newly created provider
|
||||
// In both cases GenerateCAChain is always called on a newly created provider
|
||||
// after calling Provider.Configure, and before any other calls to the
|
||||
// provider.
|
||||
//
|
||||
// The provider should return an existing root certificate if one exists,
|
||||
// otherwise it should generate a new root certificate and return it.
|
||||
GenerateRoot() (RootResult, error)
|
||||
|
||||
// GenerateIntermediate returns a new intermediate signing cert and sets it to
|
||||
// the active intermediate. If multiple intermediates are needed to complete
|
||||
// the chain from the signing certificate back to the active root, they should
|
||||
// all by bundled here.
|
||||
// TODO: replace with GenerateLeafSigningCert (https://github.com/hashicorp/consul/issues/12386)
|
||||
GenerateIntermediate() (string, error)
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
|
@ -195,10 +193,8 @@ type SecondaryProvider interface {
|
|||
SetIntermediate(intermediatePEM, rootPEM, opaque string) error
|
||||
}
|
||||
|
||||
// RootResult is the result returned by PrimaryProvider.GenerateRoot.
|
||||
//
|
||||
// TODO: rename this struct
|
||||
type RootResult struct {
|
||||
// CAChainResult is the result returned by PrimaryProvider.GenerateCAChain.
|
||||
type CAChainResult struct {
|
||||
// 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.
|
||||
|
@ -206,6 +202,11 @@ type RootResult struct {
|
|||
// 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
|
||||
|
||||
// IntermediatePEM is an encoded bundle of CA certificates used only by
|
||||
// providers that use an intermediate CA to sign leaf certificates (e.g.
|
||||
// Vault). Its issuer should form a chain leading to the trusted CA in PEM.
|
||||
IntermediatePEM string
|
||||
}
|
||||
|
||||
// NeedsStop is an optional interface that allows a CA to define a function
|
||||
|
|
|
@ -139,20 +139,20 @@ func (a *AWSProvider) State() (map[string]string, error) {
|
|||
return state, nil
|
||||
}
|
||||
|
||||
// GenerateRoot implements Provider
|
||||
func (a *AWSProvider) GenerateRoot() (RootResult, error) {
|
||||
// GenerateCAChain implements Provider
|
||||
func (a *AWSProvider) GenerateCAChain() (CAChainResult, error) {
|
||||
if !a.isPrimary {
|
||||
return RootResult{}, fmt.Errorf("provider is not the root certificate authority")
|
||||
return CAChainResult{}, fmt.Errorf("provider is not the root certificate authority")
|
||||
}
|
||||
|
||||
if err := a.ensureCA(); err != nil {
|
||||
return RootResult{}, err
|
||||
return CAChainResult{}, err
|
||||
}
|
||||
|
||||
if a.rootPEM == "" {
|
||||
return RootResult{}, fmt.Errorf("AWS CA provider not fully Initialized")
|
||||
return CAChainResult{}, fmt.Errorf("AWS CA provider not fully Initialized")
|
||||
}
|
||||
return RootResult{PEM: a.rootPEM}, nil
|
||||
return CAChainResult{PEM: a.rootPEM}, nil
|
||||
}
|
||||
|
||||
// ensureCA loads the CA resource to check it exists if configured by User or in
|
||||
|
@ -545,8 +545,8 @@ func (a *AWSProvider) SetIntermediate(intermediatePEM string, rootPEM string, _
|
|||
return nil
|
||||
}
|
||||
|
||||
// ActiveIntermediate implements Provider
|
||||
func (a *AWSProvider) ActiveIntermediate() (string, error) {
|
||||
// ActiveLeafSigningCert implements Provider
|
||||
func (a *AWSProvider) ActiveLeafSigningCert() (string, error) {
|
||||
err := a.ensureCA()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -574,19 +574,6 @@ func (a *AWSProvider) ActiveIntermediate() (string, error) {
|
|||
return a.intermediatePEM, nil
|
||||
}
|
||||
|
||||
// GenerateIntermediate implements Provider
|
||||
func (a *AWSProvider) GenerateIntermediate() (string, error) {
|
||||
// Like the consul provider, for now the Primary DC just gets a root and no
|
||||
// intermediate to sign with. so just return this. Secondaries use
|
||||
// intermediates but this method is only called during primary DC (root)
|
||||
// initialization in case a provider generates separate root and
|
||||
// intermediates.
|
||||
//
|
||||
// TODO(banks) support user-supplied CA being a Subordinate even in the
|
||||
// primary DC.
|
||||
return a.ActiveIntermediate()
|
||||
}
|
||||
|
||||
// Sign implements Provider
|
||||
func (a *AWSProvider) Sign(csr *x509.CertificateRequest) (string, error) {
|
||||
connect.HackSANExtensionForCSR(csr)
|
||||
|
|
|
@ -49,18 +49,10 @@ func TestAWSBootstrapAndSignPrimary(t *testing.T) {
|
|||
provider := testAWSProvider(t, testProviderConfigPrimary(t, cfg))
|
||||
defer provider.Cleanup(true, nil)
|
||||
|
||||
root, err := provider.GenerateRoot()
|
||||
root, err := provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
rootPEM := root.PEM
|
||||
|
||||
// Generate Intermediate (not actually needed for this provider for now
|
||||
// but this simulates the calls in Server.initializeRoot).
|
||||
interPEM, err := provider.GenerateIntermediate()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should be the same for now
|
||||
require.Equal(t, rootPEM, interPEM)
|
||||
|
||||
// Ensure they use the right key type
|
||||
rootCert, err := connect.ParseCert(rootPEM)
|
||||
require.NoError(t, err)
|
||||
|
@ -84,7 +76,7 @@ func TestAWSBootstrapAndSignPrimary(t *testing.T) {
|
|||
provider := testAWSProvider(t, testProviderConfigPrimary(t, nil))
|
||||
defer provider.Cleanup(true, nil)
|
||||
|
||||
root, err := provider.GenerateRoot()
|
||||
root, err := provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
rootPEM := root.PEM
|
||||
|
||||
|
@ -119,7 +111,7 @@ func TestAWSBootstrapAndSignSecondary(t *testing.T) {
|
|||
|
||||
p1 := testAWSProvider(t, testProviderConfigPrimary(t, nil))
|
||||
defer p1.Cleanup(true, nil)
|
||||
root, err := p1.GenerateRoot()
|
||||
root, err := p1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
rootPEM := root.PEM
|
||||
|
||||
|
@ -129,7 +121,7 @@ func TestAWSBootstrapAndSignSecondary(t *testing.T) {
|
|||
testSignIntermediateCrossDC(t, p1, p2)
|
||||
|
||||
// Fetch intermediate from s2 now for later comparison
|
||||
intPEM, err := p2.ActiveIntermediate()
|
||||
intPEM, err := p2.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Capture the state of the providers we've setup
|
||||
|
@ -148,15 +140,15 @@ func TestAWSBootstrapAndSignSecondary(t *testing.T) {
|
|||
cfg1 := testProviderConfigPrimary(t, nil)
|
||||
cfg1.State = p1State
|
||||
p1 = testAWSProvider(t, cfg1)
|
||||
root, err := p1.GenerateRoot()
|
||||
root, err := p1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
newRootPEM := root.PEM
|
||||
|
||||
cfg2 := testProviderConfigPrimary(t, nil)
|
||||
cfg2.State = p2State
|
||||
p2 = testAWSProvider(t, cfg2)
|
||||
// Need call ActiveIntermediate like leader would to trigger loading from PCA
|
||||
newIntPEM, err := p2.ActiveIntermediate()
|
||||
// Need call ActiveLeafSigningCert like leader would to trigger loading from PCA
|
||||
newIntPEM, err := p2.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Root cert should not have changed
|
||||
|
@ -182,7 +174,7 @@ func TestAWSBootstrapAndSignSecondary(t *testing.T) {
|
|||
"ExistingARN": p1State[AWSStateCAARNKey],
|
||||
})
|
||||
p1 = testAWSProvider(t, cfg1)
|
||||
root, err := p1.GenerateRoot()
|
||||
root, err := p1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
newRootPEM := root.PEM
|
||||
|
||||
|
@ -191,8 +183,8 @@ func TestAWSBootstrapAndSignSecondary(t *testing.T) {
|
|||
})
|
||||
cfg1.RawConfig["ExistingARN"] = p2State[AWSStateCAARNKey]
|
||||
p2 = testAWSProvider(t, cfg2)
|
||||
// Need call ActiveIntermediate like leader would to trigger loading from PCA
|
||||
newIntPEM, err := p2.ActiveIntermediate()
|
||||
// Need call ActiveLeafSigningCert like leader would to trigger loading from PCA
|
||||
newIntPEM, err := p2.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Root cert should not have changed
|
||||
|
@ -221,10 +213,10 @@ func TestAWSBootstrapAndSignSecondary(t *testing.T) {
|
|||
p2 = testAWSProvider(t, cfg2)
|
||||
require.NoError(t, p2.SetIntermediate(newIntPEM, newRootPEM, ""))
|
||||
|
||||
root, err = p1.GenerateRoot()
|
||||
root, err = p1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
newRootPEM = root.PEM
|
||||
newIntPEM, err = p2.ActiveIntermediate()
|
||||
newIntPEM, err = p2.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, rootPEM, newRootPEM)
|
||||
|
@ -243,7 +235,7 @@ func TestAWSBootstrapAndSignSecondaryConsul(t *testing.T) {
|
|||
p1 := TestConsulProvider(t, delegate)
|
||||
cfg := testProviderConfig(conf)
|
||||
require.NoError(t, p1.Configure(cfg))
|
||||
_, err := p1.GenerateRoot()
|
||||
_, err := p1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
p2 := testAWSProvider(t, testProviderConfigSecondary(t, nil))
|
||||
|
@ -256,7 +248,7 @@ func TestAWSBootstrapAndSignSecondaryConsul(t *testing.T) {
|
|||
p1 := testAWSProvider(t, testProviderConfigPrimary(t, nil))
|
||||
defer p1.Cleanup(true, nil)
|
||||
|
||||
_, err := p1.GenerateRoot()
|
||||
_, err := p1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
conf := testConsulCAConfig()
|
||||
|
@ -334,7 +326,7 @@ func TestAWSProvider_Cleanup(t *testing.T) {
|
|||
// create a provider with the default config which will create the CA
|
||||
p1Conf := testProviderConfigPrimary(t, nil)
|
||||
p1 := testAWSProvider(t, p1Conf)
|
||||
p1.GenerateRoot()
|
||||
p1.GenerateCAChain()
|
||||
|
||||
t.Cleanup(func() {
|
||||
// This is a fail safe just in case the Cleanup routine of the
|
||||
|
@ -368,7 +360,7 @@ func TestAWSProvider_Cleanup(t *testing.T) {
|
|||
// create a provider with the default config which will create the CA
|
||||
p1Conf := testProviderConfigPrimary(t, nil)
|
||||
p1 := testAWSProvider(t, p1Conf)
|
||||
p1.GenerateRoot()
|
||||
p1.GenerateCAChain()
|
||||
|
||||
t.Cleanup(func() {
|
||||
// This is a fail safe just in case the Cleanup routine of the
|
||||
|
@ -405,7 +397,7 @@ func TestAWSProvider_Cleanup(t *testing.T) {
|
|||
// create a provider with the default config which will create the CA
|
||||
p1Conf := testProviderConfigPrimary(t, nil)
|
||||
p1 := testAWSProvider(t, p1Conf)
|
||||
p1.GenerateRoot()
|
||||
p1.GenerateCAChain()
|
||||
|
||||
t.Cleanup(func() {
|
||||
// the p2 provider should not remove the CA but we need to ensure that
|
||||
|
|
|
@ -154,18 +154,18 @@ func (c *ConsulProvider) State() (map[string]string, error) {
|
|||
return c.testState, nil
|
||||
}
|
||||
|
||||
// GenerateRoot initializes a new root certificate and private key if needed.
|
||||
func (c *ConsulProvider) GenerateRoot() (RootResult, error) {
|
||||
// GenerateCAChain initializes a new root certificate and private key if needed.
|
||||
func (c *ConsulProvider) GenerateCAChain() (CAChainResult, error) {
|
||||
providerState, err := c.getState()
|
||||
if err != nil {
|
||||
return RootResult{}, err
|
||||
return CAChainResult{}, err
|
||||
}
|
||||
|
||||
if !c.isPrimary {
|
||||
return RootResult{}, fmt.Errorf("provider is not the root certificate authority")
|
||||
return CAChainResult{}, fmt.Errorf("provider is not the root certificate authority")
|
||||
}
|
||||
if providerState.RootCert != "" {
|
||||
return RootResult{PEM: providerState.RootCert}, nil
|
||||
return CAChainResult{PEM: providerState.RootCert}, nil
|
||||
}
|
||||
|
||||
// Generate a private key if needed
|
||||
|
@ -173,7 +173,7 @@ func (c *ConsulProvider) GenerateRoot() (RootResult, error) {
|
|||
if c.config.PrivateKey == "" {
|
||||
_, pk, err := connect.GeneratePrivateKeyWithConfig(c.config.PrivateKeyType, c.config.PrivateKeyBits)
|
||||
if err != nil {
|
||||
return RootResult{}, err
|
||||
return CAChainResult{}, err
|
||||
}
|
||||
newState.PrivateKey = pk
|
||||
} else {
|
||||
|
@ -184,12 +184,12 @@ func (c *ConsulProvider) GenerateRoot() (RootResult, error) {
|
|||
if c.config.RootCert == "" {
|
||||
nextSerial, err := c.incrementAndGetNextSerialNumber()
|
||||
if err != nil {
|
||||
return RootResult{}, fmt.Errorf("error computing next serial number: %v", err)
|
||||
return CAChainResult{}, fmt.Errorf("error computing next serial number: %v", err)
|
||||
}
|
||||
|
||||
ca, err := c.generateCA(newState.PrivateKey, nextSerial, c.config.RootCertTTL)
|
||||
if err != nil {
|
||||
return RootResult{}, fmt.Errorf("error generating CA: %v", err)
|
||||
return CAChainResult{}, fmt.Errorf("error generating CA: %v", err)
|
||||
}
|
||||
newState.RootCert = ca
|
||||
} else {
|
||||
|
@ -202,10 +202,10 @@ func (c *ConsulProvider) GenerateRoot() (RootResult, error) {
|
|||
ProviderState: &newState,
|
||||
}
|
||||
if _, err := c.Delegate.ApplyCARequest(args); err != nil {
|
||||
return RootResult{}, err
|
||||
return CAChainResult{}, err
|
||||
}
|
||||
|
||||
return RootResult{PEM: newState.RootCert}, nil
|
||||
return CAChainResult{PEM: newState.RootCert}, nil
|
||||
}
|
||||
|
||||
// GenerateIntermediateCSR creates a private key and generates a CSR
|
||||
|
@ -280,7 +280,7 @@ func (c *ConsulProvider) SetIntermediate(intermediatePEM, rootPEM, _ string) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *ConsulProvider) ActiveIntermediate() (string, error) {
|
||||
func (c *ConsulProvider) ActiveLeafSigningCert() (string, error) {
|
||||
providerState, err := c.getState()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -292,12 +292,6 @@ func (c *ConsulProvider) ActiveIntermediate() (string, error) {
|
|||
return providerState.IntermediateCert, nil
|
||||
}
|
||||
|
||||
// We aren't maintaining separate root/intermediate CAs for the builtin
|
||||
// provider, so just return the root.
|
||||
func (c *ConsulProvider) GenerateIntermediate() (string, error) {
|
||||
return c.ActiveIntermediate()
|
||||
}
|
||||
|
||||
// Remove the state store entry for this provider instance.
|
||||
func (c *ConsulProvider) Cleanup(_ bool, _ map[string]interface{}) error {
|
||||
// This method only gets called for final cleanup. Therefore we don't
|
||||
|
@ -354,7 +348,7 @@ func (c *ConsulProvider) Sign(csr *x509.CertificateRequest) (string, error) {
|
|||
}
|
||||
|
||||
// Parse the CA cert
|
||||
certPEM, err := c.ActiveIntermediate()
|
||||
certPEM, err := c.ActiveLeafSigningCert()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -87,11 +87,11 @@ func TestConsulCAProvider_Bootstrap(t *testing.T) {
|
|||
provider := TestConsulProvider(t, delegate)
|
||||
require.NoError(t, provider.Configure(testProviderConfig(conf)))
|
||||
|
||||
root, err := provider.GenerateRoot()
|
||||
root, err := provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Intermediate should be the same cert.
|
||||
inter, err := provider.ActiveIntermediate()
|
||||
inter, err := provider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, root.PEM, inter)
|
||||
|
||||
|
@ -126,7 +126,7 @@ func TestConsulCAProvider_Bootstrap_WithCert(t *testing.T) {
|
|||
provider := TestConsulProvider(t, delegate)
|
||||
require.NoError(t, provider.Configure(testProviderConfig(conf)))
|
||||
|
||||
root, err := provider.GenerateRoot()
|
||||
root, err := provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, root.PEM, rootCA.RootCert)
|
||||
|
||||
|
@ -161,7 +161,7 @@ func TestConsulCAProvider_SignLeaf(t *testing.T) {
|
|||
|
||||
provider := TestConsulProvider(t, delegate)
|
||||
require.NoError(t, provider.Configure(testProviderConfig(conf)))
|
||||
_, err := provider.GenerateRoot()
|
||||
_, err := provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
spiffeService := &connect.SpiffeIDService{
|
||||
|
@ -274,7 +274,7 @@ func TestConsulCAProvider_CrossSignCA(t *testing.T) {
|
|||
conf1.Config["PrivateKeyType"] = tc.SigningKeyType
|
||||
conf1.Config["PrivateKeyBits"] = tc.SigningKeyBits
|
||||
require.NoError(t, provider1.Configure(testProviderConfig(conf1)))
|
||||
_, err := provider1.GenerateRoot()
|
||||
_, err := provider1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
conf2 := testConsulCAConfig()
|
||||
|
@ -284,7 +284,7 @@ func TestConsulCAProvider_CrossSignCA(t *testing.T) {
|
|||
conf2.Config["PrivateKeyType"] = tc.CSRKeyType
|
||||
conf2.Config["PrivateKeyBits"] = tc.CSRKeyBits
|
||||
require.NoError(t, provider2.Configure(testProviderConfig(conf2)))
|
||||
_, err = provider2.GenerateRoot()
|
||||
_, err = provider2.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
testCrossSignProviders(t, provider1, provider2)
|
||||
|
@ -295,7 +295,7 @@ func TestConsulCAProvider_CrossSignCA(t *testing.T) {
|
|||
func testCrossSignProviders(t *testing.T, provider1, provider2 Provider) {
|
||||
|
||||
// Get the root from the new provider to be cross-signed.
|
||||
root, err := provider2.GenerateRoot()
|
||||
root, err := provider2.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
newRoot, err := connect.ParseCert(root.PEM)
|
||||
|
@ -304,7 +304,7 @@ func testCrossSignProviders(t *testing.T, provider1, provider2 Provider) {
|
|||
requireNotEncoded(t, newRoot.SubjectKeyId)
|
||||
requireNotEncoded(t, newRoot.AuthorityKeyId)
|
||||
|
||||
newInterPEM, err := provider2.ActiveIntermediate()
|
||||
newInterPEM, err := provider2.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
newIntermediate, err := connect.ParseCert(newInterPEM)
|
||||
require.NoError(t, err)
|
||||
|
@ -319,7 +319,7 @@ func testCrossSignProviders(t *testing.T, provider1, provider2 Provider) {
|
|||
requireNotEncoded(t, xc.SubjectKeyId)
|
||||
requireNotEncoded(t, xc.AuthorityKeyId)
|
||||
|
||||
p1Root, err := provider1.GenerateRoot()
|
||||
p1Root, err := provider1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
oldRoot, err := connect.ParseCert(p1Root.PEM)
|
||||
require.NoError(t, err)
|
||||
|
@ -382,7 +382,7 @@ func testCrossSignProvidersShouldFail(t *testing.T, provider1, provider2 Provide
|
|||
t.Helper()
|
||||
|
||||
// Get the root from the new provider to be cross-signed.
|
||||
root, err := provider2.GenerateRoot()
|
||||
root, err := provider2.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
newRoot, err := connect.ParseCert(root.PEM)
|
||||
|
@ -390,7 +390,7 @@ func testCrossSignProvidersShouldFail(t *testing.T, provider1, provider2 Provide
|
|||
requireNotEncoded(t, newRoot.SubjectKeyId)
|
||||
requireNotEncoded(t, newRoot.AuthorityKeyId)
|
||||
|
||||
newInterPEM, err := provider2.ActiveIntermediate()
|
||||
newInterPEM, err := provider2.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
newIntermediate, err := connect.ParseCert(newInterPEM)
|
||||
require.NoError(t, err)
|
||||
|
@ -421,7 +421,7 @@ func TestConsulProvider_SignIntermediate(t *testing.T) {
|
|||
conf1.Config["PrivateKeyType"] = tc.SigningKeyType
|
||||
conf1.Config["PrivateKeyBits"] = tc.SigningKeyBits
|
||||
require.NoError(t, provider1.Configure(testProviderConfig(conf1)))
|
||||
_, err := provider1.GenerateRoot()
|
||||
_, err := provider1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
conf2 := testConsulCAConfig()
|
||||
|
@ -452,7 +452,7 @@ func testSignIntermediateCrossDC(t *testing.T, provider1, provider2 Provider) {
|
|||
// Sign the CSR with provider1.
|
||||
intermediatePEM, err := provider1.SignIntermediate(csr)
|
||||
require.NoError(t, err)
|
||||
root, err := provider1.GenerateRoot()
|
||||
root, err := provider1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
rootPEM := root.PEM
|
||||
|
||||
|
@ -527,7 +527,7 @@ func TestConsulCAProvider_MigrateOldID(t *testing.T) {
|
|||
|
||||
provider := TestConsulProvider(t, delegate)
|
||||
require.NoError(t, provider.Configure(testProviderConfig(conf)))
|
||||
_, err = provider.GenerateRoot()
|
||||
_, err = provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
// After running Configure, the old ID entry should be gone.
|
||||
|
|
|
@ -279,10 +279,10 @@ func (v *VaultProvider) State() (map[string]string, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// GenerateRoot mounts and initializes a new root PKI backend if needed.
|
||||
func (v *VaultProvider) GenerateRoot() (RootResult, error) {
|
||||
// GenerateCAChain mounts and initializes a new root PKI backend if needed.
|
||||
func (v *VaultProvider) GenerateCAChain() (CAChainResult, error) {
|
||||
if !v.isPrimary {
|
||||
return RootResult{}, fmt.Errorf("provider is not the root certificate authority")
|
||||
return CAChainResult{}, fmt.Errorf("provider is not the root certificate authority")
|
||||
}
|
||||
|
||||
// Set up the root PKI backend if necessary.
|
||||
|
@ -302,7 +302,7 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) {
|
|||
},
|
||||
})
|
||||
if err != nil {
|
||||
return RootResult{}, fmt.Errorf("failed to mount root CA backend: %w", err)
|
||||
return CAChainResult{}, fmt.Errorf("failed to mount root CA backend: %w", err)
|
||||
}
|
||||
|
||||
// We want to initialize afterwards
|
||||
|
@ -310,7 +310,7 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) {
|
|||
case ErrBackendNotInitialized:
|
||||
uid, err := connect.CompactUID()
|
||||
if err != nil {
|
||||
return RootResult{}, err
|
||||
return CAChainResult{}, 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) GenerateRoot() (RootResult, error) {
|
|||
"key_bits": v.config.PrivateKeyBits,
|
||||
})
|
||||
if err != nil {
|
||||
return RootResult{}, fmt.Errorf("failed to initialize root CA: %w", err)
|
||||
return CAChainResult{}, fmt.Errorf("failed to initialize root CA: %w", err)
|
||||
}
|
||||
var ok bool
|
||||
rootPEM, ok = resp.Data["certificate"].(string)
|
||||
if !ok {
|
||||
return RootResult{}, fmt.Errorf("unexpected response from Vault: %v", resp.Data["certificate"])
|
||||
return CAChainResult{}, fmt.Errorf("unexpected response from Vault: %v", resp.Data["certificate"])
|
||||
}
|
||||
|
||||
default:
|
||||
if err != nil {
|
||||
return RootResult{}, fmt.Errorf("unexpected error while setting root PKI backend: %w", err)
|
||||
return CAChainResult{}, 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 RootResult{}, err
|
||||
return CAChainResult{}, err
|
||||
}
|
||||
|
||||
// Workaround for a bug in the Vault PKI API.
|
||||
|
@ -344,7 +344,18 @@ func (v *VaultProvider) GenerateRoot() (RootResult, error) {
|
|||
rootChain = rootPEM
|
||||
}
|
||||
|
||||
return RootResult{PEM: rootChain}, nil
|
||||
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
|
||||
}
|
||||
|
||||
// GenerateIntermediateCSR creates a private key and generates a CSR
|
||||
|
@ -498,7 +509,7 @@ func (v *VaultProvider) SetIntermediate(intermediatePEM, rootPEM, keyId string)
|
|||
}
|
||||
|
||||
// ActiveIntermediate returns the current intermediate certificate.
|
||||
func (v *VaultProvider) ActiveIntermediate() (string, error) {
|
||||
func (v *VaultProvider) ActiveLeafSigningCert() (string, error) {
|
||||
cert, err := v.getCA(v.config.IntermediatePKINamespace, v.config.IntermediatePKIPath)
|
||||
|
||||
// This error is expected when calling initializeSecondaryCA for the
|
||||
|
@ -571,7 +582,7 @@ func (v *VaultProvider) getCAChain(namespace, path string) (string, error) {
|
|||
// GenerateIntermediate 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) GenerateIntermediate() (string, error) {
|
||||
func (v *VaultProvider) GenerateLeafSigningCert() (string, error) {
|
||||
csr, keyId, err := v.generateIntermediateCSR()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -607,7 +618,7 @@ func (v *VaultProvider) GenerateIntermediate() (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return v.ActiveIntermediate()
|
||||
return v.ActiveLeafSigningCert()
|
||||
}
|
||||
|
||||
// setDefaultIntermediateIssuer updates the default issuer for
|
||||
|
@ -814,8 +825,6 @@ func (v *VaultProvider) Stop() {
|
|||
v.stopWatcher()
|
||||
}
|
||||
|
||||
func (v *VaultProvider) PrimaryUsesIntermediate() {}
|
||||
|
||||
// We use raw path here
|
||||
func (v *VaultProvider) mountNamespaced(namespace, path string, mountInfo *vaultapi.MountInput) error {
|
||||
defer v.setNamespace(namespace)()
|
||||
|
|
|
@ -245,7 +245,7 @@ func TestVaultCAProvider_SecondaryActiveIntermediate(t *testing.T) {
|
|||
"IntermediatePKIPath": "pki-intermediate/",
|
||||
})
|
||||
|
||||
cert, err := provider.ActiveIntermediate()
|
||||
cert, err := provider.ActiveLeafSigningCert()
|
||||
require.Empty(t, cert)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
@ -405,7 +405,7 @@ func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
|||
"LeafCertTTL": "1h",
|
||||
},
|
||||
certFunc: func(provider *VaultProvider) (string, error) {
|
||||
root, err := provider.GenerateRoot()
|
||||
root, err := provider.GenerateCAChain()
|
||||
return root.PEM, err
|
||||
},
|
||||
backendPath: "pki-root/",
|
||||
|
@ -419,7 +419,7 @@ func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
|||
"RootCertTTL": "8761h",
|
||||
},
|
||||
certFunc: func(provider *VaultProvider) (string, error) {
|
||||
return provider.ActiveIntermediate()
|
||||
return provider.ActiveLeafSigningCert()
|
||||
},
|
||||
backendPath: "pki-intermediate/",
|
||||
rootCaCreation: false,
|
||||
|
@ -483,12 +483,12 @@ func TestVaultCAProvider_SignLeaf(t *testing.T) {
|
|||
Service: "foo",
|
||||
}
|
||||
|
||||
root, err := provider.GenerateRoot()
|
||||
root, err := provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
rootPEM := root.PEM
|
||||
assertCorrectKeyType(t, tc.KeyType, rootPEM)
|
||||
|
||||
intPEM, err := provider.ActiveIntermediate()
|
||||
intPEM, err := provider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
assertCorrectKeyType(t, tc.KeyType, intPEM)
|
||||
|
||||
|
@ -586,11 +586,11 @@ func TestVaultCAProvider_CrossSignCA(t *testing.T) {
|
|||
})
|
||||
|
||||
testutil.RunStep(t, "init", func(t *testing.T) {
|
||||
root, err := provider1.GenerateRoot()
|
||||
root, err := provider1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
assertCorrectKeyType(t, tc.SigningKeyType, root.PEM)
|
||||
|
||||
intPEM, err := provider1.ActiveIntermediate()
|
||||
intPEM, err := provider1.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
assertCorrectKeyType(t, tc.SigningKeyType, intPEM)
|
||||
})
|
||||
|
@ -614,11 +614,11 @@ func TestVaultCAProvider_CrossSignCA(t *testing.T) {
|
|||
})
|
||||
|
||||
testutil.RunStep(t, "swap", func(t *testing.T) {
|
||||
root, err := provider2.GenerateRoot()
|
||||
root, err := provider2.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
assertCorrectKeyType(t, tc.CSRKeyType, root.PEM)
|
||||
|
||||
intPEM, err := provider2.ActiveIntermediate()
|
||||
intPEM, err := provider2.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
assertCorrectKeyType(t, tc.CSRKeyType, intPEM)
|
||||
|
||||
|
@ -738,7 +738,7 @@ func TestVaultProvider_SignIntermediateConsul(t *testing.T) {
|
|||
delegate := newMockDelegate(t, conf)
|
||||
provider1 := TestConsulProvider(t, delegate)
|
||||
require.NoError(t, provider1.Configure(testProviderConfig(conf)))
|
||||
_, err := provider1.GenerateRoot()
|
||||
_, err := provider1.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Ensure that we don't configure vault to try and mint leafs that
|
||||
|
@ -1076,9 +1076,9 @@ func TestVaultProvider_ReconfigureIntermediateTTL(t *testing.T) {
|
|||
t.Cleanup(provider.Stop)
|
||||
err = provider.Configure(makeProviderConfWithTTL("222h"))
|
||||
require.NoError(t, err)
|
||||
_, err = provider.GenerateRoot()
|
||||
_, err = provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
_, err = provider.GenerateIntermediate()
|
||||
_, err = provider.GenerateLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Attempt to update the ttl without permissions for the tune endpoint - shouldn't
|
||||
|
@ -1127,16 +1127,16 @@ func TestVaultCAProvider_GenerateIntermediate(t *testing.T) {
|
|||
"IntermediatePKIPath": "pki-intermediate/",
|
||||
})
|
||||
|
||||
orig, err := provider.ActiveIntermediate()
|
||||
orig, err := provider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
// This test was created to ensure that our calls to Vault
|
||||
// returns a new Intermediate certificate and further calls
|
||||
// to ActiveIntermediate return the same new cert.
|
||||
new, err := provider.GenerateIntermediate()
|
||||
// to ActiveLeafSigningCert return the same new cert.
|
||||
new, err := provider.GenerateLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
newActive, err := provider.ActiveIntermediate()
|
||||
newActive, err := provider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, new, newActive)
|
||||
|
@ -1153,7 +1153,7 @@ func TestVaultCAProvider_GenerateIntermediate_inSecondary(t *testing.T) {
|
|||
delegate := newMockDelegate(t, conf)
|
||||
primaryProvider := TestConsulProvider(t, delegate)
|
||||
require.NoError(t, primaryProvider.Configure(testProviderConfig(conf)))
|
||||
_, err := primaryProvider.GenerateRoot()
|
||||
_, err := primaryProvider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Ensure that we don't configure vault to try and mint leafs that
|
||||
|
@ -1187,14 +1187,14 @@ func TestVaultCAProvider_GenerateIntermediate_inSecondary(t *testing.T) {
|
|||
// Sign the CSR with primaryProvider.
|
||||
intermediatePEM, err := primaryProvider.SignIntermediate(csr)
|
||||
require.NoError(t, err)
|
||||
root, err := primaryProvider.GenerateRoot()
|
||||
root, err := primaryProvider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
rootPEM := root.PEM
|
||||
|
||||
// Give the new intermediate to provider to use.
|
||||
require.NoError(t, provider.SetIntermediate(intermediatePEM, rootPEM, issuerID))
|
||||
|
||||
origIntermediate, err = provider.ActiveIntermediate()
|
||||
origIntermediate, err = provider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
|
@ -1208,7 +1208,7 @@ func TestVaultCAProvider_GenerateIntermediate_inSecondary(t *testing.T) {
|
|||
// Sign the CSR with primaryProvider.
|
||||
intermediatePEM, err := primaryProvider.SignIntermediate(csr)
|
||||
require.NoError(t, err)
|
||||
root, err := primaryProvider.GenerateRoot()
|
||||
root, err := primaryProvider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
rootPEM := root.PEM
|
||||
|
||||
|
@ -1217,8 +1217,8 @@ func TestVaultCAProvider_GenerateIntermediate_inSecondary(t *testing.T) {
|
|||
|
||||
// This test was created to ensure that our calls to Vault
|
||||
// returns a new Intermediate certificate and further calls
|
||||
// to ActiveIntermediate return the same new cert.
|
||||
newActiveIntermediate, err := provider.ActiveIntermediate()
|
||||
// to ActiveLeafSigningCert return the same new cert.
|
||||
newActiveIntermediate, err := provider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotEqual(t, origIntermediate, newActiveIntermediate)
|
||||
|
@ -1358,9 +1358,9 @@ func createVaultProvider(t *testing.T, isPrimary bool, addr, token string, rawCo
|
|||
t.Cleanup(provider.Stop)
|
||||
require.NoError(t, provider.Configure(cfg))
|
||||
if isPrimary {
|
||||
_, err := provider.GenerateRoot()
|
||||
_, err := provider.GenerateCAChain()
|
||||
require.NoError(t, err)
|
||||
_, err = provider.GenerateIntermediate()
|
||||
_, err = provider.GenerateLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -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(pemValue, provider, clusterID string) (*structs.CARoot, error) {
|
||||
primaryCert, err := connect.ParseCert(pemValue)
|
||||
func newCARoot(rootResult ca.CAChainResult, provider, clusterID string) (*structs.CARoot, error) {
|
||||
primaryCert, err := connect.ParseCert(rootResult.PEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ func newCARoot(pemValue, provider, clusterID string) (*structs.CARoot, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error extracting root key info: %v", err)
|
||||
}
|
||||
return &structs.CARoot{
|
||||
caRoot := &structs.CARoot{
|
||||
ID: connect.CalculateCertFingerprint(primaryCert.Raw),
|
||||
Name: fmt.Sprintf("%s CA Primary Cert", providerPrettyName(provider)),
|
||||
SerialNumber: primaryCert.SerialNumber.Uint64(),
|
||||
|
@ -275,11 +275,18 @@ func newCARoot(pemValue, provider, clusterID string) (*structs.CARoot, error) {
|
|||
ExternalTrustDomain: clusterID,
|
||||
NotBefore: primaryCert.NotBefore,
|
||||
NotAfter: primaryCert.NotAfter,
|
||||
RootCert: lib.EnsureTrailingNewline(pemValue),
|
||||
RootCert: lib.EnsureTrailingNewline(rootResult.PEM),
|
||||
PrivateKeyType: keyType,
|
||||
PrivateKeyBits: keyBits,
|
||||
Active: true,
|
||||
}, nil
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// getCAProvider returns the currently active instance of the CA Provider,
|
||||
|
@ -482,25 +489,6 @@ func (c *CAManager) primaryInitialize(provider ca.Provider, conf *structs.CAConf
|
|||
if err := provider.Configure(pCfg); err != nil {
|
||||
return fmt.Errorf("error configuring provider: %v", err)
|
||||
}
|
||||
root, err := provider.GenerateRoot()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating CA root certificate: %v", err)
|
||||
}
|
||||
|
||||
rootCA, err := newCARoot(root.PEM, conf.Provider, conf.ClusterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: https://github.com/hashicorp/consul/issues/12386
|
||||
interPEM, err := provider.GenerateIntermediate()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating intermediate cert: %v", err)
|
||||
}
|
||||
intermediateCert, err := connect.ParseCert(interPEM)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting intermediate cert: %v", err)
|
||||
}
|
||||
|
||||
// If the provider has state to persist and it's changed or new then update
|
||||
// CAConfig.
|
||||
|
@ -520,24 +508,18 @@ func (c *CAManager) primaryInitialize(provider ca.Provider, conf *structs.CAConf
|
|||
}
|
||||
}
|
||||
|
||||
var rootUpdateRequired bool
|
||||
|
||||
// Versions prior to 1.9.3, 1.8.8, and 1.7.12 incorrectly used the primary
|
||||
// rootCA's subjectKeyID here instead of the intermediate. For
|
||||
// provider=consul this didn't matter since there are no intermediates in
|
||||
// the primaryDC, but for vault it does matter.
|
||||
expectedSigningKeyID := connect.EncodeSigningKeyID(intermediateCert.SubjectKeyId)
|
||||
if rootCA.SigningKeyID != expectedSigningKeyID {
|
||||
c.logger.Info("Correcting stored CARoot values",
|
||||
"previous-signing-key", rootCA.SigningKeyID, "updated-signing-key", expectedSigningKeyID)
|
||||
rootCA.SigningKeyID = expectedSigningKeyID
|
||||
rootUpdateRequired = true
|
||||
root, err := provider.GenerateCAChain()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating CA root certificate: %v", err)
|
||||
}
|
||||
|
||||
// Add the local leaf signing cert to the rootCA struct. This handles both
|
||||
// upgrades of existing state, and new rootCA.
|
||||
if c.getLeafSigningCertFromRoot(rootCA) != interPEM {
|
||||
rootCA.IntermediateCerts = append(rootCA.IntermediateCerts, interPEM)
|
||||
rootCA, err := newCARoot(root, conf.Provider, conf.ClusterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var rootUpdateRequired bool
|
||||
if len(rootCA.IntermediateCerts) > 0 {
|
||||
rootUpdateRequired = true
|
||||
}
|
||||
|
||||
|
@ -580,14 +562,10 @@ func (c *CAManager) primaryInitialize(provider ca.Provider, conf *structs.CAConf
|
|||
// sign leaf certificates in the local datacenter. The SubjectKeyId of the
|
||||
// returned cert should always match the SigningKeyID of the CARoot.
|
||||
//
|
||||
// TODO: fix the data model so that we don't need this complicated lookup to
|
||||
// find the leaf signing cert. See github.com/hashicorp/consul/issues/11347.
|
||||
// TODO: only used in tests. Remove if possible.
|
||||
func (c *CAManager) getLeafSigningCertFromRoot(root *structs.CARoot) string {
|
||||
if !c.isIntermediateUsedToSignLeaf() {
|
||||
return root.RootCert
|
||||
}
|
||||
if len(root.IntermediateCerts) == 0 {
|
||||
return ""
|
||||
return root.RootCert
|
||||
}
|
||||
return root.IntermediateCerts[len(root.IntermediateCerts)-1]
|
||||
}
|
||||
|
@ -599,7 +577,7 @@ func (c *CAManager) getLeafSigningCertFromRoot(root *structs.CARoot) string {
|
|||
// This method should only be called while the state lock is held by setting the
|
||||
// state to non-ready.
|
||||
func (c *CAManager) secondaryInitializeIntermediateCA(provider ca.Provider, config *structs.CAConfiguration) error {
|
||||
activeIntermediate, err := provider.ActiveIntermediate()
|
||||
activeIntermediate, err := provider.ActiveLeafSigningCert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -879,34 +857,6 @@ type ValidateConfigUpdater interface {
|
|||
}
|
||||
|
||||
func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.CARequest, config *structs.CAConfiguration) error {
|
||||
providerRoot, err := newProvider.GenerateRoot()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating CA root certificate: %v", err)
|
||||
}
|
||||
|
||||
newRootPEM := providerRoot.PEM
|
||||
newActiveRoot, err := newCARoot(newRootPEM, args.Config.Provider, args.Config.ClusterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: https://github.com/hashicorp/consul/issues/12386
|
||||
intermediate, err := newProvider.ActiveIntermediate()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching active intermediate: %w", err)
|
||||
}
|
||||
if intermediate == "" {
|
||||
intermediate, err = newProvider.GenerateIntermediate()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating intermediate: %w", err)
|
||||
}
|
||||
}
|
||||
if intermediate != newRootPEM {
|
||||
if err := setLeafSigningCert(newActiveRoot, intermediate); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// See if the provider needs to persist any state along with the config
|
||||
pState, err := newProvider.State()
|
||||
if err != nil {
|
||||
|
@ -914,6 +864,17 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C
|
|||
}
|
||||
args.Config.State = pState
|
||||
|
||||
providerRoot, 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -1042,8 +1003,12 @@ func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.C
|
|||
// This is only run for CAs that require an intermediary in the primary DC, such as Vault.
|
||||
// It should only be called while the state lock is held by setting the state to non-ready.
|
||||
func (c *CAManager) primaryRenewIntermediate(provider ca.Provider, newActiveRoot *structs.CARoot) error {
|
||||
p, ok := provider.(ca.PrimaryUsesIntermediate)
|
||||
if !ok {
|
||||
return fmt.Errorf("tried to renew intermediates for a provider that does not use them")
|
||||
}
|
||||
// Generate and sign an intermediate cert using the root CA.
|
||||
intermediatePEM, err := provider.GenerateIntermediate()
|
||||
intermediatePEM, err := p.GenerateLeafSigningCert()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating new intermediate cert: %v", err)
|
||||
}
|
||||
|
@ -1187,7 +1152,7 @@ func (c *CAManager) renewIntermediate(ctx context.Context, forceNow bool) error
|
|||
return nil
|
||||
}
|
||||
|
||||
activeIntermediate, err := provider.ActiveIntermediate()
|
||||
activeIntermediate, err := provider.ActiveLeafSigningCert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -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) GenerateRoot() (ca.RootResult, error) {
|
||||
return ca.RootResult{PEM: m.rootPEM}, nil
|
||||
func (m *mockCAProvider) GenerateCAChain() (ca.CAChainResult, error) {
|
||||
return ca.CAChainResult{PEM: m.rootPEM}, nil
|
||||
}
|
||||
func (m *mockCAProvider) GenerateIntermediateCSR() (string, string, error) {
|
||||
m.callbackCh <- "provider/GenerateIntermediateCSR"
|
||||
|
@ -270,13 +270,13 @@ func (m *mockCAProvider) SetIntermediate(intermediatePEM, rootPEM, _ string) err
|
|||
m.callbackCh <- "provider/SetIntermediate"
|
||||
return nil
|
||||
}
|
||||
func (m *mockCAProvider) ActiveIntermediate() (string, error) {
|
||||
func (m *mockCAProvider) ActiveLeafSigningCert() (string, error) {
|
||||
if m.intermediatePem == "" {
|
||||
return m.rootPEM, nil
|
||||
}
|
||||
return m.intermediatePem, nil
|
||||
}
|
||||
func (m *mockCAProvider) GenerateIntermediate() (string, error) { return "", nil }
|
||||
|
||||
func (m *mockCAProvider) Sign(*x509.CertificateRequest) (string, error) { return "", nil }
|
||||
func (m *mockCAProvider) SignIntermediate(*x509.CertificateRequest) (string, error) { return "", nil }
|
||||
func (m *mockCAProvider) CrossSignCA(*x509.Certificate) (string, error) { return "", nil }
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
msgpackrpc "github.com/hashicorp/consul-net-rpc/net-rpc-msgpackrpc"
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
|
@ -254,7 +254,7 @@ func TestCAManager_Initialize_Secondary(t *testing.T) {
|
|||
retry.Run(t, func(r *retry.R) {
|
||||
_, caRoot = getCAProviderWithLock(s1)
|
||||
secondaryProvider, _ = getCAProviderWithLock(s2)
|
||||
intermediatePEM, err = secondaryProvider.ActiveIntermediate()
|
||||
intermediatePEM, err = secondaryProvider.ActiveLeafSigningCert()
|
||||
require.NoError(r, err)
|
||||
|
||||
// Sanity check CA is using the correct key type
|
||||
|
@ -581,7 +581,7 @@ func TestConnectCA_ConfigurationSet_RootRotation_Secondary(t *testing.T) {
|
|||
|
||||
// Get the original intermediate
|
||||
secondaryProvider, _ := getCAProviderWithLock(s2)
|
||||
oldIntermediatePEM, err := secondaryProvider.ActiveIntermediate()
|
||||
oldIntermediatePEM, err := secondaryProvider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, oldIntermediatePEM)
|
||||
|
||||
|
@ -634,7 +634,7 @@ func TestConnectCA_ConfigurationSet_RootRotation_Secondary(t *testing.T) {
|
|||
// Wait for dc2's intermediate to be refreshed.
|
||||
var intermediatePEM string
|
||||
retry.Run(t, func(r *retry.R) {
|
||||
intermediatePEM, err = secondaryProvider.ActiveIntermediate()
|
||||
intermediatePEM, err = secondaryProvider.ActiveLeafSigningCert()
|
||||
r.Check(err)
|
||||
if intermediatePEM == oldIntermediatePEM {
|
||||
r.Fatal("not a new intermediate")
|
||||
|
@ -856,7 +856,7 @@ func TestCAManager_Initialize_Vault_FixesSigningKeyID_Primary(t *testing.T) {
|
|||
require.NotNil(r, provider)
|
||||
require.NotNil(r, activeRoot)
|
||||
|
||||
activeIntermediate, err := provider.ActiveIntermediate()
|
||||
activeIntermediate, err := provider.ActiveLeafSigningCert()
|
||||
require.NoError(r, err)
|
||||
|
||||
intermediateCert, err := connect.ParseCert(activeIntermediate)
|
||||
|
@ -957,7 +957,7 @@ func TestCAManager_Initialize_FixesSigningKeyID_Secondary(t *testing.T) {
|
|||
require.NotNil(r, provider)
|
||||
require.NotNil(r, activeRoot)
|
||||
|
||||
activeIntermediate, err := provider.ActiveIntermediate()
|
||||
activeIntermediate, err := provider.ActiveLeafSigningCert()
|
||||
require.NoError(r, err)
|
||||
|
||||
intermediateCert, err := connect.ParseCert(activeIntermediate)
|
||||
|
@ -1146,13 +1146,13 @@ func TestCAManager_Initialize_SecondaryBeforePrimary(t *testing.T) {
|
|||
require.Equal(r, roots1[0].RootCert, roots2[0].RootCert)
|
||||
|
||||
secondaryProvider, _ := getCAProviderWithLock(s2)
|
||||
inter, err := secondaryProvider.ActiveIntermediate()
|
||||
inter, err := secondaryProvider.ActiveLeafSigningCert()
|
||||
require.NoError(r, err)
|
||||
require.NotEmpty(r, inter, "should have valid intermediate")
|
||||
})
|
||||
|
||||
secondaryProvider, _ := getCAProviderWithLock(s2)
|
||||
intermediatePEM, err := secondaryProvider.ActiveIntermediate()
|
||||
intermediatePEM, err := secondaryProvider.ActiveLeafSigningCert()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, caRoot := getCAProviderWithLock(s1)
|
||||
|
@ -1354,20 +1354,24 @@ func TestConnectCA_ConfigurationSet_PersistsRoots(t *testing.T) {
|
|||
|
||||
func TestNewCARoot(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
pem string
|
||||
expected *structs.CARoot
|
||||
expectedErr string
|
||||
name string
|
||||
pem string
|
||||
intermediatePem string
|
||||
expected *structs.CARoot
|
||||
expectedErr string
|
||||
}
|
||||
|
||||
run := func(t *testing.T, tc testCase) {
|
||||
root, err := newCARoot(tc.pem, "provider-name", "cluster-id")
|
||||
root, err := newCARoot(ca.CAChainResult{
|
||||
PEM: tc.pem,
|
||||
IntermediatePEM: tc.intermediatePem,
|
||||
}, "provider-name", "cluster-id")
|
||||
if tc.expectedErr != "" {
|
||||
testutil.RequireErrorContains(t, err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, root, tc.expected)
|
||||
assert.DeepEqual(t, tc.expected, root)
|
||||
}
|
||||
|
||||
// Test certs can be generated with
|
||||
|
@ -1464,6 +1468,28 @@ func TestNewCARoot(t *testing.T) {
|
|||
PrivateKeyBits: 256,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Although the intermediate pem doesn't have pem as the issuer
|
||||
// as in a real certificate chain, we are testing that the IntermediateCerts
|
||||
// are being populated and that the signing key is from the intermediatePem.
|
||||
name: "pem with intermediate pem",
|
||||
pem: readTestData(t, "cert-with-rsa-4096-key.pem"),
|
||||
intermediatePem: readTestData(t, "cert-with-ec-256-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: "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, 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"),
|
||||
IntermediateCerts: []string{readTestData(t, "cert-with-ec-256-key.pem")},
|
||||
Active: true,
|
||||
PrivateKeyType: "rsa",
|
||||
PrivateKeyBits: 4096,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue