From 2656c020aea48e308f46dc9843dcb0e999977442 Mon Sep 17 00:00:00 2001 From: Victor Rodriguez Date: Thu, 4 May 2023 14:22:30 -0400 Subject: [PATCH] Convert seal.Access struct into a interface (OSS) (#20510) * Move seal barrier type field from Access to autoSeal struct. Remove method Access.SetType(), which was only being used by a single test, and which can use the name option of NewTestSeal() to specify the type. * Change method signatures of Access to match those of Wrapper. * Turn seal.Access struct into an interface. * Tweak Access implementation. Change `access` struct to have a field of type wrapping.Wrapper, rather than extending it. * Add method Seal.GetShamirWrapper(). Add method Seal.GetShamirWrapper() for use by code that need to perform Shamir-specific operations. --- command/command_test.go | 2 +- command/server.go | 19 +++----- helper/testhelpers/seal/sealhelper.go | 4 +- http/sys_init_test.go | 3 +- physical/raft/raft.go | 8 ++-- vault/core.go | 29 +++++++----- vault/ha.go | 7 ++- vault/init.go | 7 ++- vault/raft.go | 2 +- vault/rekey.go | 12 ++--- vault/seal.go | 43 ++++++++++++------ vault/seal/seal.go | 65 +++++++++++++++++---------- vault/seal/seal_testing.go | 42 +++++++++-------- vault/seal_access.go | 3 +- vault/seal_autoseal.go | 20 ++++++--- vault/seal_autoseal_test.go | 4 +- vault/seal_testing_util.go | 11 ++--- 17 files changed, 166 insertions(+), 115 deletions(-) diff --git a/command/command_test.go b/command/command_test.go index 73719d583..a34603a8d 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -96,7 +96,7 @@ func testVaultServerAllBackends(tb testing.TB) (*api.Client, func()) { // testVaultServerAutoUnseal creates a test vault cluster and sets it up with auto unseal // the function returns a client, the recovery keys, and a closer function func testVaultServerAutoUnseal(tb testing.TB) (*api.Client, []string, func()) { - testSeal := seal.NewTestSeal(nil) + testSeal, _ := seal.NewTestSeal(nil) autoSeal, err := vault.NewAutoSeal(testSeal) if err != nil { tb.Fatal("unable to create autoseal", err) diff --git a/command/server.go b/command/server.go index 2c0da0bf2..86a063226 100644 --- a/command/server.go +++ b/command/server.go @@ -547,9 +547,7 @@ func (c *ServerCommand) runRecoveryMode() int { info["Seal Type"] = sealType var seal vault.Seal - defaultSeal := vault.NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewShamirWrapper(), - }) + defaultSeal := vault.NewDefaultSeal(vaultseal.NewAccess(aeadwrapper.NewShamirWrapper())) sealLogger := c.logger.ResetNamed(fmt.Sprintf("seal.%s", sealType)) wrapper, sealConfigError = configutil.ConfigureWrapper(configSeal, &infoKeys, &info, sealLogger) if sealConfigError != nil { @@ -562,9 +560,7 @@ func (c *ServerCommand) runRecoveryMode() int { if wrapper == nil { seal = defaultSeal } else { - seal, err = vault.NewAutoSeal(&vaultseal.Access{ - Wrapper: wrapper, - }) + seal, err = vault.NewAutoSeal(vaultseal.NewAccess(wrapper)) if err != nil { c.UI.Error(fmt.Sprintf("error creating auto seal: %v", err)) } @@ -2442,7 +2438,8 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma var barrierWrapper wrapping.Wrapper if c.flagDevAutoSeal { var err error - barrierSeal, err = vault.NewAutoSeal(vaultseal.NewTestSeal(nil)) + access, _ := vaultseal.NewTestSeal(nil) + barrierSeal, err = vault.NewAutoSeal(access) if err != nil { return nil, nil, nil, nil, nil, err } @@ -2473,9 +2470,7 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma var seal vault.Seal sealLogger := c.logger.ResetNamed(fmt.Sprintf("seal.%s", sealType)) c.allLoggers = append(c.allLoggers, sealLogger) - defaultSeal := vault.NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewShamirWrapper(), - }) + defaultSeal := vault.NewDefaultSeal(vaultseal.NewAccess(aeadwrapper.NewShamirWrapper())) var sealInfoKeys []string sealInfoMap := map[string]string{} wrapper, sealConfigError = configutil.ConfigureWrapper(configSeal, &sealInfoKeys, &sealInfoMap, sealLogger) @@ -2489,9 +2484,7 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma seal = defaultSeal } else { var err error - seal, err = vault.NewAutoSeal(&vaultseal.Access{ - Wrapper: wrapper, - }) + seal, err = vault.NewAutoSeal(vaultseal.NewAccess(wrapper)) if err != nil { return nil, nil, nil, nil, nil, err } diff --git a/helper/testhelpers/seal/sealhelper.go b/helper/testhelpers/seal/sealhelper.go index f4d5aa629..b05401f1c 100644 --- a/helper/testhelpers/seal/sealhelper.go +++ b/helper/testhelpers/seal/sealhelper.go @@ -74,7 +74,5 @@ func (tss *TransitSealServer) MakeSeal(t testing.T, key string) (vault.Seal, err t.Fatalf("error setting wrapper config: %v", err) } - return vault.NewAutoSeal(&seal.Access{ - Wrapper: transitSeal, - }) + return vault.NewAutoSeal(seal.NewAccess(transitSeal)) } diff --git a/http/sys_init_test.go b/http/sys_init_test.go index 620db9d73..79dd27582 100644 --- a/http/sys_init_test.go +++ b/http/sys_init_test.go @@ -153,12 +153,11 @@ func TestSysInit_Put_ValidateParams(t *testing.T) { } func TestSysInit_Put_ValidateParams_AutoUnseal(t *testing.T) { - testSeal := seal.NewTestSeal(nil) + testSeal, _ := seal.NewTestSeal(&seal.TestSealOpts{Name: "transit"}) autoSeal, err := vault.NewAutoSeal(testSeal) if err != nil { t.Fatal(err) } - autoSeal.SetType("transit") // Create the transit server. conf := &vault.CoreConfig{ diff --git a/physical/raft/raft.go b/physical/raft/raft.go index 1507aad83..1060eda7a 100644 --- a/physical/raft/raft.go +++ b/physical/raft/raft.go @@ -1367,7 +1367,7 @@ func (b *RaftBackend) Peers(ctx context.Context) ([]Peer, error) { // SnapshotHTTP is a wrapper for Snapshot that sends the snapshot as an HTTP // response. -func (b *RaftBackend) SnapshotHTTP(out *logical.HTTPResponseWriter, access *seal.Access) error { +func (b *RaftBackend) SnapshotHTTP(out *logical.HTTPResponseWriter, access seal.Access) error { out.Header().Add("Content-Disposition", "attachment") out.Header().Add("Content-Type", "application/gzip") @@ -1377,7 +1377,7 @@ func (b *RaftBackend) SnapshotHTTP(out *logical.HTTPResponseWriter, access *seal // Snapshot takes a raft snapshot, packages it into a archive file and writes it // to the provided writer. Seal access is used to encrypt the SHASUM file so we // can validate the snapshot was taken using the same root keys or not. -func (b *RaftBackend) Snapshot(out io.Writer, access *seal.Access) error { +func (b *RaftBackend) Snapshot(out io.Writer, access seal.Access) error { b.l.RLock() defer b.l.RUnlock() @@ -1401,7 +1401,7 @@ func (b *RaftBackend) Snapshot(out io.Writer, access *seal.Access) error { // access is used to decrypt the SHASUM file in the archive to ensure this // snapshot has the same root key as the running instance. If the provided // access is nil then it will skip that validation. -func (b *RaftBackend) WriteSnapshotToTemp(in io.ReadCloser, access *seal.Access) (*os.File, func(), raft.SnapshotMeta, error) { +func (b *RaftBackend) WriteSnapshotToTemp(in io.ReadCloser, access seal.Access) (*os.File, func(), raft.SnapshotMeta, error) { b.l.RLock() defer b.l.RUnlock() @@ -1894,7 +1894,7 @@ func (l *RaftLock) Value() (bool, string, error) { // sealer implements the snapshot.Sealer interface and is used in the snapshot // process for encrypting/decrypting the SHASUM file in snapshot archives. type sealer struct { - access *seal.Access + access seal.Access } // Seal encrypts the data with using the seal access object. diff --git a/vault/core.go b/vault/core.go index aca47398d..b870e70e5 100644 --- a/vault/core.go +++ b/vault/core.go @@ -1098,9 +1098,7 @@ func CreateCore(conf *CoreConfig) (*Core, error) { wrapper := aeadwrapper.NewShamirWrapper() wrapper.SetConfig(context.Background(), awskms.WithLogger(c.logger.Named("shamir"))) - c.seal = NewDefaultSeal(&vaultseal.Access{ - Wrapper: wrapper, - }) + c.seal = NewDefaultSeal(vaultseal.NewAccess(wrapper)) } c.seal.SetCore(c) return c, nil @@ -1544,7 +1542,10 @@ func (c *Core) unsealWithRaft(combinedKey []byte) error { if c.seal.BarrierType() == wrapping.WrapperTypeShamir { // If this is a legacy shamir seal this serves no purpose but it // doesn't hurt. - err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAesGcmKeyBytes(combinedKey) + shamirWrapper, err := c.seal.GetShamirWrapper() + if err == nil { + err = shamirWrapper.SetAesGcmKeyBytes(combinedKey) + } if err != nil { return err } @@ -1795,7 +1796,11 @@ func (c *Core) migrateSeal(ctx context.Context) error { } // We have recovery keys; we're going to use them as the new shamir KeK. - err = c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAesGcmKeyBytes(recoveryKey) + shamirWrapper, err := c.seal.GetShamirWrapper() + if err != nil { + return err + } + err = shamirWrapper.SetAesGcmKeyBytes(recoveryKey) if err != nil { return fmt.Errorf("failed to set master key in seal: %w", err) } @@ -2793,9 +2798,7 @@ func (c *Core) adjustForSealMigration(unwrapSeal Seal) error { case existBarrierSealConfig.Type == wrapping.WrapperTypeShamir.String(): // The configured seal is not Shamir, the stored seal config is Shamir. // This is a migration away from Shamir. - unwrapSeal = NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewShamirWrapper(), - }) + unwrapSeal = NewDefaultSeal(vaultseal.NewAccess(aeadwrapper.NewShamirWrapper())) 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 @@ -2958,9 +2961,7 @@ func (c *Core) unsealKeyToMasterKey(ctx context.Context, seal Seal, combinedKey case vaultseal.StoredKeysSupportedShamirRoot: if useTestSeal { - testseal := NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewShamirWrapper(), - }) + testseal := NewDefaultSeal(vaultseal.NewAccess(aeadwrapper.NewShamirWrapper())) testseal.SetCore(c) cfg, err := seal.BarrierConfig(ctx) if err != nil { @@ -2970,7 +2971,11 @@ func (c *Core) unsealKeyToMasterKey(ctx context.Context, seal Seal, combinedKey seal = testseal } - err := seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAesGcmKeyBytes(combinedKey) + shamirWrapper, err := seal.GetShamirWrapper() + if err != nil { + return nil, err + } + err = shamirWrapper.SetAesGcmKeyBytes(combinedKey) if err != nil { return nil, &ErrInvalidKey{fmt.Sprintf("failed to setup unseal key: %v", err)} } diff --git a/vault/ha.go b/vault/ha.go index 300f72708..4fc304390 100644 --- a/vault/ha.go +++ b/vault/ha.go @@ -18,7 +18,6 @@ import ( "github.com/armon/go-metrics" "github.com/hashicorp/errwrap" - aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2" "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/namespace" @@ -966,7 +965,11 @@ func (c *Core) reloadShamirKey(ctx context.Context) error { } shamirKey = keyring.rootKey } - return c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAesGcmKeyBytes(shamirKey) + shamirWrapper, err := c.seal.GetShamirWrapper() + if err != nil { + return err + } + return shamirWrapper.SetAesGcmKeyBytes(shamirKey) } func (c *Core) performKeyUpgrades(ctx context.Context) error { diff --git a/vault/init.go b/vault/init.go index 1f398b158..ba537c202 100644 --- a/vault/init.go +++ b/vault/init.go @@ -16,7 +16,6 @@ import ( "github.com/hashicorp/vault/physical/raft" "github.com/hashicorp/vault/vault/seal" - aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/pgpkeys" "github.com/hashicorp/vault/shamir" @@ -328,7 +327,11 @@ func (c *Core) Initialize(ctx context.Context, initParams *InitParams) (*InitRes switch c.seal.StoredKeysSupported() { case seal.StoredKeysSupportedShamirRoot: keysToStore := [][]byte{barrierKey} - if err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAesGcmKeyBytes(sealKey); err != nil { + shamirWrapper, err := c.seal.GetShamirWrapper() + if err != nil { + return nil, err + } + if err := shamirWrapper.SetAesGcmKeyBytes(sealKey); err != nil { c.logger.Error("failed to set seal key", "error", err) return nil, fmt.Errorf("failed to set seal key: %w", err) } diff --git a/vault/raft.go b/vault/raft.go index 8cd3185ac..daf4d2b6f 100644 --- a/vault/raft.go +++ b/vault/raft.go @@ -1268,7 +1268,7 @@ func (c *Core) isRaftHAOnly() bool { return isRaftHA && !isRaftStorage } -func (c *Core) joinRaftSendAnswer(ctx context.Context, sealAccess *seal.Access, raftInfo *raftInformation) error { +func (c *Core) joinRaftSendAnswer(ctx context.Context, sealAccess seal.Access, raftInfo *raftInformation) error { if raftInfo.challenge == nil { return errors.New("raft challenge is nil") } diff --git a/vault/rekey.go b/vault/rekey.go index b8249e756..80df6552d 100644 --- a/vault/rekey.go +++ b/vault/rekey.go @@ -401,11 +401,10 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string) } case c.seal.BarrierType() == wrapping.WrapperTypeShamir: if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedShamirRoot { - testseal := NewDefaultSeal(&seal.Access{ - Wrapper: aeadwrapper.NewShamirWrapper(), - }) + shamirWrapper := aeadwrapper.NewShamirWrapper() + testseal := NewDefaultSeal(seal.NewAccess(shamirWrapper)) testseal.SetCore(c) - err = testseal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAesGcmKeyBytes(recoveredKey) + err = shamirWrapper.SetAesGcmKeyBytes(recoveredKey) if err != nil { return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to setup unseal key: %w", err).Error()) } @@ -533,7 +532,10 @@ func (c *Core) performBarrierRekey(ctx context.Context, newSealKey []byte) logic } if c.seal.StoredKeysSupported() != seal.StoredKeysSupportedGeneric { - err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAesGcmKeyBytes(newSealKey) + shamirWrapper, err := c.seal.GetShamirWrapper() + if err == nil { + err = shamirWrapper.SetAesGcmKeyBytes(newSealKey) + } if err != nil { return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to update barrier seal key: %w", err).Error()) } diff --git a/vault/seal.go b/vault/seal.go index 1f6120b3f..a5dc78eee 100644 --- a/vault/seal.go +++ b/vault/seal.go @@ -13,6 +13,8 @@ import ( "strings" "sync/atomic" + aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2" + "github.com/hashicorp/vault/sdk/helper/jsonutil" "github.com/hashicorp/vault/sdk/physical" @@ -59,32 +61,35 @@ type Seal interface { SetCore(*Core) Init(context.Context) error Finalize(context.Context) error - StoredKeysSupported() seal.StoredKeysSupport + StoredKeysSupported() seal.StoredKeysSupport // SealAccess SealWrapable() bool SetStoredKeys(context.Context, [][]byte) error GetStoredKeys(context.Context) ([][]byte, error) - BarrierType() wrapping.WrapperType - BarrierConfig(context.Context) (*SealConfig, error) + BarrierType() wrapping.WrapperType // SealAccess + BarrierConfig(context.Context) (*SealConfig, error) // SealAccess SetBarrierConfig(context.Context, *SealConfig) error SetCachedBarrierConfig(*SealConfig) - RecoveryKeySupported() bool + RecoveryKeySupported() bool // SealAccess RecoveryType() string - RecoveryConfig(context.Context) (*SealConfig, error) + RecoveryConfig(context.Context) (*SealConfig, error) // SealAccess RecoveryKey(context.Context) ([]byte, error) SetRecoveryConfig(context.Context, *SealConfig) error SetCachedRecoveryConfig(*SealConfig) SetRecoveryKey(context.Context, []byte) error - VerifyRecoveryKey(context.Context, []byte) error - GetAccess() *seal.Access + VerifyRecoveryKey(context.Context, []byte) error // SealAccess + GetAccess() seal.Access // SealAccess + GetShamirWrapper() (*aeadwrapper.ShamirWrapper, error) } type defaultSeal struct { - access *seal.Access + access seal.Access config atomic.Value core *Core } -func NewDefaultSeal(lowLevel *seal.Access) Seal { +var _ Seal = (*defaultSeal)(nil) + +func NewDefaultSeal(lowLevel seal.Access) Seal { ret := &defaultSeal{ access: lowLevel, } @@ -103,11 +108,11 @@ func (d *defaultSeal) checkCore() error { return nil } -func (d *defaultSeal) GetAccess() *seal.Access { +func (d *defaultSeal) GetAccess() seal.Access { return d.access } -func (d *defaultSeal) SetAccess(access *seal.Access) { +func (d *defaultSeal) SetAccess(access seal.Access) { d.access = access } @@ -288,6 +293,16 @@ func (d *defaultSeal) SetRecoveryKey(ctx context.Context, key []byte) error { return fmt.Errorf("recovery not supported") } +func (d *defaultSeal) GetShamirWrapper() (*aeadwrapper.ShamirWrapper, error) { + // defaultSeal is meant to be for Shamir seals, so it should always have a ShamirWrapper. + // Nonetheless, NewDefaultSeal does not check, so let's play it safe. + w, ok := d.GetAccess().GetWrapper().(*aeadwrapper.ShamirWrapper) + if !ok { + return nil, fmt.Errorf("expected defaultSeal to have a ShamirWrapper, but found a %T instead", d.GetAccess().GetWrapper()) + } + return w, nil +} + // SealConfig is used to describe the seal configuration type SealConfig struct { // The type, for sanity checking @@ -432,7 +447,7 @@ func (e *ErrDecrypt) Is(target error) bool { return ok || errors.Is(e.Err, target) } -func writeStoredKeys(ctx context.Context, storage physical.Backend, encryptor *seal.Access, keys [][]byte) error { +func writeStoredKeys(ctx context.Context, storage physical.Backend, encryptor seal.Access, keys [][]byte) error { if keys == nil { return fmt.Errorf("keys were nil") } @@ -458,7 +473,7 @@ func writeStoredKeys(ctx context.Context, storage physical.Backend, encryptor *s // Store the seal configuration. pe := &physical.Entry{ - Key: StoredBarrierKeysPath, + Key: StoredBarrierKeysPath, // TODO(SEALHA): will we need to store more than one set of keys? Value: value, } @@ -469,7 +484,7 @@ func writeStoredKeys(ctx context.Context, storage physical.Backend, encryptor *s return nil } -func readStoredKeys(ctx context.Context, storage physical.Backend, encryptor *seal.Access) ([][]byte, error) { +func readStoredKeys(ctx context.Context, storage physical.Backend, encryptor seal.Access) ([][]byte, error) { pe, err := storage.Get(ctx, StoredBarrierKeysPath) if err != nil { return nil, fmt.Errorf("failed to fetch stored keys: %w", err) diff --git a/vault/seal/seal.go b/vault/seal/seal.go index 2741658f7..4233951c2 100644 --- a/vault/seal/seal.go +++ b/vault/seal/seal.go @@ -36,32 +36,51 @@ func (s StoredKeysSupport) String() string { // Access is the embedded implementation of autoSeal that contains logic // specific to encrypting and decrypting data, or in this case keys. -type Access struct { +type Access interface { wrapping.Wrapper - WrapperType wrapping.WrapperType + wrapping.InitFinalizer + + GetWrapper() wrapping.Wrapper } -func (a *Access) Init(ctx context.Context) error { - if initWrapper, ok := a.Wrapper.(wrapping.InitFinalizer); ok { - return initWrapper.Init(ctx) +type access struct { + w wrapping.Wrapper +} + +var _ Access = (*access)(nil) + +func NewAccess(w wrapping.Wrapper) Access { + return &access{ + w: w, + } +} + +func (a *access) KeyId(ctx context.Context) (string, error) { + return a.w.KeyId(ctx) +} + +func (a *access) SetConfig(ctx context.Context, options ...wrapping.Option) (*wrapping.WrapperConfig, error) { + return a.w.SetConfig(ctx, options...) +} + +func (a *access) GetWrapper() wrapping.Wrapper { + return a.w +} + +func (a *access) Init(ctx context.Context, options ...wrapping.Option) error { + if initWrapper, ok := a.w.(wrapping.InitFinalizer); ok { + return initWrapper.Init(ctx, options...) } return nil } -func (a *Access) SetType(t wrapping.WrapperType) { - a.WrapperType = t -} - -func (a *Access) Type(ctx context.Context) (wrapping.WrapperType, error) { - if a != nil && a.WrapperType != "" { - return a.WrapperType, nil - } - return a.Wrapper.Type(ctx) +func (a *access) Type(ctx context.Context) (wrapping.WrapperType, error) { + return a.w.Type(ctx) } // Encrypt uses the underlying seal to encrypt the plaintext and returns it. -func (a *Access) Encrypt(ctx context.Context, plaintext, aad []byte) (blob *wrapping.BlobInfo, err error) { - wTyp, err := a.Wrapper.Type(ctx) +func (a *access) Encrypt(ctx context.Context, plaintext []byte, options ...wrapping.Option) (blob *wrapping.BlobInfo, err error) { + wTyp, err := a.w.Type(ctx) if err != nil { return nil, err } @@ -79,14 +98,14 @@ func (a *Access) Encrypt(ctx context.Context, plaintext, aad []byte) (blob *wrap metrics.IncrCounter([]string{"seal", "encrypt"}, 1) metrics.IncrCounter([]string{"seal", wTyp.String(), "encrypt"}, 1) - return a.Wrapper.Encrypt(ctx, plaintext, wrapping.WithAad(aad)) + return a.w.Encrypt(ctx, plaintext, options...) } // Decrypt uses the underlying seal to decrypt the cryptotext and returns it. // Note that it is possible depending on the wrapper used that both pt and err // are populated. -func (a *Access) Decrypt(ctx context.Context, data *wrapping.BlobInfo, aad []byte) (pt []byte, err error) { - wTyp, err := a.Wrapper.Type(ctx) +func (a *access) Decrypt(ctx context.Context, data *wrapping.BlobInfo, options ...wrapping.Option) (pt []byte, err error) { + wTyp, err := a.w.Type(ctx) defer func(now time.Time) { metrics.MeasureSince([]string{"seal", "decrypt", "time"}, now) metrics.MeasureSince([]string{"seal", wTyp.String(), "decrypt", "time"}, now) @@ -100,12 +119,12 @@ func (a *Access) Decrypt(ctx context.Context, data *wrapping.BlobInfo, aad []byt metrics.IncrCounter([]string{"seal", "decrypt"}, 1) metrics.IncrCounter([]string{"seal", wTyp.String(), "decrypt"}, 1) - return a.Wrapper.Decrypt(ctx, data, wrapping.WithAad(aad)) + return a.w.Decrypt(ctx, data, options...) } -func (a *Access) Finalize(ctx context.Context) error { - if finalizeWrapper, ok := a.Wrapper.(wrapping.InitFinalizer); ok { - return finalizeWrapper.Finalize(ctx) +func (a *access) Finalize(ctx context.Context, options ...wrapping.Option) error { + if finalizeWrapper, ok := a.w.(wrapping.InitFinalizer); ok { + return finalizeWrapper.Finalize(ctx, options...) } return nil } diff --git a/vault/seal/seal_testing.go b/vault/seal/seal_testing.go index 99fe2b7ba..ebbe71b81 100644 --- a/vault/seal/seal_testing.go +++ b/vault/seal/seal_testing.go @@ -18,33 +18,32 @@ type TestSealOpts struct { Name wrapping.WrapperType } -func NewTestSeal(opts *TestSealOpts) *Access { - if opts == nil { - opts = new(TestSealOpts) - } - - return &Access{ - Wrapper: wrapping.NewTestWrapper(opts.Secret), - WrapperType: opts.Name, - } -} - -func NewToggleableTestSeal(opts *TestSealOpts) (*Access, func(error)) { +func NewTestSeal(opts *TestSealOpts) (Access, *ToggleableWrapper) { if opts == nil { opts = new(TestSealOpts) } w := &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)} - return &Access{ - Wrapper: w, - WrapperType: opts.Name, - }, w.SetError + if opts.Name != "" { + w.wrapperType = &opts.Name + } + return NewAccess(w), w +} + +func NewToggleableTestSeal(opts *TestSealOpts) (Access, func(error)) { + if opts == nil { + opts = new(TestSealOpts) + } + + w := &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)} + return NewAccess(w), w.SetError } type ToggleableWrapper struct { wrapping.Wrapper - error error - l sync.RWMutex + wrapperType *wrapping.WrapperType + error error + l sync.RWMutex } func (t *ToggleableWrapper) Encrypt(ctx context.Context, bytes []byte, opts ...wrapping.Option) (*wrapping.BlobInfo, error) { @@ -71,4 +70,11 @@ func (t *ToggleableWrapper) SetError(err error) { t.error = err } +func (t *ToggleableWrapper) Type(ctx context.Context) (wrapping.WrapperType, error) { + if t.wrapperType != nil { + return *t.wrapperType, nil + } + return t.Wrapper.Type(ctx) +} + var _ wrapping.Wrapper = &ToggleableWrapper{} diff --git a/vault/seal_access.go b/vault/seal_access.go index 1d9621a67..b278f773f 100644 --- a/vault/seal_access.go +++ b/vault/seal_access.go @@ -46,6 +46,7 @@ func (s *SealAccess) VerifyRecoveryKey(ctx context.Context, key []byte) error { return s.seal.VerifyRecoveryKey(ctx, key) } +// TODO(SEALHA): This looks like it belongs in Seal instead, it only has two callers func (s *SealAccess) ClearCaches(ctx context.Context) { s.seal.SetBarrierConfig(ctx, nil) if s.RecoveryKeySupported() { @@ -53,6 +54,6 @@ func (s *SealAccess) ClearCaches(ctx context.Context) { } } -func (s *SealAccess) GetAccess() *seal.Access { +func (s *SealAccess) GetAccess() seal.Access { return s.seal.GetAccess() } diff --git a/vault/seal_autoseal.go b/vault/seal_autoseal.go index 6a3f4e8ce..ebae89280 100644 --- a/vault/seal_autoseal.go +++ b/vault/seal_autoseal.go @@ -14,6 +14,8 @@ import ( "sync/atomic" "time" + aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2" + proto "github.com/golang/protobuf/proto" log "github.com/hashicorp/go-hclog" wrapping "github.com/hashicorp/go-kms-wrapping/v2" @@ -36,8 +38,9 @@ var ( // decrypting stored keys via an underlying AutoSealAccess implementation, as // well as logic related to recovery keys and barrier config. type autoSeal struct { - *seal.Access + seal.Access + barrierType wrapping.WrapperType barrierConfig atomic.Value recoveryConfig atomic.Value core *Core @@ -50,18 +53,21 @@ type autoSeal struct { // Ensure we are implementing the Seal interface var _ Seal = (*autoSeal)(nil) -func NewAutoSeal(lowLevel *seal.Access) (*autoSeal, error) { +func NewAutoSeal(lowLevel seal.Access) (*autoSeal, error) { ret := &autoSeal{ Access: lowLevel, } ret.barrierConfig.Store((*SealConfig)(nil)) ret.recoveryConfig.Store((*SealConfig)(nil)) + // Having the wrapper type in a field is just a convenience since Seal.BarrierType() + // does not return an error. var err error - ret.WrapperType, err = ret.Type(context.Background()) + ret.barrierType, err = ret.Type(context.Background()) if err != nil { return nil, err } + return ret, nil } @@ -69,7 +75,7 @@ func (d *autoSeal) SealWrapable() bool { return true } -func (d *autoSeal) GetAccess() *seal.Access { +func (d *autoSeal) GetAccess() seal.Access { return d.Access } @@ -97,7 +103,11 @@ func (d *autoSeal) Finalize(ctx context.Context) error { } func (d *autoSeal) BarrierType() wrapping.WrapperType { - return d.WrapperType + return d.barrierType +} + +func (d *autoSeal) GetShamirWrapper() (*aeadwrapper.ShamirWrapper, error) { + return nil, fmt.Errorf("autoSeal does not use a ShamirWrapper") } func (d *autoSeal) StoredKeysSupported() seal.StoredKeysSupport { diff --git a/vault/seal_autoseal_test.go b/vault/seal_autoseal_test.go index a9e728fce..dc3393616 100644 --- a/vault/seal_autoseal_test.go +++ b/vault/seal_autoseal_test.go @@ -69,12 +69,12 @@ func (p *phy) Len() int { func TestAutoSeal_UpgradeKeys(t *testing.T) { core, _, _ := TestCoreUnsealed(t) - testSeal := seal.NewTestSeal(nil) + testSeal, toggleableWrapper := seal.NewTestSeal(nil) var encKeys []string changeKey := func(key string) { encKeys = append(encKeys, key) - testSeal.Wrapper.(*wrapping.TestWrapper).SetKeyId(key) + toggleableWrapper.Wrapper.(*wrapping.TestWrapper).SetKeyId(key) } // Set initial encryption key. diff --git a/vault/seal_testing_util.go b/vault/seal_testing_util.go index 52e7244cf..f51f0296f 100644 --- a/vault/seal_testing_util.go +++ b/vault/seal_testing_util.go @@ -22,9 +22,7 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal { switch opts.StoredKeys { case seal.StoredKeysSupportedShamirRoot: - newSeal := NewDefaultSeal(&seal.Access{ - Wrapper: aeadwrapper.NewShamirWrapper(), - }) + newSeal := NewDefaultSeal(seal.NewAccess(aeadwrapper.NewShamirWrapper())) // Need StoredShares set or this will look like a legacy shamir seal. newSeal.SetCachedBarrierConfig(&SealConfig{ StoredShares: 1, @@ -33,9 +31,7 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal { }) return newSeal case seal.StoredKeysNotSupported: - newSeal := NewDefaultSeal(&seal.Access{ - Wrapper: aeadwrapper.NewShamirWrapper(), - }) + newSeal := NewDefaultSeal(seal.NewAccess(aeadwrapper.NewShamirWrapper())) newSeal.SetCachedBarrierConfig(&SealConfig{ StoredShares: 0, SecretThreshold: 1, @@ -43,7 +39,8 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal { }) return newSeal default: - seal, err := NewAutoSeal(seal.NewTestSeal(opts)) + access, _ := seal.NewTestSeal(opts) + seal, err := NewAutoSeal(access) if err != nil { t.Fatal(err) }