mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 19:17:58 +00:00
Unseal HA changes, CE side (#23192)
* Unseal HA changes, CE side * Transit wrapper update
This commit is contained in:
@@ -1275,6 +1275,9 @@ func (c *ServerCommand) Run(args []string) int {
|
|||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
if setSealResponse.sealConfigWarning != nil {
|
||||||
|
c.UI.Warn(fmt.Sprintf("Warnings during seal configuration: %v", setSealResponse.sealConfigWarning))
|
||||||
|
}
|
||||||
|
|
||||||
for _, seal := range setSealResponse.getCreatedSeals() {
|
for _, seal := range setSealResponse.getCreatedSeals() {
|
||||||
seal := seal // capture range variable
|
seal := seal // capture range variable
|
||||||
@@ -2557,7 +2560,8 @@ type SetSealResponse struct {
|
|||||||
unwrapSeal vault.Seal
|
unwrapSeal vault.Seal
|
||||||
|
|
||||||
// sealConfigError is present if there was an error configuring wrappers, other than KeyNotFound.
|
// sealConfigError is present if there was an error configuring wrappers, other than KeyNotFound.
|
||||||
sealConfigError error
|
sealConfigError error
|
||||||
|
sealConfigWarning error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SetSealResponse) getCreatedSeals() []*vault.Seal {
|
func (r *SetSealResponse) getCreatedSeals() []*vault.Seal {
|
||||||
@@ -2602,9 +2606,13 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
var sealConfigError error
|
var sealConfigError error
|
||||||
|
var sealConfigWarning error
|
||||||
recordSealConfigError := func(err error) {
|
recordSealConfigError := func(err error) {
|
||||||
sealConfigError = errors.Join(sealConfigError, err)
|
sealConfigError = errors.Join(sealConfigError, err)
|
||||||
}
|
}
|
||||||
|
recordSealConfigWarning := func(err error) {
|
||||||
|
sealConfigWarning = errors.Join(sealConfigWarning, err)
|
||||||
|
}
|
||||||
enabledSealWrappers := make([]*vaultseal.SealWrapper, 0)
|
enabledSealWrappers := make([]*vaultseal.SealWrapper, 0)
|
||||||
disabledSealWrappers := make([]*vaultseal.SealWrapper, 0)
|
disabledSealWrappers := make([]*vaultseal.SealWrapper, 0)
|
||||||
allSealKmsConfigs := make([]*configutil.KMS, 0)
|
allSealKmsConfigs := make([]*configutil.KMS, 0)
|
||||||
@@ -2615,6 +2623,7 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
}
|
}
|
||||||
sealWrapperInfoKeysMap := make(map[string]infoKeysAndMap)
|
sealWrapperInfoKeysMap := make(map[string]infoKeysAndMap)
|
||||||
|
|
||||||
|
configuredSeals := 0
|
||||||
for _, configSeal := range config.Seals {
|
for _, configSeal := range config.Seals {
|
||||||
sealTypeEnvVarName := "VAULT_SEAL_TYPE"
|
sealTypeEnvVarName := "VAULT_SEAL_TYPE"
|
||||||
if configSeal.Priority > 1 {
|
if configSeal.Priority > 1 {
|
||||||
@@ -2628,24 +2637,18 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
|
|
||||||
sealLogger := c.logger.ResetNamed(fmt.Sprintf("seal.%s", configSeal.Type))
|
sealLogger := c.logger.ResetNamed(fmt.Sprintf("seal.%s", configSeal.Type))
|
||||||
|
|
||||||
|
allSealKmsConfigs = append(allSealKmsConfigs, configSeal)
|
||||||
var wrapperInfoKeys []string
|
var wrapperInfoKeys []string
|
||||||
wrapperInfoMap := map[string]string{}
|
wrapperInfoMap := map[string]string{}
|
||||||
wrapper, wrapperConfigError := configutil.ConfigureWrapper(configSeal, &wrapperInfoKeys, &wrapperInfoMap, sealLogger)
|
wrapper, wrapperConfigError := configutil.ConfigureWrapper(configSeal, &wrapperInfoKeys, &wrapperInfoMap, sealLogger)
|
||||||
if wrapperConfigError != nil {
|
if wrapperConfigError == nil {
|
||||||
// It seems that we are checking for this particular error here is to distinguish between a
|
// for some reason configureWrapper in kms.go returns nil wrapper and nil error for wrapping.WrapperTypeShamir
|
||||||
// mis-configured seal vs one that fails for another reason. Apparently the only other reason is
|
if wrapper == nil {
|
||||||
// a key not found error. It seems the intention is for the key not found error to be returned
|
wrapper = aeadwrapper.NewShamirWrapper()
|
||||||
// as a seal specific error later
|
|
||||||
if !errwrap.ContainsType(wrapperConfigError, new(logical.KeyNotFoundError)) {
|
|
||||||
return nil, fmt.Errorf("error parsing Seal configuration: %s", wrapperConfigError)
|
|
||||||
} else {
|
|
||||||
sealLogger.Error("error configuring seal", "name", configSeal.Name, "err", wrapperConfigError)
|
|
||||||
recordSealConfigError(wrapperConfigError)
|
|
||||||
}
|
}
|
||||||
}
|
configuredSeals++
|
||||||
// for some reason configureWrapper in kms.go returns nil wrapper and nil error for wrapping.WrapperTypeShamir
|
} else {
|
||||||
if wrapper == nil && wrapperConfigError == nil {
|
recordSealConfigWarning(fmt.Errorf("error configuring seal: %v", wrapperConfigError))
|
||||||
wrapper = aeadwrapper.NewShamirWrapper()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealWrapper := vaultseal.NewSealWrapper(
|
sealWrapper := vaultseal.NewSealWrapper(
|
||||||
@@ -2654,6 +2657,7 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
configSeal.Name,
|
configSeal.Name,
|
||||||
configSeal.Type,
|
configSeal.Type,
|
||||||
configSeal.Disabled,
|
configSeal.Disabled,
|
||||||
|
wrapperConfigError == nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
if configSeal.Disabled {
|
if configSeal.Disabled {
|
||||||
@@ -2661,7 +2665,6 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
} else {
|
} else {
|
||||||
enabledSealWrappers = append(enabledSealWrappers, sealWrapper)
|
enabledSealWrappers = append(enabledSealWrappers, sealWrapper)
|
||||||
}
|
}
|
||||||
allSealKmsConfigs = append(allSealKmsConfigs, configSeal)
|
|
||||||
|
|
||||||
sealWrapperInfoKeysMap[sealWrapper.Name] = infoKeysAndMap{
|
sealWrapperInfoKeysMap[sealWrapper.Name] = infoKeysAndMap{
|
||||||
keys: wrapperInfoKeys,
|
keys: wrapperInfoKeys,
|
||||||
@@ -2669,6 +2672,12 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(enabledSealWrappers) == 0 && len(disabledSealWrappers) == 0 && sealConfigWarning != nil {
|
||||||
|
// All of them errored out, so warnings are now errors
|
||||||
|
recordSealConfigError(sealConfigWarning)
|
||||||
|
sealConfigWarning = nil
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Set the info keys, this modifies the function arguments `info` and `infoKeys`
|
// Set the info keys, this modifies the function arguments `info` and `infoKeys`
|
||||||
// TODO(SEALHA): Why are we doing this? What is its use?
|
// TODO(SEALHA): Why are we doing this? What is its use?
|
||||||
@@ -2724,10 +2733,11 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
sealLogger := c.logger
|
sealLogger := c.logger
|
||||||
switch {
|
switch {
|
||||||
case len(enabledSealWrappers) == 0:
|
case len(enabledSealWrappers) == 0:
|
||||||
return nil, errors.New("no enabled Seals in configuration")
|
return nil, errors.Join(sealConfigWarning, errors.New("no enabled Seals in configuration"))
|
||||||
|
case configuredSeals == 0:
|
||||||
|
return nil, errors.Join(sealConfigWarning, errors.New("no seals were successfully initialized"))
|
||||||
case containsShamir(enabledSealWrappers) && containsShamir(disabledSealWrappers):
|
case containsShamir(enabledSealWrappers) && containsShamir(disabledSealWrappers):
|
||||||
return nil, errors.New("shamir seals cannot be set disabled (they should simply not be set)")
|
return nil, errors.Join(sealConfigWarning, errors.New("shamir seals cannot be set disabled (they should simply not be set)"))
|
||||||
|
|
||||||
case len(enabledSealWrappers) == 1 && containsShamir(enabledSealWrappers):
|
case len(enabledSealWrappers) == 1 && containsShamir(enabledSealWrappers):
|
||||||
// The barrier seal is Shamir. If there are any disabled seals, then we put them all in the same
|
// The barrier seal is Shamir. If there are any disabled seals, then we put them all in the same
|
||||||
@@ -2747,7 +2757,9 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
// so just put enabled and disabled wrappers on the same seal Access
|
// so just put enabled and disabled wrappers on the same seal Access
|
||||||
allSealWrappers := append(enabledSealWrappers, disabledSealWrappers...)
|
allSealWrappers := append(enabledSealWrappers, disabledSealWrappers...)
|
||||||
barrierSeal = vault.NewAutoSeal(vaultseal.NewAccess(sealLogger, sealGenerationInfo, allSealWrappers))
|
barrierSeal = vault.NewAutoSeal(vaultseal.NewAccess(sealLogger, sealGenerationInfo, allSealWrappers))
|
||||||
|
if configuredSeals < len(enabledSealWrappers) {
|
||||||
|
c.UI.Warn("WARNING: running with fewer than all configured seals during unseal. Will not be fully highly available until errors are corrected and Vault restarted.")
|
||||||
|
}
|
||||||
case len(enabledSealWrappers) == 1:
|
case len(enabledSealWrappers) == 1:
|
||||||
// We may have multiple seals disabled, but we know Shamir is not one of them.
|
// We may have multiple seals disabled, but we know Shamir is not one of them.
|
||||||
barrierSeal = vault.NewAutoSeal(vaultseal.NewAccess(sealLogger, sealGenerationInfo, enabledSealWrappers))
|
barrierSeal = vault.NewAutoSeal(vaultseal.NewAccess(sealLogger, sealGenerationInfo, enabledSealWrappers))
|
||||||
@@ -2757,13 +2769,14 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
// We know there are multiple enabled seals and that the seal HA beta is not enabled
|
// We know there are multiple enabled seals and that the seal HA beta is not enabled
|
||||||
return nil, errors.New("error: more than one enabled seal found")
|
return nil, errors.Join(sealConfigWarning, errors.New("error: more than one enabled seal found"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SetSealResponse{
|
return &SetSealResponse{
|
||||||
barrierSeal: barrierSeal,
|
barrierSeal: barrierSeal,
|
||||||
unwrapSeal: unwrapSeal,
|
unwrapSeal: unwrapSeal,
|
||||||
sealConfigError: sealConfigError,
|
sealConfigError: sealConfigError,
|
||||||
|
sealConfigWarning: sealConfigWarning,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -93,7 +93,7 @@ require (
|
|||||||
github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault/v2 v2.0.8
|
github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault/v2 v2.0.8
|
||||||
github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.8
|
github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.8
|
||||||
github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7
|
github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7
|
||||||
github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.7
|
github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.8
|
||||||
github.com/hashicorp/go-memdb v1.3.4
|
github.com/hashicorp/go-memdb v1.3.4
|
||||||
github.com/hashicorp/go-msgpack v1.1.5
|
github.com/hashicorp/go-msgpack v1.1.5
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1995,8 +1995,8 @@ github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.8 h1:16I8OqBEuxZIo
|
|||||||
github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.8/go.mod h1:6QUMo5BrXAtbzSuZilqmx0A4px2u6PeFK7vfp2WIzeM=
|
github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms/v2 v2.0.8/go.mod h1:6QUMo5BrXAtbzSuZilqmx0A4px2u6PeFK7vfp2WIzeM=
|
||||||
github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7 h1:KeG3QGrbxbr2qAqCJdf3NR4ijAYwdcWLTmwSbR0yusM=
|
github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7 h1:KeG3QGrbxbr2qAqCJdf3NR4ijAYwdcWLTmwSbR0yusM=
|
||||||
github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7/go.mod h1:rXxYzjjGw4HltEwxPp9zYSRIo6R+rBf1MSPk01bvodc=
|
github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7/go.mod h1:rXxYzjjGw4HltEwxPp9zYSRIo6R+rBf1MSPk01bvodc=
|
||||||
github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.7 h1:G25tZFw/LrAzJWxvS0/BFI7V1xAP/UsAIsgBwiE0mwo=
|
github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.8 h1:uvdmC28xaqklqRQ3HWvq9HP4jX7Vy4M5JrJqAxfo5ig=
|
||||||
github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.7/go.mod h1:hxNA5oTfAvwPacWVg1axtF/lvTafwlAa6a6K4uzWHhw=
|
github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.8/go.mod h1:zHX8LhkrU/M8sJkIQ85Dsrg7aqNEonY1+l6MlUC+6O4=
|
||||||
github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c=
|
github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c=
|
||||||
github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
|
github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
|
||||||
github.com/hashicorp/go-metrics v0.5.1 h1:rfPwUqFU6uZXNvGl4hzjY8LEBsqFVU4si1H9/Hqck/U=
|
github.com/hashicorp/go-metrics v0.5.1 h1:rfPwUqFU6uZXNvGl4hzjY8LEBsqFVU4si1H9/Hqck/U=
|
||||||
|
|||||||
@@ -388,7 +388,17 @@ func GetOCIKMSKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[
|
|||||||
|
|
||||||
var GetTransitKMSFunc = func(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
|
var GetTransitKMSFunc = func(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
|
||||||
wrapper := transit.NewWrapper()
|
wrapper := transit.NewWrapper()
|
||||||
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config))...)
|
var prefix string
|
||||||
|
if p, ok := kms.Config["key_id_prefix"]; ok {
|
||||||
|
prefix = p
|
||||||
|
} else {
|
||||||
|
prefix = kms.Name
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(prefix, "/") {
|
||||||
|
prefix = prefix + "/"
|
||||||
|
}
|
||||||
|
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config),
|
||||||
|
transit.WithKeyIdPrefix(prefix))...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the error is any other than logical.KeyNotFoundError, return the error
|
// If the error is any other than logical.KeyNotFoundError, return the error
|
||||||
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
||||||
|
|||||||
@@ -5027,7 +5027,7 @@ func (c *Core) GetSealBackendStatus(ctx context.Context) (*SealBackendStatusResp
|
|||||||
if a, ok := c.seal.(*autoSeal); ok {
|
if a, ok := c.seal.(*autoSeal); ok {
|
||||||
r.Healthy = c.seal.Healthy()
|
r.Healthy = c.seal.Healthy()
|
||||||
var uhMin time.Time
|
var uhMin time.Time
|
||||||
for _, sealWrapper := range a.GetAllSealWrappersByPriority() {
|
for _, sealWrapper := range a.GetConfiguredSealWrappersByPriority() {
|
||||||
b := SealBackendStatus{
|
b := SealBackendStatus{
|
||||||
Name: sealWrapper.Name,
|
Name: sealWrapper.Name,
|
||||||
Healthy: sealWrapper.IsHealthy(),
|
Healthy: sealWrapper.IsHealthy(),
|
||||||
|
|||||||
@@ -6272,6 +6272,7 @@ func TestGetSealBackendStatus(t *testing.T) {
|
|||||||
Wrapper: aeadwrapper.NewShamirWrapper(),
|
Wrapper: aeadwrapper.NewShamirWrapper(),
|
||||||
SealConfigType: wrapping.WrapperTypeShamir.String(),
|
SealConfigType: wrapping.WrapperTypeShamir.String(),
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
|
Configured: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to setup test seal: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to setup test seal: %w", err).Error())
|
||||||
}
|
}
|
||||||
access.GetAllSealWrappersByPriority()[0].Name = existingConfig.Name
|
access.GetConfiguredSealWrappersByPriority()[0].Name = existingConfig.Name
|
||||||
|
|
||||||
testseal := NewDefaultSeal(access)
|
testseal := NewDefaultSeal(access)
|
||||||
testseal.SetCore(c)
|
testseal.SetCore(c)
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ const (
|
|||||||
StoredKeysSupportedShamirRoot
|
StoredKeysSupportedShamirRoot
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnconfiguredWrapper = errors.New("unconfigured wrapper")
|
||||||
|
ErrNoHealthySeals = errors.New("no healthy seals!")
|
||||||
|
)
|
||||||
|
|
||||||
func (s StoredKeysSupport) String() string {
|
func (s StoredKeysSupport) String() string {
|
||||||
switch s {
|
switch s {
|
||||||
case StoredKeysNotSupported:
|
case StoredKeysNotSupported:
|
||||||
@@ -204,9 +209,12 @@ type Access interface {
|
|||||||
SetShamirSealKey([]byte) error
|
SetShamirSealKey([]byte) error
|
||||||
GetShamirKeyBytes(ctx context.Context) ([]byte, error)
|
GetShamirKeyBytes(ctx context.Context) ([]byte, error)
|
||||||
|
|
||||||
// GetAllSealWrappersByPriority returns all the SealWrapper for all the seal wrappers, including disabled ones.
|
// GetConfiguredSealWrappersByPriority returns all the SealWrappers including disabled and unconfigured wrappers.
|
||||||
GetAllSealWrappersByPriority() []*SealWrapper
|
GetAllSealWrappersByPriority() []*SealWrapper
|
||||||
|
|
||||||
|
// GetConfiguredSealWrappersByPriority returns all the configured SealWrappers for all the seal wrappers, including disabled ones.
|
||||||
|
GetConfiguredSealWrappersByPriority() []*SealWrapper
|
||||||
|
|
||||||
// GetEnabledSealWrappersByPriority returns the SealWrapper for the enabled seal wrappers.
|
// GetEnabledSealWrappersByPriority returns the SealWrapper for the enabled seal wrappers.
|
||||||
GetEnabledSealWrappersByPriority() []*SealWrapper
|
GetEnabledSealWrappersByPriority() []*SealWrapper
|
||||||
|
|
||||||
@@ -274,46 +282,60 @@ func NewAccessFromSealWrappers(logger hclog.Logger, generation uint64, rewrapped
|
|||||||
// The SealWrapper created uses the seal config type as the name, has priority set to 1 and the
|
// The SealWrapper created uses the seal config type as the name, has priority set to 1 and the
|
||||||
// disabled flag set to false.
|
// disabled flag set to false.
|
||||||
func NewAccessFromWrapper(logger hclog.Logger, wrapper wrapping.Wrapper, sealConfigType string) (Access, error) {
|
func NewAccessFromWrapper(logger hclog.Logger, wrapper wrapping.Wrapper, sealConfigType string) (Access, error) {
|
||||||
sealWrapper := NewSealWrapper(wrapper, 1, sealConfigType, sealConfigType, false)
|
sealWrapper := NewSealWrapper(wrapper, 1, sealConfigType, sealConfigType, false, true)
|
||||||
|
|
||||||
return NewAccessFromSealWrappers(logger, 1, true, []*SealWrapper{sealWrapper})
|
return NewAccessFromSealWrappers(logger, 1, true, []*SealWrapper{sealWrapper})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *access) GetAllSealWrappersByPriority() []*SealWrapper {
|
func (a *access) GetAllSealWrappersByPriority() []*SealWrapper {
|
||||||
return a.filterSealWrappers(enabledAndDisabled, healthyAndUnhealthy)
|
return a.filterSealWrappers(allWrappers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *access) GetConfiguredSealWrappersByPriority() []*SealWrapper {
|
||||||
|
return a.filterSealWrappers(configuredWrappers, allWrappers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *access) GetEnabledSealWrappersByPriority() []*SealWrapper {
|
func (a *access) GetEnabledSealWrappersByPriority() []*SealWrapper {
|
||||||
return a.filterSealWrappers(enabledOnly, healthyAndUnhealthy)
|
return a.filterSealWrappers(configuredWrappers, enabledWrappers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *access) AllSealWrappersHealthy() bool {
|
func (a *access) AllSealWrappersHealthy() bool {
|
||||||
return len(a.wrappersByPriority) == len(a.filterSealWrappers(enabledAndDisabled, healthyOnly))
|
return len(a.wrappersByPriority) == len(a.filterSealWrappers(configuredWrappers, healthyWrappers))
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type sealWrapperFilter func(*SealWrapper) bool
|
||||||
enabledFilter bool
|
|
||||||
healthyFilter bool
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
func allWrappers(wrapper *SealWrapper) bool {
|
||||||
enabledOnly = enabledFilter(true)
|
return true
|
||||||
enabledAndDisabled = !enabledOnly
|
}
|
||||||
healthyOnly = healthyFilter(true)
|
|
||||||
healthyAndUnhealthy = !healthyOnly
|
|
||||||
)
|
|
||||||
|
|
||||||
func (a *access) filterSealWrappers(enabled enabledFilter, healthy healthyFilter) []*SealWrapper {
|
func healthyWrappers(wrapper *SealWrapper) bool {
|
||||||
ret := make([]*SealWrapper, 0, len(a.wrappersByPriority))
|
return wrapper.IsHealthy()
|
||||||
for _, sw := range a.wrappersByPriority {
|
}
|
||||||
switch {
|
|
||||||
case enabled == enabledOnly && sw.Disabled:
|
func enabledWrappers(wrapper *SealWrapper) bool {
|
||||||
continue
|
return !wrapper.Disabled
|
||||||
case healthy == healthyOnly && !sw.IsHealthy():
|
}
|
||||||
continue
|
|
||||||
default:
|
func configuredWrappers(wrapper *SealWrapper) bool {
|
||||||
ret = append(ret, sw)
|
return wrapper.Configured
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a slice of wrappers who satisfy all filters
|
||||||
|
func (a *access) filterSealWrappers(filters ...sealWrapperFilter) []*SealWrapper {
|
||||||
|
return filterSealWrappers(a.wrappersByPriority, filters...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterSealWrappers(wrappers []*SealWrapper, filters ...sealWrapperFilter) []*SealWrapper {
|
||||||
|
ret := make([]*SealWrapper, 0, len(wrappers))
|
||||||
|
outer:
|
||||||
|
for _, sw := range wrappers {
|
||||||
|
for _, f := range filters {
|
||||||
|
if !f(sw) {
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ret = append(ret, sw)
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@@ -336,7 +358,7 @@ func (a *access) GetEnabledWrappers() []wrapping.Wrapper {
|
|||||||
|
|
||||||
func (a *access) Init(ctx context.Context, options ...wrapping.Option) error {
|
func (a *access) Init(ctx context.Context, options ...wrapping.Option) error {
|
||||||
var keyIds []string
|
var keyIds []string
|
||||||
for _, sealWrapper := range a.GetAllSealWrappersByPriority() {
|
for _, sealWrapper := range a.GetConfiguredSealWrappersByPriority() {
|
||||||
if initWrapper, ok := sealWrapper.Wrapper.(wrapping.InitFinalizer); ok {
|
if initWrapper, ok := sealWrapper.Wrapper.(wrapping.InitFinalizer); ok {
|
||||||
if err := initWrapper.Init(ctx, options...); err != nil {
|
if err := initWrapper.Init(ctx, options...); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -390,11 +412,12 @@ const (
|
|||||||
// Encrypt uses the underlying seal to encrypt the plaintext and returns it.
|
// Encrypt uses the underlying seal to encrypt the plaintext and returns it.
|
||||||
func (a *access) Encrypt(ctx context.Context, plaintext []byte, options ...wrapping.Option) (*MultiWrapValue, map[string]error) {
|
func (a *access) Encrypt(ctx context.Context, plaintext []byte, options ...wrapping.Option) (*MultiWrapValue, map[string]error) {
|
||||||
// Note that we do not encrypt with disabled wrappers. Disabled wrappers are only used to decrypt.
|
// Note that we do not encrypt with disabled wrappers. Disabled wrappers are only used to decrypt.
|
||||||
enabledWrappersByPriority := a.filterSealWrappers(enabledOnly, healthyOnly)
|
candidateWrappers := a.filterSealWrappers(enabledWrappers, healthyWrappers)
|
||||||
if len(enabledWrappersByPriority) == 0 {
|
if len(candidateWrappers) == 0 {
|
||||||
// If all seals are unhealthy, try any way since a seal may have recovered
|
// If all seals are unhealthy, try any way since a seal may have recovered
|
||||||
enabledWrappersByPriority = a.filterSealWrappers(enabledOnly, healthyAndUnhealthy)
|
candidateWrappers = a.filterSealWrappers(enabledWrappers)
|
||||||
}
|
}
|
||||||
|
enabledWrappersByPriority := filterSealWrappers(candidateWrappers, configuredWrappers)
|
||||||
|
|
||||||
type result struct {
|
type result struct {
|
||||||
name string
|
name string
|
||||||
@@ -474,6 +497,13 @@ GATHER_RESULTS:
|
|||||||
a.keyIdSet.set(ret)
|
a.keyIdSet.set(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add errors for unconfigured wrappers
|
||||||
|
for _, sw := range candidateWrappers {
|
||||||
|
if !sw.Configured {
|
||||||
|
errs[sw.Name] = ErrUnconfiguredWrapper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret, errs
|
return ret, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,10 +550,13 @@ func (a *access) Decrypt(ctx context.Context, ciphertext *MultiWrapValue, option
|
|||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
wrappersByPriority := a.filterSealWrappers(enabledAndDisabled, healthyOnly)
|
wrappersByPriority := a.filterSealWrappers(configuredWrappers, healthyWrappers)
|
||||||
if len(wrappersByPriority) == 0 {
|
if len(wrappersByPriority) == 0 {
|
||||||
// If all seals are unhealthy, try any way since a seal may have recovered
|
// If all seals are unhealthy, try any way since a seal may have recovered
|
||||||
wrappersByPriority = a.filterSealWrappers(enabledAndDisabled, healthyAndUnhealthy)
|
wrappersByPriority = a.filterSealWrappers(configuredWrappers)
|
||||||
|
}
|
||||||
|
if len(wrappersByPriority) == 0 {
|
||||||
|
return nil, false, ErrNoHealthySeals
|
||||||
}
|
}
|
||||||
|
|
||||||
type result struct {
|
type result struct {
|
||||||
@@ -534,23 +567,45 @@ func (a *access) Decrypt(ctx context.Context, ciphertext *MultiWrapValue, option
|
|||||||
}
|
}
|
||||||
resultCh := make(chan *result)
|
resultCh := make(chan *result)
|
||||||
|
|
||||||
decrypt := func(sealWrapper *SealWrapper) {
|
reportResult := func(name string, plaintext []byte, oldKey bool, err error) {
|
||||||
pt, oldKey, err := a.tryDecrypt(ctx, sealWrapper, blobInfoMap, options)
|
|
||||||
resultCh <- &result{
|
resultCh <- &result{
|
||||||
name: sealWrapper.Name,
|
name: name,
|
||||||
pt: pt,
|
pt: plaintext,
|
||||||
oldKey: oldKey,
|
oldKey: oldKey,
|
||||||
err: err,
|
err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decrypt := func(sealWrapper *SealWrapper) {
|
||||||
|
pt, oldKey, err := a.tryDecrypt(ctx, sealWrapper, blobInfoMap, options)
|
||||||
|
reportResult(sealWrapper.Name, pt, oldKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Start goroutines to decrypt the value
|
// Start goroutines to decrypt the value
|
||||||
for i, sealWrapper := range wrappersByPriority {
|
|
||||||
|
first := wrappersByPriority[0]
|
||||||
|
// First, if we only have one slot, try matching by keyId
|
||||||
|
if len(blobInfoMap) == 1 {
|
||||||
|
outer:
|
||||||
|
for k := range blobInfoMap {
|
||||||
|
for _, sealWrapper := range wrappersByPriority {
|
||||||
|
keyId, err := sealWrapper.Wrapper.KeyId(ctx)
|
||||||
|
if err != nil {
|
||||||
|
reportResult(sealWrapper.Name, nil, false, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if keyId == k {
|
||||||
|
first = sealWrapper
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go decrypt(first)
|
||||||
|
for _, sealWrapper := range wrappersByPriority {
|
||||||
sealWrapper := sealWrapper
|
sealWrapper := sealWrapper
|
||||||
if i == 0 {
|
if sealWrapper != first {
|
||||||
// start the highest priority wrapper right away
|
|
||||||
go decrypt(sealWrapper)
|
|
||||||
} else {
|
|
||||||
timer := time.AfterFunc(wrapperDecryptHighPriorityHeadStart, func() {
|
timer := time.AfterFunc(wrapperDecryptHighPriorityHeadStart, func() {
|
||||||
decrypt(sealWrapper)
|
decrypt(sealWrapper)
|
||||||
})
|
})
|
||||||
@@ -667,7 +722,7 @@ func JoinSealWrapErrors(msg string, errorMap map[string]error) error {
|
|||||||
func (a *access) Finalize(ctx context.Context, options ...wrapping.Option) error {
|
func (a *access) Finalize(ctx context.Context, options ...wrapping.Option) error {
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
for _, w := range a.GetAllSealWrappersByPriority() {
|
for _, w := range a.GetConfiguredSealWrappersByPriority() {
|
||||||
if finalizeWrapper, ok := w.Wrapper.(wrapping.InitFinalizer); ok {
|
if finalizeWrapper, ok := w.Wrapper.(wrapping.InitFinalizer); ok {
|
||||||
if err := finalizeWrapper.Finalize(ctx, options...); err != nil {
|
if err := finalizeWrapper.Finalize(ctx, options...); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ func NewTestSeal(opts *TestSealOpts) (Access, []*ToggleableWrapper) {
|
|||||||
fmt.Sprintf("%s-%d", opts.Name, i+1),
|
fmt.Sprintf("%s-%d", opts.Name, i+1),
|
||||||
wrapperType.String(),
|
wrapperType.String(),
|
||||||
false,
|
false,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +89,7 @@ func NewToggleableTestSeal(opts *TestSealOpts) (Access, []func(error)) {
|
|||||||
fmt.Sprintf("%s-%d", opts.Name, i+1),
|
fmt.Sprintf("%s-%d", opts.Name, i+1),
|
||||||
wrapperType.String(),
|
wrapperType.String(),
|
||||||
false,
|
false,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
funcs[i] = w.SetError
|
funcs[i] = w.SetError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ type SealWrapper struct {
|
|||||||
// Disabled indicates, when true indicates that this wrapper should only be used for decryption.
|
// Disabled indicates, when true indicates that this wrapper should only be used for decryption.
|
||||||
Disabled bool
|
Disabled bool
|
||||||
|
|
||||||
|
// Configured indicates the wrapper was successfully configured at initialization
|
||||||
|
Configured bool
|
||||||
|
|
||||||
// hcLock protects lastHealthy, lastSeenHealthy, and healthy.
|
// hcLock protects lastHealthy, lastSeenHealthy, and healthy.
|
||||||
// Do not modify those fields directly, use setHealth instead.
|
// Do not modify those fields directly, use setHealth instead.
|
||||||
// Do not access these fields directly, use getHealth instead.
|
// Do not access these fields directly, use getHealth instead.
|
||||||
@@ -35,16 +38,21 @@ type SealWrapper struct {
|
|||||||
healthy bool
|
healthy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSealWrapper(wrapper wrapping.Wrapper, priority int, name string, sealConfigType string, disabled bool) *SealWrapper {
|
func NewSealWrapper(wrapper wrapping.Wrapper, priority int, name string, sealConfigType string, disabled bool, configured bool) *SealWrapper {
|
||||||
ret := &SealWrapper{
|
ret := &SealWrapper{
|
||||||
Wrapper: wrapper,
|
Wrapper: wrapper,
|
||||||
Priority: priority,
|
Priority: priority,
|
||||||
Name: name,
|
Name: name,
|
||||||
SealConfigType: sealConfigType,
|
SealConfigType: sealConfigType,
|
||||||
Disabled: disabled,
|
Disabled: disabled,
|
||||||
|
Configured: configured,
|
||||||
}
|
}
|
||||||
|
|
||||||
setHealth(ret, true, time.Now(), ret.lastHealthCheck)
|
if configured {
|
||||||
|
setHealth(ret, true, time.Now(), ret.lastHealthCheck)
|
||||||
|
} else {
|
||||||
|
setHealth(ret, false, time.Now(), ret.lastHealthCheck)
|
||||||
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,10 @@ type autoSeal struct {
|
|||||||
core *Core
|
core *Core
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
|
|
||||||
allSealsHealthy bool
|
unsealedWithUnhealthySeal bool
|
||||||
hcLock sync.RWMutex
|
allSealsHealthy bool
|
||||||
healthCheckStop chan struct{}
|
hcLock sync.RWMutex
|
||||||
|
healthCheckStop chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we are implementing the Seal interface
|
// Ensure we are implementing the Seal interface
|
||||||
@@ -193,7 +194,7 @@ func (d *autoSeal) BarrierConfig(ctx context.Context) (*SealConfig, error) {
|
|||||||
|
|
||||||
barrierTypeUpgradeCheck(d.BarrierSealConfigType(), conf)
|
barrierTypeUpgradeCheck(d.BarrierSealConfigType(), conf)
|
||||||
|
|
||||||
if conf.Type != d.BarrierSealConfigType().String() {
|
if conf.Type != d.BarrierSealConfigType().String() && conf.Type != "multiseal" {
|
||||||
d.logger.Error("barrier seal type does not match loaded type", "seal_type", conf.Type, "loaded_type", d.BarrierSealConfigType())
|
d.logger.Error("barrier seal type does not match loaded type", "seal_type", conf.Type, "loaded_type", d.BarrierSealConfigType())
|
||||||
return nil, fmt.Errorf("barrier seal type of %q does not match loaded type of %q", conf.Type, d.BarrierSealConfigType())
|
return nil, fmt.Errorf("barrier seal type of %q does not match loaded type of %q", conf.Type, d.BarrierSealConfigType())
|
||||||
}
|
}
|
||||||
@@ -471,10 +472,16 @@ func (d *autoSeal) StartHealthCheck() {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
d.logger.Trace("performing a seal health check")
|
d.logger.Trace("performing a seal health check")
|
||||||
|
for _, sw := range d.Access.GetAllSealWrappersByPriority() {
|
||||||
|
if !sw.Configured {
|
||||||
|
d.logger.Warn(`WARNING: running in degraded mode, one or more seals failed to configure at
|
||||||
|
startup, and Vault is running with fewer than the number of configured seals for high availability. Please correct the
|
||||||
|
error and restart Vault.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
allHealthy := true
|
allHealthy := true
|
||||||
allUnhealthy := true
|
allUnhealthy := true
|
||||||
for _, sealWrapper := range d.Access.GetAllSealWrappersByPriority() {
|
for _, sealWrapper := range d.Access.GetConfiguredSealWrappersByPriority() {
|
||||||
mLabels := []metrics.Label{{Name: "seal_wrapper_name", Value: sealWrapper.Name}}
|
mLabels := []metrics.Label{{Name: "seal_wrapper_name", Value: sealWrapper.Name}}
|
||||||
|
|
||||||
wasHealthy := sealWrapper.IsHealthy()
|
wasHealthy := sealWrapper.IsHealthy()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal {
|
|||||||
switch opts.StoredKeys {
|
switch opts.StoredKeys {
|
||||||
case seal.StoredKeysSupportedShamirRoot:
|
case seal.StoredKeysSupportedShamirRoot:
|
||||||
sealAccess, err := seal.NewAccessFromSealWrappers(logger, opts.Generation, true, []*seal.SealWrapper{
|
sealAccess, err := seal.NewAccessFromSealWrappers(logger, opts.Generation, true, []*seal.SealWrapper{
|
||||||
seal.NewSealWrapper(aead.NewShamirWrapper(), 1, "shamir", "shamir", false),
|
seal.NewSealWrapper(aead.NewShamirWrapper(), 1, "shamir", "shamir", false, true),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error creating test seal", err)
|
t.Fatal("error creating test seal", err)
|
||||||
@@ -33,7 +33,7 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal {
|
|||||||
return newSeal
|
return newSeal
|
||||||
case seal.StoredKeysNotSupported:
|
case seal.StoredKeysNotSupported:
|
||||||
sealAccess, err := seal.NewAccessFromSealWrappers(logger, opts.Generation, true, []*seal.SealWrapper{
|
sealAccess, err := seal.NewAccessFromSealWrappers(logger, opts.Generation, true, []*seal.SealWrapper{
|
||||||
seal.NewSealWrapper(aead.NewShamirWrapper(), 1, "shamir", "shamir", false),
|
seal.NewSealWrapper(aead.NewShamirWrapper(), 1, "shamir", "shamir", false, true),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error creating test seal", err)
|
t.Fatal("error creating test seal", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user