mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27:54 +00:00
Update recovery mode guard to account for migrating away from Shamir (#24443)
It is not sufficient to check that function setSeal in server.go does not return an "unwrap seal". For migrations away from a Shamir seal, NewCore constructor sets up an unwrap seal by calling method adjustForSealMigration. Factor out new method checkForSealMigration out of adjustForSealMigration so that NewCore can verify that there won't be a migration when returning early due to running in recovery mode.
This commit is contained in:
@@ -562,10 +562,6 @@ func (c *ServerCommand) runRecoveryMode() int {
|
||||
c.UI.Error(fmt.Sprintf("Error setting up seal: %v", setSealResponse.sealConfigError))
|
||||
return 1
|
||||
}
|
||||
if setSealResponse.unwrapSeal != nil {
|
||||
c.UI.Error("Recovery mode cannot be started with configuration for seal migration")
|
||||
return 1
|
||||
}
|
||||
barrierSeal = setSealResponse.barrierSeal
|
||||
|
||||
// Ensure that the seal finalizer is called, even if using verify-only
|
||||
@@ -580,6 +576,7 @@ func (c *ServerCommand) runRecoveryMode() int {
|
||||
Physical: backend,
|
||||
StorageType: config.Storage.Type,
|
||||
Seal: barrierSeal,
|
||||
UnwrapSeal: setSealResponse.unwrapSeal,
|
||||
LogLevel: config.LogLevel,
|
||||
Logger: c.logger,
|
||||
DisableMlock: config.DisableMlock,
|
||||
|
||||
188
vault/core.go
188
vault/core.go
@@ -1211,6 +1211,13 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
||||
|
||||
// For recovery mode we've now configured enough to return early.
|
||||
if c.recoveryMode {
|
||||
checkResult, err := c.checkForSealMigration(context.Background(), conf.UnwrapSeal)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error checking if a seal migration is needed")
|
||||
}
|
||||
if conf.UnwrapSeal != nil || checkResult == sealMigrationCheckAdjust {
|
||||
return nil, errors.New("cannot run in recovery mode when a seal migration is needed")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@@ -2905,6 +2912,87 @@ func setPhysicalSealConfig(ctx context.Context, c *Core, label, configPath strin
|
||||
return nil
|
||||
}
|
||||
|
||||
type sealMigrationCheckResult int
|
||||
|
||||
const (
|
||||
sealMigrationCheckError sealMigrationCheckResult = iota
|
||||
sealMigrationCheckSkip
|
||||
sealMigrationCheckAdjust
|
||||
sealMigrationCheckDoNotAjust
|
||||
)
|
||||
|
||||
func (c *Core) checkForSealMigration(ctx context.Context, unwrapSeal Seal) (sealMigrationCheckResult, error) {
|
||||
existBarrierSealConfig, _, err := c.PhysicalSealConfigs(ctx)
|
||||
if err != nil {
|
||||
return sealMigrationCheckError, fmt.Errorf("Error checking for existing seal: %s", err)
|
||||
}
|
||||
|
||||
// If we don't have an existing config or if it's the deprecated auto seal
|
||||
// which needs an upgrade, skip out
|
||||
if existBarrierSealConfig == nil || existBarrierSealConfig.Type == WrapperTypeHsmAutoDeprecated.String() {
|
||||
return sealMigrationCheckSkip, nil
|
||||
}
|
||||
|
||||
if unwrapSeal == nil {
|
||||
// With unwrapSeal==nil, either we're not migrating, or we're migrating
|
||||
// from shamir.
|
||||
|
||||
storedType := SealConfigType(existBarrierSealConfig.Type)
|
||||
configuredType := c.seal.BarrierSealConfigType()
|
||||
|
||||
switch {
|
||||
case storedType == configuredType:
|
||||
// We have the same barrier type and the unwrap seal is nil so we're not
|
||||
// migrating from same to same, IOW we assume it's not a migration.
|
||||
return sealMigrationCheckDoNotAjust, nil
|
||||
case configuredType == SealConfigTypeShamir:
|
||||
// The stored barrier config is not shamir, there is no disabled seal
|
||||
// in config, and either no configured seal (which equates to Shamir)
|
||||
// or an explicitly configured Shamir seal.
|
||||
return sealMigrationCheckError, fmt.Errorf("cannot seal migrate from %q to Shamir, no disabled seal in configuration",
|
||||
existBarrierSealConfig.Type)
|
||||
case storedType == SealConfigTypeShamir:
|
||||
// The configured seal is not Shamir, the stored seal config is Shamir.
|
||||
// This is a migration away from Shamir.
|
||||
|
||||
return sealMigrationCheckAdjust, nil
|
||||
case configuredType == SealConfigTypeMultiseal && server.IsMultisealSupported():
|
||||
// We are going from a single non-shamir seal to multiseal, and multi seal is supported.
|
||||
// This scenario is not considered a migration in the sense of requiring an unwrapSeal,
|
||||
// but we will update the stored SealConfig later (see Core.migrateMultiSealConfig).
|
||||
|
||||
return sealMigrationCheckDoNotAjust, nil
|
||||
case configuredType == SealConfigTypeMultiseal:
|
||||
// The configured seal is multiseal and we know the stored type is not shamir, thus
|
||||
// we are going from auto seal to multiseal.
|
||||
return sealMigrationCheckError, fmt.Errorf("cannot seal migrate from %q to %q, multiple seals are not supported",
|
||||
existBarrierSealConfig.Type, c.seal.BarrierSealConfigType())
|
||||
case storedType == SealConfigTypeMultiseal:
|
||||
// The stored type is multiseal and we know the type the configured type is not shamir,
|
||||
// thus we are going from multiseal to autoseal.
|
||||
//
|
||||
// This scenario is not considered a migration in the sense of requiring an unwrapSeal,
|
||||
// but we will update the stored SealConfig later (see Core.migrateMultiSealConfig).
|
||||
|
||||
return sealMigrationCheckDoNotAjust, nil
|
||||
default:
|
||||
// We know at this point that there is a configured non-Shamir seal,
|
||||
// that it does not match the stored non-Shamir seal config, and that
|
||||
// there is no explicitly disabled seal stanza.
|
||||
return sealMigrationCheckError, fmt.Errorf("cannot seal migrate from %q to %q, no disabled seal in configuration",
|
||||
existBarrierSealConfig.Type, c.seal.BarrierSealConfigType())
|
||||
}
|
||||
} else {
|
||||
// If we're not coming from Shamir we expect the previous seal to be
|
||||
// in the config and disabled.
|
||||
|
||||
if unwrapSeal.BarrierSealConfigType() == SealConfigTypeShamir {
|
||||
return sealMigrationCheckError, errors.New("Shamir seals cannot be set disabled (they should simply not be set)")
|
||||
}
|
||||
return sealMigrationCheckDoNotAjust, nil
|
||||
}
|
||||
}
|
||||
|
||||
// adjustForSealMigration takes the unwrapSeal, which is nil if (a) we're not
|
||||
// configured for seal migration or (b) we might be doing a seal migration away
|
||||
// from shamir. It will only be non-nil if there is a configured seal with
|
||||
@@ -2926,81 +3014,41 @@ func setPhysicalSealConfig(ctx context.Context, c *Core, label, configPath strin
|
||||
// to write the new barrier/recovery stored seal config.
|
||||
func (c *Core) adjustForSealMigration(unwrapSeal Seal) error {
|
||||
ctx := context.Background()
|
||||
|
||||
checkResult, err := c.checkForSealMigration(ctx, unwrapSeal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch checkResult {
|
||||
case sealMigrationCheckSkip:
|
||||
// If we don't have an existing config or if it's the deprecated auto seal
|
||||
// which needs an upgrade, skip out
|
||||
return nil
|
||||
|
||||
case sealMigrationCheckAdjust:
|
||||
// The configured seal is not Shamir, the stored seal config is Shamir.
|
||||
// This is a migration away from Shamir.
|
||||
|
||||
// See note about creating a SealGenerationInfo for the unwrap seal in
|
||||
// function setSeal in server.go.
|
||||
sealAccess, err := vaultseal.NewAccessFromWrapper(c.logger, aeadwrapper.NewShamirWrapper(), SealConfigTypeShamir.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unwrapSeal = NewDefaultSeal(sealAccess)
|
||||
|
||||
case sealMigrationCheckDoNotAjust:
|
||||
// unwrapSeal stays as is
|
||||
if unwrapSeal == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
existBarrierSealConfig, existRecoverySealConfig, err := c.PhysicalSealConfigs(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error checking for existing seal: %s", err)
|
||||
}
|
||||
|
||||
// If we don't have an existing config or if it's the deprecated auto seal
|
||||
// which needs an upgrade, skip out
|
||||
if existBarrierSealConfig == nil || existBarrierSealConfig.Type == WrapperTypeHsmAutoDeprecated.String() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if unwrapSeal == nil {
|
||||
// With unwrapSeal==nil, either we're not migrating, or we're migrating
|
||||
// from shamir.
|
||||
|
||||
storedType := SealConfigType(existBarrierSealConfig.Type)
|
||||
configuredType := c.seal.BarrierSealConfigType()
|
||||
|
||||
switch {
|
||||
case storedType == configuredType:
|
||||
// We have the same barrier type and the unwrap seal is nil so we're not
|
||||
// migrating from same to same, IOW we assume it's not a migration.
|
||||
return nil
|
||||
case configuredType == SealConfigTypeShamir:
|
||||
// The stored barrier config is not shamir, there is no disabled seal
|
||||
// in config, and either no configured seal (which equates to Shamir)
|
||||
// or an explicitly configured Shamir seal.
|
||||
return fmt.Errorf("cannot seal migrate from %q to Shamir, no disabled seal in configuration",
|
||||
existBarrierSealConfig.Type)
|
||||
case storedType == SealConfigTypeShamir:
|
||||
// The configured seal is not Shamir, the stored seal config is Shamir.
|
||||
// This is a migration away from Shamir.
|
||||
|
||||
// See note about creating a SealGenerationInfo for the unwrap seal in
|
||||
// function setSeal in server.go.
|
||||
sealAccess, err := vaultseal.NewAccessFromWrapper(c.logger, aeadwrapper.NewShamirWrapper(), SealConfigTypeShamir.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unwrapSeal = NewDefaultSeal(sealAccess)
|
||||
case configuredType == SealConfigTypeMultiseal && server.IsMultisealSupported():
|
||||
// We are going from a single non-shamir seal to multiseal, and multi seal is supported.
|
||||
// This scenario is not considered a migration in the sense of requiring an unwrapSeal,
|
||||
// but we will update the stored SealConfig later (see Core.migrateMultiSealConfig).
|
||||
|
||||
return nil
|
||||
case configuredType == SealConfigTypeMultiseal:
|
||||
// The configured seal is multiseal and we know the stored type is not shamir, thus
|
||||
// we are going from auto seal to multiseal.
|
||||
return fmt.Errorf("cannot seal migrate from %q to %q, multiple seals are not supported",
|
||||
existBarrierSealConfig.Type, c.seal.BarrierSealConfigType())
|
||||
case storedType == SealConfigTypeMultiseal:
|
||||
// The stored type is multiseal and we know the type the configured type is not shamir,
|
||||
// thus we are going from multiseal to autoseal.
|
||||
//
|
||||
// This scenario is not considered a migration in the sense of requiring an unwrapSeal,
|
||||
// but we will update the stored SealConfig later (see Core.migrateMultiSealConfig).
|
||||
|
||||
return nil
|
||||
default:
|
||||
// We know at this point that there is a configured non-Shamir seal,
|
||||
// that it does not match the stored non-Shamir seal config, and that
|
||||
// there is no explicitly disabled seal stanza.
|
||||
return fmt.Errorf("cannot seal migrate from %q to %q, no disabled seal in configuration",
|
||||
existBarrierSealConfig.Type, c.seal.BarrierSealConfigType())
|
||||
}
|
||||
} else {
|
||||
// If we're not coming from Shamir we expect the previous seal to be
|
||||
// in the config and disabled.
|
||||
|
||||
if unwrapSeal.BarrierSealConfigType() == SealConfigTypeShamir {
|
||||
return errors.New("Shamir seals cannot be set disabled (they should simply not be set)")
|
||||
}
|
||||
}
|
||||
|
||||
// If we've reached this point it's a migration attempt and we should have both
|
||||
// c.migrationInfo.seal (old seal) and c.seal (new seal) populated.
|
||||
unwrapSeal.SetCore(c)
|
||||
|
||||
Reference in New Issue
Block a user