diff --git a/command/server_sealgenerationinfo_test.go b/command/server_sealgenerationinfo_test.go index 7e7b0995d1..bcd9e1fff1 100644 --- a/command/server_sealgenerationinfo_test.go +++ b/command/server_sealgenerationinfo_test.go @@ -96,7 +96,7 @@ func TestMultiSealCases(t *testing.T) { }, }, isErrorExpected: true, - expectedErrorMsg: "cannot add more than one seal", + expectedErrorMsg: "Initializing a cluster or enabling multi-seal on an existing cluster must occur with a single seal before adding additional seals", sealHaBetaEnabled: true, }, // none_to_multi_with_disabled_seals_with_beta @@ -117,7 +117,7 @@ func TestMultiSealCases(t *testing.T) { }, }, isErrorExpected: true, - expectedErrorMsg: "cannot add more than one seal", + expectedErrorMsg: "Initializing a cluster or enabling multi-seal on an existing cluster must occur with a single seal before adding additional seals", sealHaBetaEnabled: true, }, // none_to_multi_with_disabled_seals_no_beta @@ -759,6 +759,72 @@ func TestMultiSealCases(t *testing.T) { hasPartiallyWrappedPaths: false, isErrorExpected: false, }, + // migrate from non-beta single seal to single seal + { + name: "none_to_single_seal", + existingSealGenInfo: nil, + newSealGenInfo: &seal.SealGenerationInfo{ + Generation: 1, + Seals: []*configutil.KMS{ + { + Type: "shamir", + Name: "shamir", + Priority: 1, + }, + }, + }, + isRewrapped: true, + hasPartiallyWrappedPaths: false, + isErrorExpected: false, + }, + // migrate from non-beta single seal to multi seal, with one disabled, so perform an old style migration + // we do not support this use-case at this time so trap the error + { + name: "none_to_multiple_seals_one_disabled", + existingSealGenInfo: nil, + newSealGenInfo: &seal.SealGenerationInfo{ + Generation: 1, + Seals: []*configutil.KMS{ + { + Type: "pkcs11", + Name: "autoSeal", + }, + { + Type: "pkcs11", + Name: "autoSeal", + Disabled: true, + }, + }, + }, + isRewrapped: true, + hasPartiallyWrappedPaths: false, + isErrorExpected: true, + expectedErrorMsg: "Initializing a cluster or enabling multi-seal on an existing cluster must occur with a single seal before adding additional seals", + }, + // migrate from non-beta single seal to multi seal + { + name: "none_to_multiple_seals", + existingSealGenInfo: nil, + newSealGenInfo: &seal.SealGenerationInfo{ + Generation: 1, + Seals: []*configutil.KMS{ + { + Type: "pkcs11", + Name: "autoSeal1", + Priority: 1, + }, + { + Type: "pkcs11", + Name: "autoSeal2", + Priority: 2, + }, + }, + }, + isRewrapped: true, + hasPartiallyWrappedPaths: false, + isErrorExpected: true, + expectedErrorMsg: "Initializing a cluster or enabling multi-seal on an existing cluster must occur with a single seal before adding additional seals", + }, // have partially wrapped paths { name: "have_partially_wrapped_paths", diff --git a/vault/seal/seal.go b/vault/seal/seal.go index 32ab453c92..472539041b 100644 --- a/vault/seal/seal.go +++ b/vault/seal/seal.go @@ -62,32 +62,45 @@ type SealGenerationInfo struct { // Validate is used to sanity check the seal generation info being created func (sgi *SealGenerationInfo) Validate(existingSgi *SealGenerationInfo, hasPartiallyWrappedPaths bool) error { existingSealsLen := 0 - previousShamirConfigured := false - existingSealNameAndType := "[]" + numConfiguredSeals := len(sgi.Seals) configuredSealNameAndType := sealNameAndTypeAsStr(sgi.Seals) - if existingSgi != nil { - existingSealNameAndType = sealNameAndTypeAsStr(existingSgi.Seals) - if sgi.Generation == existingSgi.Generation { - if !haveMatchingSeals(sgi.Seals, existingSgi.Seals) { - return fmt.Errorf("existing seal generation is the same, but the configured seals are different\n"+ - "Existing seals: %v\n"+ - "Configured seals: %v", existingSealNameAndType, configuredSealNameAndType) - } - return nil + // If no previous generation info exists, make sure we perform the initial migration/setup + // check for enabled configured seals to allow an old style seal migration configuration + if existingSgi == nil { + if numConfiguredSeals > 1 { + return fmt.Errorf("Initializing a cluster or enabling multi-seal on an existing "+ + "cluster must occur with a single seal before adding additional seals\n"+ + "Configured seals: %v", configuredSealNameAndType) } - existingSealsLen = len(existingSgi.Seals) - for _, sealKmsConfig := range existingSgi.Seals { - if sealKmsConfig.Type == wrapping.WrapperTypeShamir.String() { - previousShamirConfigured = true - break - } - } + // No point in comparing anything more as we don't have any information around the + // existing seal if any actually existed + return nil + } - if !previousShamirConfigured && (!existingSgi.IsRewrapped() || hasPartiallyWrappedPaths) { - return errors.New("cannot make seal config changes while seal re-wrap is in progress, please revert any seal configuration changes") + existingSealNameAndType := sealNameAndTypeAsStr(existingSgi.Seals) + previousShamirConfigured := false + + if sgi.Generation == existingSgi.Generation { + if !haveMatchingSeals(sgi.Seals, existingSgi.Seals) { + return fmt.Errorf("existing seal generation is the same, but the configured seals are different\n"+ + "Existing seals: %v\n"+ + "Configured seals: %v", existingSealNameAndType, configuredSealNameAndType) } + return nil + } + + existingSealsLen = len(existingSgi.Seals) + for _, sealKmsConfig := range existingSgi.Seals { + if sealKmsConfig.Type == wrapping.WrapperTypeShamir.String() { + previousShamirConfigured = true + break + } + } + + if !previousShamirConfigured && (!existingSgi.IsRewrapped() || hasPartiallyWrappedPaths) { + return errors.New("cannot make seal config changes while seal re-wrap is in progress, please revert any seal configuration changes") } numSealsToAdd := 0 @@ -97,12 +110,12 @@ func (sgi *SealGenerationInfo) Validate(existingSgi *SealGenerationInfo, hasPart // be set disabled, so, the number of seals to add is always going to be the length // of new seal configs. if previousShamirConfigured { - numSealsToAdd = len(sgi.Seals) + numSealsToAdd = numConfiguredSeals } else { - numSealsToAdd = len(sgi.Seals) - existingSealsLen + numSealsToAdd = numConfiguredSeals - existingSealsLen } - numSealsToDelete := existingSealsLen - len(sgi.Seals) + numSealsToDelete := existingSealsLen - numConfiguredSeals switch { case numSealsToAdd > 1: return fmt.Errorf("cannot add more than one seal\n"+