Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ca: clearly identify methods that are primary-only or secondary-only #11338

Merged
merged 3 commits into from
Nov 1, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 56 additions & 54 deletions agent/consul/leader_connect_ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ func (e *caStateError) Error() string {
return fmt.Sprintf("CA is already in state %q", e.Current)
}

// setPrimaryRoots updates the most recently seen roots from the primary.
func (c *CAManager) setPrimaryRoots(newRoots structs.IndexedCARoots) error {
// secondarySetPrimaryRoots updates the most recently seen roots from the primary.
func (c *CAManager) secondarySetPrimaryRoots(newRoots structs.IndexedCARoots) error {
c.stateLock.Lock()
defer c.stateLock.Unlock()

Expand All @@ -185,7 +185,7 @@ func (c *CAManager) setPrimaryRoots(newRoots structs.IndexedCARoots) error {
return nil
}

func (c *CAManager) getPrimaryRoots() structs.IndexedCARoots {
func (c *CAManager) secondaryGetPrimaryRoots() structs.IndexedCARoots {
c.stateLock.Lock()
defer c.stateLock.Unlock()
return c.primaryRoots
Expand Down Expand Up @@ -401,11 +401,13 @@ func (c *CAManager) InitializeCA() (reterr error) {

c.setCAProvider(provider, nil)

// Run the root CA initialization if this is the primary DC.
if c.serverConf.PrimaryDatacenter == c.serverConf.Datacenter {
return c.initializeRootCA(provider, conf)
return c.primaryInitialize(provider, conf)
}
return c.secondaryInitialize(provider, conf)
}

func (c *CAManager) secondaryInitialize(provider ca.Provider, conf *structs.CAConfiguration) error {
// If this isn't the primary DC, run the secondary DC routine if the primary has already been upgraded to at least 1.6.0
versionOk, foundPrimary := ServersInDCMeetMinimumVersion(c.delegate, c.serverConf.PrimaryDatacenter, minMultiDCConnectVersion)
if !foundPrimary {
Expand All @@ -428,15 +430,15 @@ func (c *CAManager) InitializeCA() (reterr error) {
if err := c.delegate.forwardDC("ConnectCA.Roots", c.serverConf.PrimaryDatacenter, &args, &roots); err != nil {
return err
}
if err := c.setPrimaryRoots(roots); err != nil {
if err := c.secondarySetPrimaryRoots(roots); err != nil {
return err
}

// Configure the CA provider and initialize the intermediate certificate if necessary.
if err := c.initializeSecondaryProvider(provider, roots); err != nil {
if err := c.secondaryInitializeProvider(provider, roots); err != nil {
return fmt.Errorf("error configuring provider: %v", err)
}
if err := c.initializeSecondaryCA(provider, nil); err != nil {
if err := c.secondaryInitializeIntermediateCA(provider, nil); err != nil {
return err
}

Expand All @@ -462,9 +464,9 @@ func (c *CAManager) newProvider(conf *structs.CAConfiguration) (ca.Provider, err
}
}

// initializeRootCA runs the initialization logic for a root CA. It should only
// primaryInitialize runs the initialization logic for a root CA. It should only
// be called while the state lock is held by setting the state to non-ready.
func (c *CAManager) initializeRootCA(provider ca.Provider, conf *structs.CAConfiguration) error {
func (c *CAManager) primaryInitialize(provider ca.Provider, conf *structs.CAConfiguration) error {
pCfg := ca.ProviderConfig{
ClusterID: conf.ClusterID,
Datacenter: c.serverConf.Datacenter,
Expand Down Expand Up @@ -581,11 +583,11 @@ func (c *CAManager) initializeRootCA(provider ca.Provider, conf *structs.CAConfi
return nil
}

// initializeSecondaryCA runs the routine for generating an intermediate CA CSR and getting
// secondaryInitializeIntermediateCA runs the routine for generating an intermediate CA CSR and getting
// it signed by the primary DC if the root CA of the primary DC has changed since the last
// intermediate. It should only be called while the state lock is held by setting the state
// to non-ready.
func (c *CAManager) initializeSecondaryCA(provider ca.Provider, config *structs.CAConfiguration) error {
func (c *CAManager) secondaryInitializeIntermediateCA(provider ca.Provider, config *structs.CAConfiguration) error {
activeIntermediate, err := provider.ActiveIntermediate()
if err != nil {
return err
Expand Down Expand Up @@ -639,7 +641,7 @@ func (c *CAManager) initializeSecondaryCA(provider ca.Provider, config *structs.
// active one. We'll use this as a template to generate any new root
// representations meant for this secondary.
var newActiveRoot *structs.CARoot
primaryRoots := c.getPrimaryRoots()
primaryRoots := c.secondaryGetPrimaryRoots()
for _, root := range primaryRoots.Roots {
if root.ID == primaryRoots.ActiveRootID && root.Active {
newActiveRoot = root
Expand All @@ -665,7 +667,7 @@ func (c *CAManager) initializeSecondaryCA(provider ca.Provider, config *structs.

newIntermediate := false
if needsNewIntermediate {
if err := c.getIntermediateCASigned(provider, newActiveRoot); err != nil {
if err := c.secondaryRenewIntermediate(provider, newActiveRoot); err != nil {
return err
}
newIntermediate = true
Expand Down Expand Up @@ -810,7 +812,7 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error)

// Exit early if it's a no-op change
state := c.delegate.State()
confIdx, config, err := state.CAConfig(nil)
_, config, err := state.CAConfig(nil)
if err != nil {
return err
}
Expand Down Expand Up @@ -858,26 +860,29 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error)
return fmt.Errorf("error configuring provider: %v", err)
}

// Set up a defer to clean up the new provider if we exit early due to an error.
cleanupNewProvider := true
defer func() {
if cleanupNewProvider {
if err := newProvider.Cleanup(args.Config.Provider != config.Provider, args.Config.Config); err != nil {
c.logger.Warn("failed to clean up CA provider while handling startup failure", "provider", newProvider, "error", err)
}
cleanupNewProvider := func() {
if err := newProvider.Cleanup(args.Config.Provider != config.Provider, args.Config.Config); err != nil {
c.logger.Warn("failed to clean up CA provider while handling startup failure", "provider", newProvider, "error", err)
}
}()
}

// If this is a secondary, just check if the intermediate needs to be regenerated.
if c.serverConf.Datacenter != c.serverConf.PrimaryDatacenter {
if err := c.initializeSecondaryCA(newProvider, args.Config); err != nil {
if err := c.secondaryInitializeIntermediateCA(newProvider, args.Config); err != nil {
cleanupNewProvider()
return fmt.Errorf("Error updating secondary datacenter CA config: %v", err)
}
cleanupNewProvider = false
c.logger.Info("Secondary CA provider config updated")
return nil
}
if err := c.primaryUpdateRootCA(newProvider, args, config); err != nil {
cleanupNewProvider()
return err
}
return nil
}

func (c *CAManager) primaryUpdateRootCA(newProvider ca.Provider, args *structs.CARequest, config *structs.CAConfiguration) error {
if err := newProvider.GenerateRoot(); err != nil {
return fmt.Errorf("error generating CA root certificate: %v", err)
}
Expand All @@ -899,6 +904,7 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error)
}
args.Config.State = pState

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.
// If they don't match, begin the root rotation process.
Expand All @@ -919,11 +925,8 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error)
}

// If the config has been committed, update the local provider instance
cleanupNewProvider = false
c.setCAProvider(newProvider, newActiveRoot)

c.logger.Info("CA provider config updated")

return nil
}

Expand Down Expand Up @@ -1011,7 +1014,7 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error)

args.Op = structs.CAOpSetRootsAndConfig
args.Index = idx
args.Config.ModifyIndex = confIdx
args.Config.ModifyIndex = config.ModifyIndex
args.Roots = newRoots
resp, err := c.delegate.ApplyCARequest(args)
if err != nil {
Expand All @@ -1026,7 +1029,6 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error)

// If the config has been committed, update the local provider instance
// and call teardown on the old provider
cleanupNewProvider = false
c.setCAProvider(newProvider, newActiveRoot)

if err := oldProvider.Cleanup(args.Config.Provider != config.Provider, args.Config.Config); err != nil {
Expand All @@ -1038,10 +1040,10 @@ func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error)
return nil
}

// getIntermediateCAPrimary regenerates the intermediate cert in the primary datacenter.
// primaryRenewIntermediate regenerates the intermediate cert in the primary datacenter.
// 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) getIntermediateCAPrimary(provider ca.Provider, newActiveRoot *structs.CARoot) error {
func (c *CAManager) primaryRenewIntermediate(provider ca.Provider, newActiveRoot *structs.CARoot) error {
// Generate and sign an intermediate cert using the root CA.
intermediatePEM, err := provider.GenerateIntermediate()
if err != nil {
Expand All @@ -1062,9 +1064,9 @@ func (c *CAManager) getIntermediateCAPrimary(provider ca.Provider, newActiveRoot
return nil
}

// getIntermediateCASigned should only be called while the state lock is held by
// secondaryRenewIntermediate should only be called while the state lock is held by
// setting the state to non-ready.
func (c *CAManager) getIntermediateCASigned(provider ca.Provider, newActiveRoot *structs.CARoot) error {
func (c *CAManager) secondaryRenewIntermediate(provider ca.Provider, newActiveRoot *structs.CARoot) error {
csr, err := provider.GenerateIntermediateCSR()
if err != nil {
return err
Expand Down Expand Up @@ -1133,7 +1135,7 @@ func (c *CAManager) RenewIntermediate(ctx context.Context, isPrimary bool) error
return nil
}
// If this isn't the primary, make sure the CA has been initialized.
if !isPrimary && !c.configuredSecondaryCA() {
if !isPrimary && !c.secondaryIsCAConfigured() {
return fmt.Errorf("secondary CA is not yet configured.")
}

Expand Down Expand Up @@ -1172,9 +1174,9 @@ func (c *CAManager) RenewIntermediate(ctx context.Context, isPrimary bool) error
}

// Enough time has passed, go ahead with getting a new intermediate.
renewalFunc := c.getIntermediateCAPrimary
renewalFunc := c.primaryRenewIntermediate
if !isPrimary {
renewalFunc = c.getIntermediateCASigned
renewalFunc = c.secondaryRenewIntermediate
}
errCh := make(chan error, 1)
go func() {
Expand Down Expand Up @@ -1227,7 +1229,7 @@ func (c *CAManager) secondaryCARootWatch(ctx context.Context) error {
}

// Attempt to update the roots using the returned data.
if err := c.UpdateRoots(roots); err != nil {
if err := c.secondaryUpdateRoots(roots); err != nil {
return err
}
args.QueryOptions.MinQueryIndex = nextIndexVal(args.QueryOptions.MinQueryIndex, roots.QueryMeta.Index)
Expand All @@ -1242,17 +1244,17 @@ func (c *CAManager) secondaryCARootWatch(ctx context.Context) error {
return nil
}

// UpdateRoots updates the cached roots from the primary and regenerates the intermediate
// secondaryUpdateRoots updates the cached roots from the primary and regenerates the intermediate
// certificate if necessary.
func (c *CAManager) UpdateRoots(roots structs.IndexedCARoots) error {
func (c *CAManager) secondaryUpdateRoots(roots structs.IndexedCARoots) error {
// Update the state first to claim the 'lock'.
if _, err := c.setState(caStateReconfig, true); err != nil {
return err
}
defer c.setState(caStateInitialized, false)

// Update the cached primary roots now that the lock is held.
if err := c.setPrimaryRoots(roots); err != nil {
if err := c.secondarySetPrimaryRoots(roots); err != nil {
return err
}

Expand All @@ -1263,32 +1265,32 @@ func (c *CAManager) UpdateRoots(roots structs.IndexedCARoots) error {
// this happens when leadership is being revoked and this go routine will be stopped
return nil
}
if !c.configuredSecondaryCA() {
if !c.secondaryIsCAConfigured() {
versionOk, primaryFound := ServersInDCMeetMinimumVersion(c.delegate, c.serverConf.PrimaryDatacenter, minMultiDCConnectVersion)
if !primaryFound {
return fmt.Errorf("Primary datacenter is unreachable - deferring secondary CA initialization")
}

if versionOk {
if err := c.initializeSecondaryProvider(provider, roots); err != nil {
if err := c.secondaryInitializeProvider(provider, roots); err != nil {
return fmt.Errorf("Failed to initialize secondary CA provider: %v", err)
}
}
}

// Run the secondary CA init routine to see if we need to request a new
// intermediate.
if c.configuredSecondaryCA() {
if err := c.initializeSecondaryCA(provider, nil); err != nil {
if c.secondaryIsCAConfigured() {
if err := c.secondaryInitializeIntermediateCA(provider, nil); err != nil {
return fmt.Errorf("Failed to initialize the secondary CA: %v", err)
}
}

return nil
}

// initializeSecondaryProvider configures the given provider for a secondary, non-root datacenter.
func (c *CAManager) initializeSecondaryProvider(provider ca.Provider, roots structs.IndexedCARoots) error {
// secondaryInitializeProvider configures the given provider for a secondary, non-root datacenter.
func (c *CAManager) secondaryInitializeProvider(provider ca.Provider, roots structs.IndexedCARoots) error {
if roots.TrustDomain == "" {
return fmt.Errorf("trust domain from primary datacenter is not initialized")
}
Expand All @@ -1310,11 +1312,11 @@ func (c *CAManager) initializeSecondaryProvider(provider ca.Provider, roots stru
return fmt.Errorf("error configuring provider: %v", err)
}

return c.setSecondaryCA()
return c.secondarySetCAConfigured()
}

// setSecondaryCA sets the flag for acting as a secondary CA to true.
func (c *CAManager) setSecondaryCA() error {
// secondarySetCAConfigured sets the flag for acting as a secondary CA to true.
func (c *CAManager) secondarySetCAConfigured() error {
c.stateLock.Lock()
defer c.stateLock.Unlock()

Expand All @@ -1327,8 +1329,8 @@ func (c *CAManager) setSecondaryCA() error {
return nil
}

// configuredSecondaryCA returns true if we have been initialized as a secondary datacenter's CA.
func (c *CAManager) configuredSecondaryCA() bool {
// secondaryIsCAConfigured returns true if we have been initialized as a secondary datacenter's CA.
func (c *CAManager) secondaryIsCAConfigured() bool {
c.stateLock.Lock()
defer c.stateLock.Unlock()
return c.actingSecondaryCA
Expand Down Expand Up @@ -1539,12 +1541,12 @@ func (c *CAManager) SignCertificate(csr *x509.CertificateRequest, spiffeID conne
return &reply, nil
}

func (ca *CAManager) checkExpired(pem string) error {
func (c *CAManager) checkExpired(pem string) error {
cert, err := connect.ParseCert(pem)
if err != nil {
return err
}
if cert.NotAfter.Before(ca.timeNow()) {
if cert.NotAfter.Before(c.timeNow()) {
return fmt.Errorf("certificate expired, expiration date: %s ", cert.NotAfter.String())
}
return nil
Expand Down