mirror of
https://github.com/hashicorp/vault.git
synced 2025-11-30 23:21:10 +01:00
Protect SealWrapper health fields (#22740)
* Create accessors for SealWrapper fields protecteb by the lock. * Use NewSealWrapper constructor to create all seal wrappers.
This commit is contained in:
parent
07e76196ba
commit
5dc85c58c1
@ -2599,8 +2599,8 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
recordSealConfigError := func(err error) {
|
recordSealConfigError := func(err error) {
|
||||||
sealConfigError = errors.Join(sealConfigError, err)
|
sealConfigError = errors.Join(sealConfigError, 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)
|
||||||
|
|
||||||
type infoKeysAndMap struct {
|
type infoKeysAndMap struct {
|
||||||
@ -2642,13 +2642,13 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
wrapper = aeadwrapper.NewShamirWrapper()
|
wrapper = aeadwrapper.NewShamirWrapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealWrapper := vaultseal.SealWrapper{
|
sealWrapper := vaultseal.NewSealWrapper(
|
||||||
Wrapper: wrapper,
|
wrapper,
|
||||||
Priority: configSeal.Priority,
|
configSeal.Priority,
|
||||||
Name: configSeal.Name,
|
configSeal.Name,
|
||||||
SealConfigType: configSeal.Type,
|
configSeal.Type,
|
||||||
Disabled: configSeal.Disabled,
|
configSeal.Disabled,
|
||||||
}
|
)
|
||||||
|
|
||||||
if configSeal.Disabled {
|
if configSeal.Disabled {
|
||||||
disabledSealWrappers = append(disabledSealWrappers, sealWrapper)
|
disabledSealWrappers = append(disabledSealWrappers, sealWrapper)
|
||||||
@ -2666,20 +2666,21 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// 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?
|
||||||
appendWrapperInfoKeys := func(prefix string, sealWrappers []vaultseal.SealWrapper) {
|
appendWrapperInfoKeys := func(prefix string, sealWrappers []*vaultseal.SealWrapper) {
|
||||||
if len(sealWrappers) > 0 {
|
if len(sealWrappers) == 0 {
|
||||||
useName := false
|
return
|
||||||
if len(sealWrappers) > 1 {
|
}
|
||||||
useName = true
|
useName := false
|
||||||
|
if len(sealWrappers) > 1 {
|
||||||
|
useName = true
|
||||||
|
}
|
||||||
|
for _, sealWrapper := range sealWrappers {
|
||||||
|
if useName {
|
||||||
|
prefix = fmt.Sprintf("%s %s ", prefix, sealWrapper.Name)
|
||||||
}
|
}
|
||||||
for _, sealWrapper := range sealWrappers {
|
for _, k := range sealWrapperInfoKeysMap[sealWrapper.Name].keys {
|
||||||
if useName {
|
infoKeys = append(infoKeys, prefix+k)
|
||||||
prefix = fmt.Sprintf("%s %s ", prefix, sealWrapper.Name)
|
info[prefix+k] = sealWrapperInfoKeysMap[sealWrapper.Name].theMap[k]
|
||||||
}
|
|
||||||
for _, k := range sealWrapperInfoKeysMap[sealWrapper.Name].keys {
|
|
||||||
infoKeys = append(infoKeys, prefix+k)
|
|
||||||
info[prefix+k] = sealWrapperInfoKeysMap[sealWrapper.Name].theMap[k]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2697,7 +2698,7 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Create the Seals
|
// Create the Seals
|
||||||
|
|
||||||
containsShamir := func(sealWrappers []vaultseal.SealWrapper) bool {
|
containsShamir := func(sealWrappers []*vaultseal.SealWrapper) bool {
|
||||||
for _, si := range sealWrappers {
|
for _, si := range sealWrappers {
|
||||||
if vault.SealConfigTypeShamir.IsSameAs(si.SealConfigType) {
|
if vault.SealConfigTypeShamir.IsSameAs(si.SealConfigType) {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -73,13 +73,7 @@ func (tss *TransitSealServer) MakeSeal(t testing.T, key string) (vault.Seal, err
|
|||||||
t.Fatalf("error setting wrapper config: %v", err)
|
t.Fatalf("error setting wrapper config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
access, err := seal.NewAccessFromSealWrappers(tss.Logger, 1, true, []seal.SealWrapper{
|
access, err := seal.NewAccessFromWrapper(tss.Logger, transitSealWrapper, vault.SealConfigTypeTransit.String())
|
||||||
{
|
|
||||||
Wrapper: transitSealWrapper,
|
|
||||||
Priority: 1,
|
|
||||||
Name: "transit",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1113,13 +1113,7 @@ func CreateCore(conf *CoreConfig) (*Core, error) {
|
|||||||
wrapper := aeadwrapper.NewShamirWrapper()
|
wrapper := aeadwrapper.NewShamirWrapper()
|
||||||
wrapper.SetConfig(context.Background(), awskms.WithLogger(c.logger.Named("shamir")))
|
wrapper.SetConfig(context.Background(), awskms.WithLogger(c.logger.Named("shamir")))
|
||||||
|
|
||||||
access, err := vaultseal.NewAccessFromSealWrappers(c.logger, 1, true, []vaultseal.SealWrapper{
|
access, err := vaultseal.NewAccessFromWrapper(c.logger, wrapper, SealConfigTypeShamir.String())
|
||||||
{
|
|
||||||
Wrapper: wrapper,
|
|
||||||
Priority: 1,
|
|
||||||
Name: "shamir",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -2885,13 +2879,7 @@ func (c *Core) adjustForSealMigration(unwrapSeal Seal) error {
|
|||||||
|
|
||||||
// See note about creating a SealGenerationInfo for the unwrap seal in
|
// See note about creating a SealGenerationInfo for the unwrap seal in
|
||||||
// function setSeal in server.go.
|
// function setSeal in server.go.
|
||||||
sealAccess, err := vaultseal.NewAccessFromSealWrappers(c.logger, 1, true, []vaultseal.SealWrapper{
|
sealAccess, err := vaultseal.NewAccessFromWrapper(c.logger, aeadwrapper.NewShamirWrapper(), SealConfigTypeShamir.String())
|
||||||
{
|
|
||||||
Wrapper: aeadwrapper.NewShamirWrapper(),
|
|
||||||
Priority: 1,
|
|
||||||
Name: "shamir",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -3113,13 +3101,7 @@ func (c *Core) unsealKeyToRootKey(ctx context.Context, seal Seal, combinedKey []
|
|||||||
if useTestSeal {
|
if useTestSeal {
|
||||||
// Note that the seal generation should not matter, since the only thing we are doing with
|
// Note that the seal generation should not matter, since the only thing we are doing with
|
||||||
// this seal is calling GetStoredKeys (i.e. we are not encrypting anything).
|
// this seal is calling GetStoredKeys (i.e. we are not encrypting anything).
|
||||||
sealAccess, err := vaultseal.NewAccessFromSealWrappers(c.logger, 1, true, []vaultseal.SealWrapper{
|
sealAccess, err := vaultseal.NewAccessFromWrapper(c.logger, aeadwrapper.NewShamirWrapper(), SealConfigTypeShamir.String())
|
||||||
{
|
|
||||||
Wrapper: aeadwrapper.NewShamirWrapper(),
|
|
||||||
Priority: 1,
|
|
||||||
Name: "shamir",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup seal wrapper for test barrier config: %w", err)
|
return nil, fmt.Errorf("failed to setup seal wrapper for test barrier config: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4998,14 +4998,15 @@ func (c *Core) GetSealBackendStatus(ctx context.Context) (*SealBackendStatusResp
|
|||||||
for _, sealWrapper := range a.GetAllSealWrappersByPriority() {
|
for _, sealWrapper := range a.GetAllSealWrappersByPriority() {
|
||||||
b := SealBackendStatus{
|
b := SealBackendStatus{
|
||||||
Name: sealWrapper.Name,
|
Name: sealWrapper.Name,
|
||||||
Healthy: sealWrapper.Healthy,
|
Healthy: sealWrapper.IsHealthy(),
|
||||||
}
|
}
|
||||||
if !sealWrapper.Healthy {
|
if !sealWrapper.IsHealthy() {
|
||||||
if !sealWrapper.LastSeenHealthy.IsZero() {
|
lastSeenHealthy := sealWrapper.LastSeenHealthy()
|
||||||
b.UnhealthySince = sealWrapper.LastSeenHealthy.String()
|
if !lastSeenHealthy.IsZero() {
|
||||||
|
b.UnhealthySince = lastSeenHealthy.String()
|
||||||
}
|
}
|
||||||
if uhMin.IsZero() || uhMin.After(sealWrapper.LastSeenHealthy) {
|
if uhMin.IsZero() || uhMin.After(lastSeenHealthy) {
|
||||||
uhMin = sealWrapper.LastSeenHealthy
|
uhMin = lastSeenHealthy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.Backends = append(r.Backends, b)
|
r.Backends = append(r.Backends, b)
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2"
|
aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2"
|
||||||
|
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
"github.com/hashicorp/vault/helper/pgpkeys"
|
"github.com/hashicorp/vault/helper/pgpkeys"
|
||||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||||
@ -400,16 +401,12 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string)
|
|||||||
}
|
}
|
||||||
case c.seal.BarrierSealConfigType() == SealConfigTypeShamir:
|
case c.seal.BarrierSealConfigType() == SealConfigTypeShamir:
|
||||||
if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedShamirRoot {
|
if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedShamirRoot {
|
||||||
access, err := seal.NewAccessFromSealWrappers(c.logger, c.seal.GetAccess().Generation(), true, []seal.SealWrapper{
|
access, err := seal.NewAccessFromWrapper(c.logger, aeadwrapper.NewShamirWrapper(), SealConfigTypeShamir.String())
|
||||||
{
|
|
||||||
Wrapper: aeadwrapper.NewShamirWrapper(),
|
|
||||||
Priority: 1,
|
|
||||||
Name: existingConfig.Name,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
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
|
||||||
|
|
||||||
testseal := NewDefaultSeal(access)
|
testseal := NewDefaultSeal(access)
|
||||||
testseal.SetCore(c)
|
testseal.SetCore(c)
|
||||||
err = testseal.GetAccess().SetShamirSealKey(recoveredKey)
|
err = testseal.GetAccess().SetShamirSealKey(recoveredKey)
|
||||||
|
|||||||
@ -215,7 +215,7 @@ type access struct {
|
|||||||
|
|
||||||
var _ Access = (*access)(nil)
|
var _ Access = (*access)(nil)
|
||||||
|
|
||||||
func NewAccess(logger hclog.Logger, sealGenerationInfo *SealGenerationInfo, sealWrappers []SealWrapper) Access {
|
func NewAccess(logger hclog.Logger, sealGenerationInfo *SealGenerationInfo, sealWrappers []*SealWrapper) Access {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
logger = hclog.NewNullLogger()
|
logger = hclog.NewNullLogger()
|
||||||
}
|
}
|
||||||
@ -231,10 +231,7 @@ func NewAccess(logger hclog.Logger, sealGenerationInfo *SealGenerationInfo, seal
|
|||||||
}
|
}
|
||||||
a.wrappersByPriority = make([]*SealWrapper, len(sealWrappers))
|
a.wrappersByPriority = make([]*SealWrapper, len(sealWrappers))
|
||||||
for i, sw := range sealWrappers {
|
for i, sw := range sealWrappers {
|
||||||
v := sw
|
a.wrappersByPriority[i] = sw
|
||||||
a.wrappersByPriority[i] = &v
|
|
||||||
v.Healthy = true
|
|
||||||
v.LastSeenHealthy = time.Now()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(a.wrappersByPriority, func(i int, j int) bool { return a.wrappersByPriority[i].Priority < a.wrappersByPriority[j].Priority })
|
sort.Slice(a.wrappersByPriority, func(i int, j int) bool { return a.wrappersByPriority[i].Priority < a.wrappersByPriority[j].Priority })
|
||||||
@ -242,7 +239,7 @@ func NewAccess(logger hclog.Logger, sealGenerationInfo *SealGenerationInfo, seal
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAccessFromSealWrappers(logger hclog.Logger, generation uint64, rewrapped bool, sealWrappers []SealWrapper) (Access, error) {
|
func NewAccessFromSealWrappers(logger hclog.Logger, generation uint64, rewrapped bool, sealWrappers []*SealWrapper) (Access, error) {
|
||||||
sealGenerationInfo := &SealGenerationInfo{
|
sealGenerationInfo := &SealGenerationInfo{
|
||||||
Generation: generation,
|
Generation: generation,
|
||||||
}
|
}
|
||||||
@ -262,6 +259,16 @@ func NewAccessFromSealWrappers(logger hclog.Logger, generation uint64, rewrapped
|
|||||||
return NewAccess(logger, sealGenerationInfo, sealWrappers), nil
|
return NewAccess(logger, sealGenerationInfo, sealWrappers), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAccessFromWrapper creates an enabled Access for a single wrapping.Wrapper.
|
||||||
|
// The Access has generation set to 1 and the rewrapped flag set to true.
|
||||||
|
// The SealWrapper created uses the seal config type as the name, has priority set to 1 and the
|
||||||
|
// disabled flag set to false.
|
||||||
|
func NewAccessFromWrapper(logger hclog.Logger, wrapper wrapping.Wrapper, sealConfigType string) (Access, error) {
|
||||||
|
sealWrapper := NewSealWrapper(wrapper, 1, sealConfigType, sealConfigType, false)
|
||||||
|
|
||||||
|
return NewAccessFromSealWrappers(logger, 1, true, []*SealWrapper{sealWrapper})
|
||||||
|
}
|
||||||
|
|
||||||
func (a *access) GetAllSealWrappersByPriority() []*SealWrapper {
|
func (a *access) GetAllSealWrappersByPriority() []*SealWrapper {
|
||||||
return copySealWrappers(a.wrappersByPriority, false)
|
return copySealWrappers(a.wrappersByPriority, false)
|
||||||
}
|
}
|
||||||
@ -276,9 +283,7 @@ func (a *access) AllSealWrappersHealthy() bool {
|
|||||||
if sw.Disabled {
|
if sw.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sw.HcLock.RLock()
|
if !sw.IsHealthy() {
|
||||||
defer sw.HcLock.RUnlock()
|
|
||||||
if !sw.Healthy {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,6 +366,7 @@ func (a *access) Encrypt(ctx context.Context, plaintext []byte, options ...wrapp
|
|||||||
errs := make(map[string]error)
|
errs := make(map[string]error)
|
||||||
|
|
||||||
for _, sealWrapper := range a.GetEnabledSealWrappersByPriority() {
|
for _, sealWrapper := range a.GetEnabledSealWrappersByPriority() {
|
||||||
|
now := time.Now()
|
||||||
var encryptErr error
|
var encryptErr error
|
||||||
defer func(now time.Time) {
|
defer func(now time.Time) {
|
||||||
metrics.MeasureSince([]string{"seal", "encrypt", "time"}, now)
|
metrics.MeasureSince([]string{"seal", "encrypt", "time"}, now)
|
||||||
@ -370,7 +376,7 @@ func (a *access) Encrypt(ctx context.Context, plaintext []byte, options ...wrapp
|
|||||||
metrics.IncrCounter([]string{"seal", "encrypt", "error"}, 1)
|
metrics.IncrCounter([]string{"seal", "encrypt", "error"}, 1)
|
||||||
metrics.IncrCounter([]string{"seal", sealWrapper.Name, "encrypt", "error"}, 1)
|
metrics.IncrCounter([]string{"seal", sealWrapper.Name, "encrypt", "error"}, 1)
|
||||||
}
|
}
|
||||||
}(time.Now())
|
}(now)
|
||||||
|
|
||||||
metrics.IncrCounter([]string{"seal", "encrypt"}, 1)
|
metrics.IncrCounter([]string{"seal", "encrypt"}, 1)
|
||||||
metrics.IncrCounter([]string{"seal", sealWrapper.Name, "encrypt"}, 1)
|
metrics.IncrCounter([]string{"seal", sealWrapper.Name, "encrypt"}, 1)
|
||||||
@ -381,7 +387,7 @@ func (a *access) Encrypt(ctx context.Context, plaintext []byte, options ...wrapp
|
|||||||
a.logger.Trace("error encrypting with seal", "seal", sealWrapper.Name, "err", encryptErr)
|
a.logger.Trace("error encrypting with seal", "seal", sealWrapper.Name, "err", encryptErr)
|
||||||
|
|
||||||
errs[sealWrapper.Name] = encryptErr
|
errs[sealWrapper.Name] = encryptErr
|
||||||
sealWrapper.Healthy = false
|
sealWrapper.SetHealthy(false, now)
|
||||||
} else {
|
} else {
|
||||||
a.logger.Trace("encrypted value using seal", "seal", sealWrapper.Name, "keyId", ciphertext.KeyInfo.KeyId)
|
a.logger.Trace("encrypted value using seal", "seal", sealWrapper.Name, "keyId", ciphertext.KeyInfo.KeyId)
|
||||||
|
|
||||||
|
|||||||
@ -43,14 +43,21 @@ func NewTestSealOpts(opts *TestSealOpts) *TestSealOpts {
|
|||||||
func NewTestSeal(opts *TestSealOpts) (Access, []*ToggleableWrapper) {
|
func NewTestSeal(opts *TestSealOpts) (Access, []*ToggleableWrapper) {
|
||||||
opts = NewTestSealOpts(opts)
|
opts = NewTestSealOpts(opts)
|
||||||
wrappers := make([]*ToggleableWrapper, opts.WrapperCount)
|
wrappers := make([]*ToggleableWrapper, opts.WrapperCount)
|
||||||
sealWrappers := make([]SealWrapper, opts.WrapperCount)
|
sealWrappers := make([]*SealWrapper, opts.WrapperCount)
|
||||||
|
ctx := context.Background()
|
||||||
for i := 0; i < opts.WrapperCount; i++ {
|
for i := 0; i < opts.WrapperCount; i++ {
|
||||||
wrappers[i] = &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)}
|
wrappers[i] = &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)}
|
||||||
sealWrappers[i] = SealWrapper{
|
wrapperType, err := wrappers[i].Type(ctx)
|
||||||
Wrapper: wrappers[i],
|
if err != nil {
|
||||||
Priority: i + 1,
|
panic(err)
|
||||||
Name: fmt.Sprintf("%s-%d", opts.Name, i+1),
|
|
||||||
}
|
}
|
||||||
|
sealWrappers[i] = NewSealWrapper(
|
||||||
|
wrappers[i],
|
||||||
|
i+1,
|
||||||
|
fmt.Sprintf("%s-%d", opts.Name, i+1),
|
||||||
|
wrapperType.String(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealAccess, err := NewAccessFromSealWrappers(nil, opts.Generation, true, sealWrappers)
|
sealAccess, err := NewAccessFromSealWrappers(nil, opts.Generation, true, sealWrappers)
|
||||||
@ -64,16 +71,24 @@ func NewToggleableTestSeal(opts *TestSealOpts) (Access, []func(error)) {
|
|||||||
opts = NewTestSealOpts(opts)
|
opts = NewTestSealOpts(opts)
|
||||||
|
|
||||||
wrappers := make([]*ToggleableWrapper, opts.WrapperCount)
|
wrappers := make([]*ToggleableWrapper, opts.WrapperCount)
|
||||||
sealWrappers := make([]SealWrapper, opts.WrapperCount)
|
sealWrappers := make([]*SealWrapper, opts.WrapperCount)
|
||||||
funcs := make([]func(error), opts.WrapperCount)
|
funcs := make([]func(error), opts.WrapperCount)
|
||||||
|
ctx := context.Background()
|
||||||
for i := 0; i < opts.WrapperCount; i++ {
|
for i := 0; i < opts.WrapperCount; i++ {
|
||||||
w := &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)}
|
w := &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)}
|
||||||
wrappers[i] = w
|
wrapperType, err := w.Type(ctx)
|
||||||
sealWrappers[i] = SealWrapper{
|
if err != nil {
|
||||||
Wrapper: wrappers[i],
|
panic(err)
|
||||||
Priority: i + 1,
|
|
||||||
Name: fmt.Sprintf("%s-%d", opts.Name, i+1),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wrappers[i] = w
|
||||||
|
sealWrappers[i] = NewSealWrapper(
|
||||||
|
wrappers[i],
|
||||||
|
i+1,
|
||||||
|
fmt.Sprintf("%s-%d", opts.Name, i+1),
|
||||||
|
wrapperType.String(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
funcs[i] = w.SetError
|
funcs[i] = w.SetError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SealWrapper contains a Wrapper and related information needed by the seal that uses it.
|
// SealWrapper contains a Wrapper and related information needed by the seal that uses it.
|
||||||
|
// Use NewSealWrapper to construct new instances, do not do it directly.
|
||||||
type SealWrapper struct {
|
type SealWrapper struct {
|
||||||
Wrapper wrapping.Wrapper
|
Wrapper wrapping.Wrapper
|
||||||
Priority int
|
Priority int
|
||||||
@ -25,17 +26,69 @@ 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
|
||||||
|
|
||||||
HcLock sync.RWMutex
|
// hcLock protects lastHealthy, lastSeenHealthy, and healthy. Do not modify those fields directly, use setHealth instead.
|
||||||
LastHealthCheck time.Time
|
hcLock sync.RWMutex
|
||||||
LastSeenHealthy time.Time
|
lastHealthCheck time.Time
|
||||||
Healthy bool
|
lastSeenHealthy time.Time
|
||||||
|
healthy bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSealWrapper(wrapper wrapping.Wrapper, priority int, name string, sealConfigType string, disabled bool) *SealWrapper {
|
||||||
|
ret := &SealWrapper{
|
||||||
|
Wrapper: wrapper,
|
||||||
|
Priority: priority,
|
||||||
|
Name: name,
|
||||||
|
SealConfigType: sealConfigType,
|
||||||
|
Disabled: disabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.setHealth(true, time.Now(), ret.lastHealthCheck)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sw *SealWrapper) rlock() func() {
|
||||||
|
sw.hcLock.RLock()
|
||||||
|
return sw.hcLock.RUnlock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sw *SealWrapper) lock() func() {
|
||||||
|
sw.hcLock.Lock()
|
||||||
|
return sw.hcLock.Unlock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sw *SealWrapper) SetHealthy(healthy bool, checkTime time.Time) {
|
||||||
|
unlock := sw.lock()
|
||||||
|
defer unlock()
|
||||||
|
|
||||||
|
wasHealthy := sw.healthy
|
||||||
|
lastHealthy := sw.lastSeenHealthy
|
||||||
|
if !wasHealthy && healthy {
|
||||||
|
lastHealthy = checkTime
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.setHealth(healthy, lastHealthy, checkTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sw *SealWrapper) IsHealthy() bool {
|
func (sw *SealWrapper) IsHealthy() bool {
|
||||||
sw.HcLock.RLock()
|
unlock := sw.rlock()
|
||||||
defer sw.HcLock.RUnlock()
|
defer unlock()
|
||||||
|
|
||||||
return sw.Healthy
|
return sw.healthy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sw *SealWrapper) LastSeenHealthy() time.Time {
|
||||||
|
unlock := sw.rlock()
|
||||||
|
defer unlock()
|
||||||
|
|
||||||
|
return sw.lastSeenHealthy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sw *SealWrapper) LastHealthCheck() time.Time {
|
||||||
|
unlock := sw.rlock()
|
||||||
|
defer unlock()
|
||||||
|
|
||||||
|
return sw.lastHealthCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -46,13 +99,11 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (sw *SealWrapper) CheckHealth(ctx context.Context, checkTime time.Time) error {
|
func (sw *SealWrapper) CheckHealth(ctx context.Context, checkTime time.Time) error {
|
||||||
sw.HcLock.Lock()
|
unlock := sw.lock()
|
||||||
defer sw.HcLock.Unlock()
|
defer unlock()
|
||||||
|
|
||||||
sw.LastHealthCheck = checkTime
|
|
||||||
|
|
||||||
// Assume the wrapper is unhealthy, if we make it to the end we'll set it to true
|
// Assume the wrapper is unhealthy, if we make it to the end we'll set it to true
|
||||||
sw.Healthy = false
|
sw.setHealth(false, sw.lastSeenHealthy, checkTime)
|
||||||
|
|
||||||
testVal := fmt.Sprintf("Heartbeat %d", mathrand.Intn(1000))
|
testVal := fmt.Sprintf("Heartbeat %d", mathrand.Intn(1000))
|
||||||
ciphertext, err := sw.Wrapper.Encrypt(ctx, []byte(testVal), nil)
|
ciphertext, err := sw.Wrapper.Encrypt(ctx, []byte(testVal), nil)
|
||||||
@ -70,8 +121,14 @@ func (sw *SealWrapper) CheckHealth(ctx context.Context, checkTime time.Time) err
|
|||||||
return errors.New("failed to decrypt health test value to expected result")
|
return errors.New("failed to decrypt health test value to expected result")
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.LastSeenHealthy = checkTime
|
sw.setHealth(true, checkTime, checkTime)
|
||||||
sw.Healthy = true
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setHealth sets the fields protected by sw.hcLock, callers *must* hold the write lock.
|
||||||
|
func (sw *SealWrapper) setHealth(healthy bool, lastSeenHealthy, lastHealthCheck time.Time) {
|
||||||
|
sw.healthy = healthy
|
||||||
|
sw.lastSeenHealthy = lastSeenHealthy
|
||||||
|
sw.lastHealthCheck = lastHealthCheck
|
||||||
|
}
|
||||||
|
|||||||
@ -480,7 +480,7 @@ func (d *autoSeal) StartHealthCheck() {
|
|||||||
// Seal wrapper is unhealthy
|
// Seal wrapper is unhealthy
|
||||||
d.logger.Warn("seal wrapper health check failed", "seal_name", sealWrapper.Name, "err", err)
|
d.logger.Warn("seal wrapper health check failed", "seal_name", sealWrapper.Name, "err", err)
|
||||||
d.core.MetricSink().SetGaugeWithLabels(autoSealUnavailableDuration,
|
d.core.MetricSink().SetGaugeWithLabels(autoSealUnavailableDuration,
|
||||||
float32(time.Since(sealWrapper.LastSeenHealthy).Milliseconds()), mLabels)
|
float32(time.Since(sealWrapper.LastSeenHealthy()).Milliseconds()), mLabels)
|
||||||
allHealthy = false
|
allHealthy = false
|
||||||
} else {
|
} else {
|
||||||
// Seal wrapper is healthy
|
// Seal wrapper is healthy
|
||||||
@ -488,7 +488,7 @@ func (d *autoSeal) StartHealthCheck() {
|
|||||||
d.logger.Debug("seal wrapper health test passed", "seal_name", sealWrapper.Name)
|
d.logger.Debug("seal wrapper health test passed", "seal_name", sealWrapper.Name)
|
||||||
} else {
|
} else {
|
||||||
d.logger.Info("seal wrapper is now healthy again", "downtime", "seal_name", sealWrapper.Name,
|
d.logger.Info("seal wrapper is now healthy again", "downtime", "seal_name", sealWrapper.Name,
|
||||||
now.Sub(sealWrapper.LastSeenHealthy).String())
|
now.Sub(sealWrapper.LastSeenHealthy()).String())
|
||||||
}
|
}
|
||||||
allUnhealthy = false
|
allUnhealthy = false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -181,7 +181,7 @@ func TestAutoSeal_HealthCheck(t *testing.T) {
|
|||||||
metrics.NewGlobal(metricsConf, inmemSink)
|
metrics.NewGlobal(metricsConf, inmemSink)
|
||||||
|
|
||||||
pBackend := newTestBackend(t)
|
pBackend := newTestBackend(t)
|
||||||
testSealAccess, setErrs := seal.NewToggleableTestSeal(nil)
|
testSealAccess, setErrs := seal.NewToggleableTestSeal(&seal.TestSealOpts{Name: "health-test"})
|
||||||
core, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{
|
core, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{
|
||||||
MetricSink: metricsutil.NewClusterMetricSink("", inmemSink),
|
MetricSink: metricsutil.NewClusterMetricSink("", inmemSink),
|
||||||
Physical: pBackend,
|
Physical: pBackend,
|
||||||
|
|||||||
@ -144,6 +144,8 @@ const (
|
|||||||
SealConfigTypePkcs11 = SealConfigType(wrapping.WrapperTypePkcs11)
|
SealConfigTypePkcs11 = SealConfigType(wrapping.WrapperTypePkcs11)
|
||||||
SealConfigTypeAwsKms = SealConfigType(wrapping.WrapperTypeAwsKms)
|
SealConfigTypeAwsKms = SealConfigType(wrapping.WrapperTypeAwsKms)
|
||||||
SealConfigTypeHsmAutoDeprecated = SealConfigType(wrapping.WrapperTypeHsmAuto)
|
SealConfigTypeHsmAutoDeprecated = SealConfigType(wrapping.WrapperTypeHsmAuto)
|
||||||
|
SealConfigTypeTransit = SealConfigType(wrapping.WrapperTypeTransit)
|
||||||
|
SealConfigTypeGcpCkms = SealConfigType(wrapping.WrapperTypeGcpCkms)
|
||||||
|
|
||||||
// SealConfigTypeRecovery is an alias for SealConfigTypeShamir since all recovery seals are
|
// SealConfigTypeRecovery is an alias for SealConfigTypeShamir since all recovery seals are
|
||||||
// defaultSeals using shamir wrappers.
|
// defaultSeals using shamir wrappers.
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
package vault
|
package vault
|
||||||
|
|
||||||
import (
|
import (
|
||||||
aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2"
|
"github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2"
|
||||||
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
|
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
|
||||||
"github.com/hashicorp/vault/vault/seal"
|
"github.com/hashicorp/vault/vault/seal"
|
||||||
testing "github.com/mitchellh/go-testing-interface"
|
testing "github.com/mitchellh/go-testing-interface"
|
||||||
@ -17,13 +17,8 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal {
|
|||||||
|
|
||||||
switch opts.StoredKeys {
|
switch opts.StoredKeys {
|
||||||
case seal.StoredKeysSupportedShamirRoot:
|
case seal.StoredKeysSupportedShamirRoot:
|
||||||
w := aeadwrapper.NewShamirWrapper()
|
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),
|
||||||
{
|
|
||||||
Wrapper: w,
|
|
||||||
Priority: 1,
|
|
||||||
Name: "shamir",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error creating test seal", err)
|
t.Fatal("error creating test seal", err)
|
||||||
@ -37,13 +32,8 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal {
|
|||||||
})
|
})
|
||||||
return newSeal
|
return newSeal
|
||||||
case seal.StoredKeysNotSupported:
|
case seal.StoredKeysNotSupported:
|
||||||
w := aeadwrapper.NewShamirWrapper()
|
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),
|
||||||
{
|
|
||||||
Wrapper: w,
|
|
||||||
Priority: 1,
|
|
||||||
Name: "shamir",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error creating test seal", err)
|
t.Fatal("error creating test seal", err)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user