Rename master key to root key (#13324)
* See what it looks like to replace "master key" with "root key". There are two places that would require more challenging code changes: the storage path `core/master`, and its contents (the JSON-serialized EncodedKeyringtructure.) * Restore accidentally deleted line * Add changelog * Update root->recovery * Fix test Co-authored-by: Nick Cabatoff <ncabatoff@hashicorp.com>
This commit is contained in:
parent
04d634d9d2
commit
22c4ae5933
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
core: Replace "master key" terminology with "root key"
|
||||||
|
```
|
|
@ -57,10 +57,10 @@ Usage: vault operator init [options]
|
||||||
same storage backend in HA mode, you only need to initialize one Vault to
|
same storage backend in HA mode, you only need to initialize one Vault to
|
||||||
initialize the storage backend.
|
initialize the storage backend.
|
||||||
|
|
||||||
During initialization, Vault generates an in-memory master key and applies
|
During initialization, Vault generates an in-memory root key and applies
|
||||||
Shamir's secret sharing algorithm to disassemble that master key into a
|
Shamir's secret sharing algorithm to disassemble that root key into a
|
||||||
configuration number of key shares such that a configurable subset of those
|
configuration number of key shares such that a configurable subset of those
|
||||||
key shares must come together to regenerate the master key. These keys are
|
key shares must come together to regenerate the root key. These keys are
|
||||||
often called "unseal keys" in Vault's documentation.
|
often called "unseal keys" in Vault's documentation.
|
||||||
|
|
||||||
This command cannot be run against an already-initialized Vault cluster.
|
This command cannot be run against an already-initialized Vault cluster.
|
||||||
|
@ -105,7 +105,7 @@ func (c *OperatorInitCommand) Flags() *FlagSets {
|
||||||
Target: &c.flagKeyShares,
|
Target: &c.flagKeyShares,
|
||||||
Default: defKeyShares,
|
Default: defKeyShares,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "Number of key shares to split the generated master key into. " +
|
Usage: "Number of key shares to split the generated root key into. " +
|
||||||
"This is the number of \"unseal keys\" to generate.",
|
"This is the number of \"unseal keys\" to generate.",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ func (c *OperatorInitCommand) Flags() *FlagSets {
|
||||||
Target: &c.flagKeyThreshold,
|
Target: &c.flagKeyThreshold,
|
||||||
Default: defKeyThreshold,
|
Default: defKeyThreshold,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "Number of key shares required to reconstruct the master key. " +
|
Usage: "Number of key shares required to reconstruct the root key. " +
|
||||||
"This must be less than or equal to -key-shares.",
|
"This must be less than or equal to -key-shares.",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -447,8 +447,8 @@ func (c *OperatorInitCommand) init(client *api.Client, req *api.InitRequest) int
|
||||||
|
|
||||||
c.UI.Output("")
|
c.UI.Output("")
|
||||||
c.UI.Output(wrapAtLength(fmt.Sprintf(
|
c.UI.Output(wrapAtLength(fmt.Sprintf(
|
||||||
"Vault does not store the generated master key. Without at least %d "+
|
"Vault does not store the generated root key. Without at least %d "+
|
||||||
"keys to reconstruct the master key, Vault will remain permanently "+
|
"keys to reconstruct the root key, Vault will remain permanently "+
|
||||||
"sealed!",
|
"sealed!",
|
||||||
req.SecretThreshold)))
|
req.SecretThreshold)))
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ Usage: vault operator rekey [options] [KEY]
|
||||||
|
|
||||||
Generates a new set of unseal keys. This can optionally change the total
|
Generates a new set of unseal keys. This can optionally change the total
|
||||||
number of key shares or the required threshold of those key shares to
|
number of key shares or the required threshold of those key shares to
|
||||||
reconstruct the master key. This operation is zero downtime, but it requires
|
reconstruct the root key. This operation is zero downtime, but it requires
|
||||||
the Vault is unsealed and a quorum of existing unseal keys are provided.
|
the Vault is unsealed and a quorum of existing unseal keys are provided.
|
||||||
|
|
||||||
An unseal key may be provided directly on the command line as an argument to
|
An unseal key may be provided directly on the command line as an argument to
|
||||||
|
@ -129,7 +129,7 @@ func (c *OperatorRekeyCommand) Flags() *FlagSets {
|
||||||
Target: &c.flagKeyShares,
|
Target: &c.flagKeyShares,
|
||||||
Default: 5,
|
Default: 5,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "Number of key shares to split the generated master key into. " +
|
Usage: "Number of key shares to split the generated root key into. " +
|
||||||
"This is the number of \"unseal keys\" to generate.",
|
"This is the number of \"unseal keys\" to generate.",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ func (c *OperatorRekeyCommand) Flags() *FlagSets {
|
||||||
Target: &c.flagKeyThreshold,
|
Target: &c.flagKeyThreshold,
|
||||||
Default: 3,
|
Default: 3,
|
||||||
Completion: complete.PredictAnything,
|
Completion: complete.PredictAnything,
|
||||||
Usage: "Number of key shares required to reconstruct the master key. " +
|
Usage: "Number of key shares required to reconstruct the root key. " +
|
||||||
"This must be less than or equal to -key-shares.",
|
"This must be less than or equal to -key-shares.",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ Usage: vault operator seal [options]
|
||||||
|
|
||||||
Seals the Vault server. Sealing tells the Vault server to stop responding
|
Seals the Vault server. Sealing tells the Vault server to stop responding
|
||||||
to any operations until it is unsealed. When sealed, the Vault server
|
to any operations until it is unsealed. When sealed, the Vault server
|
||||||
discards its in-memory master key to unlock the data, so it is physically
|
discards its in-memory root key to unlock the data, so it is physically
|
||||||
blocked from responding to operations unsealed.
|
blocked from responding to operations unsealed.
|
||||||
|
|
||||||
If an unseal is in progress, sealing the Vault will reset the unsealing
|
If an unseal is in progress, sealing the Vault will reset the unsealing
|
||||||
process. Users will have to re-enter their portions of the master key again.
|
process. Users will have to re-enter their portions of the root key again.
|
||||||
|
|
||||||
This command does nothing if the Vault server is already sealed.
|
This command does nothing if the Vault server is already sealed.
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,9 @@ func (c *OperatorUnsealCommand) Help() string {
|
||||||
helpText := `
|
helpText := `
|
||||||
Usage: vault operator unseal [options] [KEY]
|
Usage: vault operator unseal [options] [KEY]
|
||||||
|
|
||||||
Provide a portion of the master key to unseal a Vault server. Vault starts
|
Provide a portion of the root key to unseal a Vault server. Vault starts
|
||||||
in a sealed state. It cannot perform operations until it is unsealed. This
|
in a sealed state. It cannot perform operations until it is unsealed. This
|
||||||
command accepts a portion of the master key (an "unseal key").
|
command accepts a portion of the root key (an "unseal key").
|
||||||
|
|
||||||
The unseal key can be supplied as an argument to the command, but this is
|
The unseal key can be supplied as an argument to the command, but this is
|
||||||
not recommended as the unseal key will be available in your history:
|
not recommended as the unseal key will be available in your history:
|
||||||
|
|
|
@ -1144,7 +1144,7 @@ func (b *RaftBackend) SnapshotHTTP(out *logical.HTTPResponseWriter, access *seal
|
||||||
|
|
||||||
// Snapshot takes a raft snapshot, packages it into a archive file and writes it
|
// 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
|
// to the provided writer. Seal access is used to encrypt the SHASUM file so we
|
||||||
// can validate the snapshot was taken using the same master keys or not.
|
// 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()
|
b.l.RLock()
|
||||||
defer b.l.RUnlock()
|
defer b.l.RUnlock()
|
||||||
|
@ -1167,7 +1167,7 @@ func (b *RaftBackend) Snapshot(out io.Writer, access *seal.Access) error {
|
||||||
// WriteSnapshotToTemp reads a snapshot archive off the provided reader,
|
// WriteSnapshotToTemp reads a snapshot archive off the provided reader,
|
||||||
// extracts the data and writes the snapshot to a temporary file. The seal
|
// extracts the data and writes the snapshot to a temporary file. The seal
|
||||||
// access is used to decrypt the SHASUM file in the archive to ensure this
|
// access is used to decrypt the SHASUM file in the archive to ensure this
|
||||||
// snapshot has the same master key as the running instance. If the provided
|
// snapshot has the same root key as the running instance. If the provided
|
||||||
// access is nil then it will skip that validation.
|
// 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()
|
b.l.RLock()
|
||||||
|
|
|
@ -35,15 +35,15 @@ const (
|
||||||
barrierInitPath = "barrier/init"
|
barrierInitPath = "barrier/init"
|
||||||
|
|
||||||
// keyringPath is the location of the keyring data. This is encrypted
|
// keyringPath is the location of the keyring data. This is encrypted
|
||||||
// by the master key.
|
// by the root key.
|
||||||
keyringPath = "core/keyring"
|
keyringPath = "core/keyring"
|
||||||
keyringPrefix = "core/"
|
keyringPrefix = "core/"
|
||||||
|
|
||||||
// keyringUpgradePrefix is the path used to store keyring update entries.
|
// keyringUpgradePrefix is the path used to store keyring update entries.
|
||||||
// When running in HA mode, the active instance will install the new key
|
// When running in HA mode, the active instance will install the new key
|
||||||
// and re-write the keyring. For standby instances, they need an upgrade
|
// and re-write the keyring. For standby instances, they need an upgrade
|
||||||
// path from key N to N+1. They cannot just use the master key because
|
// path from key N to N+1. They cannot just use the root key because
|
||||||
// in the event of a rekey, that master key can no longer decrypt the keyring.
|
// in the event of a rekey, that root key can no longer decrypt the keyring.
|
||||||
// When key N+1 is installed, we create an entry at "prefix/N" which uses
|
// When key N+1 is installed, we create an entry at "prefix/N" which uses
|
||||||
// encryption key N to provide the N+1 key. The standby instances scan
|
// encryption key N to provide the N+1 key. The standby instances scan
|
||||||
// for this periodically and refresh their keyring. The upgrade keys
|
// for this periodically and refresh their keyring. The upgrade keys
|
||||||
|
@ -51,17 +51,17 @@ const (
|
||||||
// standby instances to upgrade without causing any disruption.
|
// standby instances to upgrade without causing any disruption.
|
||||||
keyringUpgradePrefix = "core/upgrade/"
|
keyringUpgradePrefix = "core/upgrade/"
|
||||||
|
|
||||||
// masterKeyPath is the location of the master key. This is encrypted
|
// rootKeyPath is the location of the root key. This is encrypted
|
||||||
// by the latest key in the keyring. This is only used by standby instances
|
// by the latest key in the keyring. This is only used by standby instances
|
||||||
// to handle the case of a rekey. If the active instance does a rekey,
|
// to handle the case of a rekey. If the active instance does a rekey,
|
||||||
// the standby instances can no longer reload the keyring since they
|
// the standby instances can no longer reload the keyring since they
|
||||||
// have the old master key. This key can be decrypted if you have the
|
// have the old root key. This key can be decrypted if you have the
|
||||||
// keyring to discover the new master key. The new master key is then
|
// keyring to discover the new root key. The new root key is then
|
||||||
// used to reload the keyring itself.
|
// used to reload the keyring itself.
|
||||||
masterKeyPath = "core/master"
|
rootKeyPath = "core/master"
|
||||||
|
|
||||||
// shamirKekPath is used with Shamir in v1.3+ to store a copy of the
|
// shamirKekPath is used with Shamir in v1.3+ to store a copy of the
|
||||||
// unseal key behind the barrier. As with masterKeyPath this is primarily
|
// unseal key behind the barrier. As with rootKeyPath this is primarily
|
||||||
// used by standbys to handle rekeys. It also comes into play when restoring
|
// used by standbys to handle rekeys. It also comes into play when restoring
|
||||||
// raft snapshots.
|
// raft snapshots.
|
||||||
shamirKekPath = "core/shamir-kek"
|
shamirKekPath = "core/shamir-kek"
|
||||||
|
@ -75,14 +75,14 @@ const (
|
||||||
// a Vault. The barrier should only be Unlockable given its key.
|
// a Vault. The barrier should only be Unlockable given its key.
|
||||||
type SecurityBarrier interface {
|
type SecurityBarrier interface {
|
||||||
// Initialized checks if the barrier has been initialized
|
// Initialized checks if the barrier has been initialized
|
||||||
// and has a master key set.
|
// and has a root key set.
|
||||||
Initialized(ctx context.Context) (bool, error)
|
Initialized(ctx context.Context) (bool, error)
|
||||||
|
|
||||||
// Initialize works only if the barrier has not been initialized
|
// Initialize works only if the barrier has not been initialized
|
||||||
// and makes use of the given master key. When sealKey is provided
|
// and makes use of the given root key. When sealKey is provided
|
||||||
// it's because we're using a new-style Shamir seal, and masterKey
|
// it's because we're using a new-style Shamir seal, and rootKey
|
||||||
// is to be stored using sealKey to encrypt it.
|
// is to be stored using sealKey to encrypt it.
|
||||||
Initialize(ctx context.Context, masterKey []byte, sealKey []byte, random io.Reader) error
|
Initialize(ctx context.Context, rootKey []byte, sealKey []byte, random io.Reader) error
|
||||||
|
|
||||||
// GenerateKey is used to generate a new key
|
// GenerateKey is used to generate a new key
|
||||||
GenerateKey(io.Reader) ([]byte, error)
|
GenerateKey(io.Reader) ([]byte, error)
|
||||||
|
@ -94,27 +94,27 @@ type SecurityBarrier interface {
|
||||||
// is not expected to be able to perform any CRUD until it is unsealed.
|
// is not expected to be able to perform any CRUD until it is unsealed.
|
||||||
Sealed() (bool, error)
|
Sealed() (bool, error)
|
||||||
|
|
||||||
// Unseal is used to provide the master key which permits the barrier
|
// Unseal is used to provide the unseal key which permits the barrier
|
||||||
// to be unsealed. If the key is not correct, the barrier remains sealed.
|
// to be unsealed. If the key is not correct, the barrier remains sealed.
|
||||||
Unseal(ctx context.Context, key []byte) error
|
Unseal(ctx context.Context, key []byte) error
|
||||||
|
|
||||||
// VerifyMaster is used to check if the given key matches the master key
|
// VerifyRoot is used to check if the given key matches the root key
|
||||||
VerifyMaster(key []byte) error
|
VerifyRoot(key []byte) error
|
||||||
|
|
||||||
// SetMasterKey is used to directly set a new master key. This is used in
|
// SetRootKey is used to directly set a new root key. This is used in
|
||||||
// replicated scenarios due to the chicken and egg problem of reloading the
|
// replicated scenarios due to the chicken and egg problem of reloading the
|
||||||
// keyring from disk before we have the master key to decrypt it.
|
// keyring from disk before we have the root key to decrypt it.
|
||||||
SetMasterKey(key []byte) error
|
SetRootKey(key []byte) error
|
||||||
|
|
||||||
// ReloadKeyring is used to re-read the underlying keyring.
|
// ReloadKeyring is used to re-read the underlying keyring.
|
||||||
// This is used for HA deployments to ensure the latest keyring
|
// This is used for HA deployments to ensure the latest keyring
|
||||||
// is present in the leader.
|
// is present in the leader.
|
||||||
ReloadKeyring(ctx context.Context) error
|
ReloadKeyring(ctx context.Context) error
|
||||||
|
|
||||||
// ReloadMasterKey is used to re-read the underlying masterkey.
|
// ReloadRootKey is used to re-read the underlying root key.
|
||||||
// This is used for HA deployments to ensure the latest master key
|
// This is used for HA deployments to ensure the latest root key
|
||||||
// is available for keyring reloading.
|
// is available for keyring reloading.
|
||||||
ReloadMasterKey(ctx context.Context) error
|
ReloadRootKey(ctx context.Context) error
|
||||||
|
|
||||||
// Seal is used to re-seal the barrier. This requires the barrier to
|
// Seal is used to re-seal the barrier. This requires the barrier to
|
||||||
// be unsealed again to perform any further operations.
|
// be unsealed again to perform any further operations.
|
||||||
|
|
|
@ -122,7 +122,7 @@ func NewAESGCMBarrier(physical physical.Backend) (*AESGCMBarrier, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialized checks if the barrier has been initialized
|
// Initialized checks if the barrier has been initialized
|
||||||
// and has a master key set.
|
// and has a root key set.
|
||||||
func (b *AESGCMBarrier) Initialized(ctx context.Context) (bool, error) {
|
func (b *AESGCMBarrier) Initialized(ctx context.Context) (bool, error) {
|
||||||
if b.initialized.Load() {
|
if b.initialized.Load() {
|
||||||
return true, nil
|
return true, nil
|
||||||
|
@ -148,7 +148,7 @@ func (b *AESGCMBarrier) Initialized(ctx context.Context) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize works only if the barrier has not been initialized
|
// Initialize works only if the barrier has not been initialized
|
||||||
// and makes use of the given master key.
|
// and makes use of the given root key.
|
||||||
func (b *AESGCMBarrier) Initialize(ctx context.Context, key, sealKey []byte, reader io.Reader) error {
|
func (b *AESGCMBarrier) Initialize(ctx context.Context, key, sealKey []byte, reader io.Reader) error {
|
||||||
// Verify the key size
|
// Verify the key size
|
||||||
min, max := b.KeyLength()
|
min, max := b.KeyLength()
|
||||||
|
@ -171,7 +171,7 @@ func (b *AESGCMBarrier) Initialize(ctx context.Context, key, sealKey []byte, rea
|
||||||
|
|
||||||
// Create a new keyring, install the keys
|
// Create a new keyring, install the keys
|
||||||
keyring := NewKeyring()
|
keyring := NewKeyring()
|
||||||
keyring = keyring.SetMasterKey(key)
|
keyring = keyring.SetRootKey(key)
|
||||||
keyring, err = keyring.AddKey(&Key{
|
keyring, err = keyring.AddKey(&Key{
|
||||||
Term: 1,
|
Term: 1,
|
||||||
Version: 1,
|
Version: 1,
|
||||||
|
@ -205,7 +205,7 @@ func (b *AESGCMBarrier) Initialize(ctx context.Context, key, sealKey []byte, rea
|
||||||
}
|
}
|
||||||
|
|
||||||
// persistKeyring is used to write out the keyring using the
|
// persistKeyring is used to write out the keyring using the
|
||||||
// master key to encrypt it.
|
// root key to encrypt it.
|
||||||
func (b *AESGCMBarrier) persistKeyring(ctx context.Context, keyring *Keyring) error {
|
func (b *AESGCMBarrier) persistKeyring(ctx context.Context, keyring *Keyring) error {
|
||||||
// Create the keyring entry
|
// Create the keyring entry
|
||||||
keyringBuf, err := keyring.Serialize()
|
keyringBuf, err := keyring.Serialize()
|
||||||
|
@ -215,7 +215,7 @@ func (b *AESGCMBarrier) persistKeyring(ctx context.Context, keyring *Keyring) er
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the AES-GCM
|
// Create the AES-GCM
|
||||||
gcm, err := b.aeadFromKey(keyring.MasterKey())
|
gcm, err := b.aeadFromKey(keyring.RootKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -235,36 +235,36 @@ func (b *AESGCMBarrier) persistKeyring(ctx context.Context, keyring *Keyring) er
|
||||||
return fmt.Errorf("failed to persist keyring: %w", err)
|
return fmt.Errorf("failed to persist keyring: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize the master key value
|
// Serialize the root key value
|
||||||
key := &Key{
|
key := &Key{
|
||||||
Term: 1,
|
Term: 1,
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Value: keyring.MasterKey(),
|
Value: keyring.RootKey(),
|
||||||
}
|
}
|
||||||
keyBuf, err := key.Serialize()
|
keyBuf, err := key.Serialize()
|
||||||
defer memzero(keyBuf)
|
defer memzero(keyBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to serialize master key: %w", err)
|
return fmt.Errorf("failed to serialize root key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt the master key
|
// Encrypt the root key
|
||||||
activeKey := keyring.ActiveKey()
|
activeKey := keyring.ActiveKey()
|
||||||
aead, err := b.aeadFromKey(activeKey.Value)
|
aead, err := b.aeadFromKey(activeKey.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
value, err = b.encryptTracked(masterKeyPath, activeKey.Term, aead, keyBuf)
|
value, err = b.encryptTracked(rootKeyPath, activeKey.Term, aead, keyBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the masterKeyPath for standby instances
|
// Update the rootKeyPath for standby instances
|
||||||
pe = &physical.Entry{
|
pe = &physical.Entry{
|
||||||
Key: masterKeyPath,
|
Key: rootKeyPath,
|
||||||
Value: value,
|
Value: value,
|
||||||
}
|
}
|
||||||
if err := b.backend.Put(ctx, pe); err != nil {
|
if err := b.backend.Put(ctx, pe); err != nil {
|
||||||
return fmt.Errorf("failed to persist master key: %w", err)
|
return fmt.Errorf("failed to persist root key: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -292,14 +292,14 @@ func (b *AESGCMBarrier) Sealed() (bool, error) {
|
||||||
return sealed, nil
|
return sealed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyMaster is used to check if the given key matches the master key
|
// VerifyRoot is used to check if the given key matches the root key
|
||||||
func (b *AESGCMBarrier) VerifyMaster(key []byte) error {
|
func (b *AESGCMBarrier) VerifyRoot(key []byte) error {
|
||||||
b.l.RLock()
|
b.l.RLock()
|
||||||
defer b.l.RUnlock()
|
defer b.l.RUnlock()
|
||||||
if b.sealed {
|
if b.sealed {
|
||||||
return ErrBarrierSealed
|
return ErrBarrierSealed
|
||||||
}
|
}
|
||||||
if subtle.ConstantTimeCompare(key, b.keyring.MasterKey()) != 1 {
|
if subtle.ConstantTimeCompare(key, b.keyring.RootKey()) != 1 {
|
||||||
return ErrBarrierInvalidKey
|
return ErrBarrierInvalidKey
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -313,7 +313,7 @@ func (b *AESGCMBarrier) ReloadKeyring(ctx context.Context) error {
|
||||||
defer b.l.Unlock()
|
defer b.l.Unlock()
|
||||||
|
|
||||||
// Create the AES-GCM
|
// Create the AES-GCM
|
||||||
gcm, err := b.aeadFromKey(b.keyring.MasterKey())
|
gcm, err := b.aeadFromKey(b.keyring.RootKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -367,19 +367,19 @@ func (b *AESGCMBarrier) recoverKeyring(plaintext []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReloadMasterKey is used to re-read the underlying masterkey.
|
// ReloadRootKey is used to re-read the underlying root key.
|
||||||
// This is used for HA deployments to ensure the latest master key
|
// This is used for HA deployments to ensure the latest root key
|
||||||
// is available for keyring reloading.
|
// is available for keyring reloading.
|
||||||
func (b *AESGCMBarrier) ReloadMasterKey(ctx context.Context) error {
|
func (b *AESGCMBarrier) ReloadRootKey(ctx context.Context) error {
|
||||||
// Read the masterKeyPath upgrade
|
// Read the rootKeyPath upgrade
|
||||||
out, err := b.Get(ctx, masterKeyPath)
|
out, err := b.Get(ctx, rootKeyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read master key path: %w", err)
|
return fmt.Errorf("failed to read root key path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The masterKeyPath could be missing (backwards incompatible),
|
// The rootKeyPath could be missing (backwards incompatible),
|
||||||
// we can ignore this and attempt to make progress with the current
|
// we can ignore this and attempt to make progress with the current
|
||||||
// master key.
|
// root key.
|
||||||
if out == nil {
|
if out == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -388,35 +388,35 @@ func (b *AESGCMBarrier) ReloadMasterKey(ctx context.Context) error {
|
||||||
b.l.Lock()
|
b.l.Lock()
|
||||||
defer b.l.Unlock()
|
defer b.l.Unlock()
|
||||||
|
|
||||||
out, err = b.lockSwitchedGet(ctx, masterKeyPath, false)
|
out, err = b.lockSwitchedGet(ctx, rootKeyPath, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read master key path: %w", err)
|
return fmt.Errorf("failed to read root key path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if out == nil {
|
if out == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize the master key
|
// Deserialize the root key
|
||||||
key, err := DeserializeKey(out.Value)
|
key, err := DeserializeKey(out.Value)
|
||||||
memzero(out.Value)
|
memzero(out.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to deserialize key: %w", err)
|
return fmt.Errorf("failed to deserialize key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the master key is the same
|
// Check if the root key is the same
|
||||||
if subtle.ConstantTimeCompare(b.keyring.MasterKey(), key.Value) == 1 {
|
if subtle.ConstantTimeCompare(b.keyring.RootKey(), key.Value) == 1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the master key
|
// Update the root key
|
||||||
oldKeyring := b.keyring
|
oldKeyring := b.keyring
|
||||||
b.keyring = b.keyring.SetMasterKey(key.Value)
|
b.keyring = b.keyring.SetRootKey(key.Value)
|
||||||
oldKeyring.Zeroize(false)
|
oldKeyring.Zeroize(false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unseal is used to provide the master key which permits the barrier
|
// Unseal is used to provide the root key which permits the barrier
|
||||||
// to be unsealed. If the key is not correct, the barrier remains sealed.
|
// to be unsealed. If the key is not correct, the barrier remains sealed.
|
||||||
func (b *AESGCMBarrier) Unseal(ctx context.Context, key []byte) error {
|
func (b *AESGCMBarrier) Unseal(ctx context.Context, key []byte) error {
|
||||||
b.l.Lock()
|
b.l.Lock()
|
||||||
|
@ -499,9 +499,9 @@ func (b *AESGCMBarrier) Unseal(ctx context.Context, key []byte) error {
|
||||||
|
|
||||||
// Setup a new keyring, this is for backwards compatibility
|
// Setup a new keyring, this is for backwards compatibility
|
||||||
keyringNew := NewKeyring()
|
keyringNew := NewKeyring()
|
||||||
keyring := keyringNew.SetMasterKey(key)
|
keyring := keyringNew.SetRootKey(key)
|
||||||
|
|
||||||
// AddKey reuses the master, so we are only zeroizing after this call
|
// AddKey reuses the root, so we are only zeroizing after this call
|
||||||
defer keyringNew.Zeroize(false)
|
defer keyringNew.Zeroize(false)
|
||||||
|
|
||||||
keyring, err = keyring.AddKey(&Key{
|
keyring, err = keyring.AddKey(&Key{
|
||||||
|
@ -719,12 +719,12 @@ func (b *AESGCMBarrier) ActiveKeyInfo() (*KeyInfo, error) {
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rekey is used to change the master key used to protect the keyring
|
// Rekey is used to change the root key used to protect the keyring
|
||||||
func (b *AESGCMBarrier) Rekey(ctx context.Context, key []byte) error {
|
func (b *AESGCMBarrier) Rekey(ctx context.Context, key []byte) error {
|
||||||
b.l.Lock()
|
b.l.Lock()
|
||||||
defer b.l.Unlock()
|
defer b.l.Unlock()
|
||||||
|
|
||||||
newKeyring, err := b.updateMasterKeyCommon(key)
|
newKeyring, err := b.updateRootKeyCommon(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -741,13 +741,13 @@ func (b *AESGCMBarrier) Rekey(ctx context.Context, key []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMasterKey updates the keyring's in-memory master key but does not persist
|
// SetRootKey updates the keyring's in-memory root key but does not persist
|
||||||
// anything to storage
|
// anything to storage
|
||||||
func (b *AESGCMBarrier) SetMasterKey(key []byte) error {
|
func (b *AESGCMBarrier) SetRootKey(key []byte) error {
|
||||||
b.l.Lock()
|
b.l.Lock()
|
||||||
defer b.l.Unlock()
|
defer b.l.Unlock()
|
||||||
|
|
||||||
newKeyring, err := b.updateMasterKeyCommon(key)
|
newKeyring, err := b.updateRootKeyCommon(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -759,9 +759,9 @@ func (b *AESGCMBarrier) SetMasterKey(key []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs common tasks related to updating the master key; note that the lock
|
// Performs common tasks related to updating the root key; note that the lock
|
||||||
// must be held before calling this function
|
// must be held before calling this function
|
||||||
func (b *AESGCMBarrier) updateMasterKeyCommon(key []byte) (*Keyring, error) {
|
func (b *AESGCMBarrier) updateRootKeyCommon(key []byte) (*Keyring, error) {
|
||||||
if b.sealed {
|
if b.sealed {
|
||||||
return nil, ErrBarrierSealed
|
return nil, ErrBarrierSealed
|
||||||
}
|
}
|
||||||
|
@ -772,7 +772,7 @@ func (b *AESGCMBarrier) updateMasterKeyCommon(key []byte) (*Keyring, error) {
|
||||||
return nil, fmt.Errorf("key size must be %d or %d", min, max)
|
return nil, fmt.Errorf("key size must be %d or %d", min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.keyring.SetMasterKey(key), nil
|
return b.keyring.SetRootKey(key), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put is used to insert or update an entry
|
// Put is used to insert or update an entry
|
||||||
|
|
|
@ -245,8 +245,8 @@ func testInitAndUnseal(t *testing.T, b SecurityBarrier) (error, *logical.Storage
|
||||||
t.Fatalf("should be unsealed")
|
t.Fatalf("should be unsealed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the master key
|
// Verify the root key
|
||||||
if err := b.VerifyMaster(key); err != nil {
|
if err := b.VerifyRoot(key); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
return err, e, key
|
return err, e, key
|
||||||
|
@ -374,7 +374,7 @@ func testBarrier_Rekey(t *testing.T, b SecurityBarrier) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the master key
|
// Verify the master key
|
||||||
if err := b.VerifyMaster(key); err != nil {
|
if err := b.VerifyRoot(key); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,12 +386,12 @@ func testBarrier_Rekey(t *testing.T, b SecurityBarrier) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the old master key
|
// Verify the old master key
|
||||||
if err := b.VerifyMaster(key); err != ErrBarrierInvalidKey {
|
if err := b.VerifyRoot(key); err != ErrBarrierInvalidKey {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the new master key
|
// Verify the new master key
|
||||||
if err := b.VerifyMaster(newKey); err != nil {
|
if err := b.VerifyRoot(newKey); err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +530,7 @@ func testBarrier_Upgrade_Rekey(t *testing.T, b1, b2 SecurityBarrier) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload the master key
|
// Reload the master key
|
||||||
err = b2.ReloadMasterKey(context.Background())
|
err = b2.ReloadRootKey(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2547,7 +2547,7 @@ func (c *Core) adjustSealConfigDuringMigration(existBarrierSealConfig, existReco
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) unsealKeyToMasterKeyPostUnseal(ctx context.Context, combinedKey []byte) ([]byte, error) {
|
func (c *Core) unsealKeyToRootKeyPostUnseal(ctx context.Context, combinedKey []byte) ([]byte, error) {
|
||||||
return c.unsealKeyToMasterKey(ctx, c.seal, combinedKey, true, false)
|
return c.unsealKeyToMasterKey(ctx, c.seal, combinedKey, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2586,7 +2586,7 @@ func (c *Core) unsealKeyToMasterKey(ctx context.Context, seal Seal, combinedKey
|
||||||
}
|
}
|
||||||
return storedKeys[0], nil
|
return storedKeys[0], nil
|
||||||
|
|
||||||
case vaultseal.StoredKeysSupportedShamirMaster:
|
case vaultseal.StoredKeysSupportedShamirRoot:
|
||||||
if useTestSeal {
|
if useTestSeal {
|
||||||
testseal := NewDefaultSeal(&vaultseal.Access{
|
testseal := NewDefaultSeal(&vaultseal.Access{
|
||||||
Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{
|
Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{
|
||||||
|
|
|
@ -38,12 +38,12 @@ type GenerateRootStrategy interface {
|
||||||
type generateStandardRootToken struct{}
|
type generateStandardRootToken struct{}
|
||||||
|
|
||||||
func (g generateStandardRootToken) authenticate(ctx context.Context, c *Core, combinedKey []byte) error {
|
func (g generateStandardRootToken) authenticate(ctx context.Context, c *Core, combinedKey []byte) error {
|
||||||
masterKey, err := c.unsealKeyToMasterKeyPostUnseal(ctx, combinedKey)
|
rootKey, err := c.unsealKeyToRootKeyPostUnseal(ctx, combinedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to authenticate: %w", err)
|
return fmt.Errorf("unable to authenticate: %w", err)
|
||||||
}
|
}
|
||||||
if err := c.barrier.VerifyMaster(masterKey); err != nil {
|
if err := c.barrier.VerifyRoot(rootKey); err != nil {
|
||||||
return fmt.Errorf("master key verification failed: %w", err)
|
return fmt.Errorf("root key verification failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -303,7 +303,7 @@ func (c *Core) GenerateRootUpdate(ctx context.Context, key []byte, nonce string,
|
||||||
combinedKey, err = shamir.Combine(c.generateRootProgress)
|
combinedKey, err = shamir.Combine(c.generateRootProgress)
|
||||||
c.generateRootProgress = nil
|
c.generateRootProgress = nil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to compute master key: %w", err)
|
return nil, fmt.Errorf("failed to compute root key: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,12 @@ type generateRecoveryToken struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *generateRecoveryToken) authenticate(ctx context.Context, c *Core, combinedKey []byte) error {
|
func (g *generateRecoveryToken) authenticate(ctx context.Context, c *Core, combinedKey []byte) error {
|
||||||
key, err := c.unsealKeyToMasterKeyPostUnseal(ctx, combinedKey)
|
key, err := c.unsealKeyToRootKeyPostUnseal(ctx, combinedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to authenticate: %w", err)
|
return fmt.Errorf("unable to authenticate: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the retrieved master key to unseal the barrier
|
// Use the retrieved root key to unseal the barrier
|
||||||
if err := c.barrier.Unseal(ctx, key); err != nil {
|
if err := c.barrier.Unseal(ctx, key); err != nil {
|
||||||
return fmt.Errorf("recovery operation token generation failed, cannot unseal barrier: %w", err)
|
return fmt.Errorf("recovery operation token generation failed, cannot unseal barrier: %w", err)
|
||||||
}
|
}
|
||||||
|
|
14
vault/ha.go
14
vault/ha.go
|
@ -825,9 +825,9 @@ func (c *Core) checkKeyUpgrades(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) reloadMasterKey(ctx context.Context) error {
|
func (c *Core) reloadRootKey(ctx context.Context) error {
|
||||||
if err := c.barrier.ReloadMasterKey(ctx); err != nil {
|
if err := c.barrier.ReloadRootKey(ctx); err != nil {
|
||||||
return fmt.Errorf("error reloading master key: %w", err)
|
return fmt.Errorf("error reloading root key: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -841,7 +841,7 @@ func (c *Core) reloadShamirKey(ctx context.Context) error {
|
||||||
switch c.seal.StoredKeysSupported() {
|
switch c.seal.StoredKeysSupported() {
|
||||||
case seal.StoredKeysSupportedGeneric:
|
case seal.StoredKeysSupportedGeneric:
|
||||||
return nil
|
return nil
|
||||||
case seal.StoredKeysSupportedShamirMaster:
|
case seal.StoredKeysSupportedShamirRoot:
|
||||||
entry, err := c.barrier.Get(ctx, shamirKekPath)
|
entry, err := c.barrier.Get(ctx, shamirKekPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -855,7 +855,7 @@ func (c *Core) reloadShamirKey(ctx context.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to update seal access: %w", err)
|
return fmt.Errorf("failed to update seal access: %w", err)
|
||||||
}
|
}
|
||||||
shamirKey = keyring.masterKey
|
shamirKey = keyring.rootKey
|
||||||
}
|
}
|
||||||
return c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(shamirKey)
|
return c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(shamirKey)
|
||||||
}
|
}
|
||||||
|
@ -865,8 +865,8 @@ func (c *Core) performKeyUpgrades(ctx context.Context) error {
|
||||||
return fmt.Errorf("error checking for key upgrades: %w", err)
|
return fmt.Errorf("error checking for key upgrades: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.reloadMasterKey(ctx); err != nil {
|
if err := c.reloadRootKey(ctx); err != nil {
|
||||||
return fmt.Errorf("error reloading master key: %w", err)
|
return fmt.Errorf("error reloading root key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.barrier.ReloadKeyring(ctx); err != nil {
|
if err := c.barrier.ReloadKeyring(ctx); err != nil {
|
||||||
|
|
|
@ -122,19 +122,19 @@ func (c *Core) InitializedLocally(ctx context.Context) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) {
|
func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) {
|
||||||
// Generate a master key
|
// Generate a root key
|
||||||
masterKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
rootKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("key generation failed: %w", err)
|
return nil, nil, fmt.Errorf("key generation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the master key if only a single key part is used
|
// Return the root key if only a single key part is used
|
||||||
var unsealKeys [][]byte
|
var unsealKeys [][]byte
|
||||||
if sc.SecretShares == 1 {
|
if sc.SecretShares == 1 {
|
||||||
unsealKeys = append(unsealKeys, masterKey)
|
unsealKeys = append(unsealKeys, rootKey)
|
||||||
} else {
|
} else {
|
||||||
// Split the master key using the Shamir algorithm
|
// Split the root key using the Shamir algorithm
|
||||||
shares, err := shamir.Split(masterKey, sc.SecretShares, sc.SecretThreshold)
|
shares, err := shamir.Split(rootKey, sc.SecretShares, sc.SecretThreshold)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to generate barrier shares: %w", err)
|
return nil, nil, fmt.Errorf("failed to generate barrier shares: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) {
|
||||||
unsealKeys = encryptedShares
|
unsealKeys = encryptedShares
|
||||||
}
|
}
|
||||||
|
|
||||||
return masterKey, unsealKeys, nil
|
return rootKey, unsealKeys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize is used to initialize the Vault with the given
|
// Initialize is used to initialize the Vault with the given
|
||||||
|
@ -172,7 +172,7 @@ func (c *Core) Initialize(ctx context.Context, initParams *InitParams) (*InitRes
|
||||||
// N.B. Although the core is capable of handling situations where some keys
|
// N.B. Although the core is capable of handling situations where some keys
|
||||||
// are stored and some aren't, in practice, replication + HSMs makes this
|
// are stored and some aren't, in practice, replication + HSMs makes this
|
||||||
// extremely hard to reason about, to the point that it will probably never
|
// extremely hard to reason about, to the point that it will probably never
|
||||||
// be supported. The reason is that each HSM needs to encode the master key
|
// be supported. The reason is that each HSM needs to encode the root key
|
||||||
// separately, which means the shares must be generated independently,
|
// separately, which means the shares must be generated independently,
|
||||||
// which means both that the shares will be different *AND* there would
|
// which means both that the shares will be different *AND* there would
|
||||||
// need to be a way to actually allow fetching of the generated keys by
|
// need to be a way to actually allow fetching of the generated keys by
|
||||||
|
@ -322,7 +322,7 @@ func (c *Core) Initialize(ctx context.Context, initParams *InitParams) (*InitRes
|
||||||
// If we are storing shares, pop them out of the returned results and push
|
// If we are storing shares, pop them out of the returned results and push
|
||||||
// them through the seal
|
// them through the seal
|
||||||
switch c.seal.StoredKeysSupported() {
|
switch c.seal.StoredKeysSupported() {
|
||||||
case seal.StoredKeysSupportedShamirMaster:
|
case seal.StoredKeysSupportedShamirRoot:
|
||||||
keysToStore := [][]byte{barrierKey}
|
keysToStore := [][]byte{barrierKey}
|
||||||
if err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(sealKey); err != nil {
|
if err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(sealKey); err != nil {
|
||||||
c.logger.Error("failed to set seal key", "error", err)
|
c.logger.Error("failed to set seal key", "error", err)
|
||||||
|
|
|
@ -31,11 +31,11 @@ var (
|
||||||
// The term used to encrypt a key is prefixed to the key written out.
|
// The term used to encrypt a key is prefixed to the key written out.
|
||||||
// All data is encrypted with the latest key, but storing the old keys
|
// All data is encrypted with the latest key, but storing the old keys
|
||||||
// allows for decryption of keys written previously. Along with the encryption
|
// allows for decryption of keys written previously. Along with the encryption
|
||||||
// keys, the keyring also tracks the master key. This is necessary so that
|
// keys, the keyring also tracks the root key. This is necessary so that
|
||||||
// when a new key is added to the keyring, we can encrypt with the master key
|
// when a new key is added to the keyring, we can encrypt with the root key
|
||||||
// and write out the new keyring.
|
// and write out the new keyring.
|
||||||
type Keyring struct {
|
type Keyring struct {
|
||||||
masterKey []byte
|
rootKey []byte
|
||||||
keys map[uint32]*Key
|
keys map[uint32]*Key
|
||||||
activeTerm uint32
|
activeTerm uint32
|
||||||
rotationConfig KeyRotationConfig
|
rotationConfig KeyRotationConfig
|
||||||
|
@ -90,7 +90,7 @@ func NewKeyring() *Keyring {
|
||||||
// Clone returns a new copy of the keyring
|
// Clone returns a new copy of the keyring
|
||||||
func (k *Keyring) Clone() *Keyring {
|
func (k *Keyring) Clone() *Keyring {
|
||||||
clone := &Keyring{
|
clone := &Keyring{
|
||||||
masterKey: k.masterKey,
|
rootKey: k.rootKey,
|
||||||
keys: make(map[uint32]*Key, len(k.keys)),
|
keys: make(map[uint32]*Key, len(k.keys)),
|
||||||
activeTerm: k.activeTerm,
|
activeTerm: k.activeTerm,
|
||||||
rotationConfig: k.rotationConfig,
|
rotationConfig: k.rotationConfig,
|
||||||
|
@ -170,25 +170,25 @@ func (k *Keyring) TermKey(term uint32) *Key {
|
||||||
return k.keys[term]
|
return k.keys[term]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMasterKey is used to update the master key
|
// SetRootKey is used to update the root key
|
||||||
func (k *Keyring) SetMasterKey(val []byte) *Keyring {
|
func (k *Keyring) SetRootKey(val []byte) *Keyring {
|
||||||
valCopy := make([]byte, len(val))
|
valCopy := make([]byte, len(val))
|
||||||
copy(valCopy, val)
|
copy(valCopy, val)
|
||||||
clone := k.Clone()
|
clone := k.Clone()
|
||||||
clone.masterKey = valCopy
|
clone.rootKey = valCopy
|
||||||
return clone
|
return clone
|
||||||
}
|
}
|
||||||
|
|
||||||
// MasterKey returns the master key
|
// RootKey returns the root key
|
||||||
func (k *Keyring) MasterKey() []byte {
|
func (k *Keyring) RootKey() []byte {
|
||||||
return k.masterKey
|
return k.rootKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize is used to create a byte encoded keyring
|
// Serialize is used to create a byte encoded keyring
|
||||||
func (k *Keyring) Serialize() ([]byte, error) {
|
func (k *Keyring) Serialize() ([]byte, error) {
|
||||||
// Create the encoded entry
|
// Create the encoded entry
|
||||||
enc := EncodedKeyring{
|
enc := EncodedKeyring{
|
||||||
MasterKey: k.masterKey,
|
MasterKey: k.rootKey,
|
||||||
RotationConfig: k.rotationConfig,
|
RotationConfig: k.rotationConfig,
|
||||||
}
|
}
|
||||||
for _, key := range k.keys {
|
for _, key := range k.keys {
|
||||||
|
@ -210,7 +210,7 @@ func DeserializeKeyring(buf []byte) (*Keyring, error) {
|
||||||
|
|
||||||
// Create a new keyring
|
// Create a new keyring
|
||||||
k := NewKeyring()
|
k := NewKeyring()
|
||||||
k.masterKey = enc.MasterKey
|
k.rootKey = enc.MasterKey
|
||||||
k.rotationConfig = enc.RotationConfig
|
k.rotationConfig = enc.RotationConfig
|
||||||
k.rotationConfig.Sanitize()
|
k.rotationConfig.Sanitize()
|
||||||
for _, key := range enc.Keys {
|
for _, key := range enc.Keys {
|
||||||
|
@ -229,8 +229,8 @@ func (k *Keyring) Zeroize(keysToo bool) {
|
||||||
if k == nil {
|
if k == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if k.masterKey != nil {
|
if k.rootKey != nil {
|
||||||
memzero(k.masterKey)
|
memzero(k.rootKey)
|
||||||
}
|
}
|
||||||
if !keysToo || k.keys == nil {
|
if !keysToo || k.keys == nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -113,21 +113,21 @@ func TestKeyring_MasterKey(t *testing.T) {
|
||||||
master2 := []byte("test2")
|
master2 := []byte("test2")
|
||||||
|
|
||||||
// Check no master
|
// Check no master
|
||||||
out := k.MasterKey()
|
out := k.RootKey()
|
||||||
if out != nil {
|
if out != nil {
|
||||||
t.Fatalf("bad: %v", out)
|
t.Fatalf("bad: %v", out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set master
|
// Set master
|
||||||
k = k.SetMasterKey(master)
|
k = k.SetRootKey(master)
|
||||||
out = k.MasterKey()
|
out = k.RootKey()
|
||||||
if !bytes.Equal(out, master) {
|
if !bytes.Equal(out, master) {
|
||||||
t.Fatalf("bad: %v", out)
|
t.Fatalf("bad: %v", out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update master
|
// Update master
|
||||||
k = k.SetMasterKey(master2)
|
k = k.SetRootKey(master2)
|
||||||
out = k.MasterKey()
|
out = k.RootKey()
|
||||||
if !bytes.Equal(out, master2) {
|
if !bytes.Equal(out, master2) {
|
||||||
t.Fatalf("bad: %v", out)
|
t.Fatalf("bad: %v", out)
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ func TestKeyring_MasterKey(t *testing.T) {
|
||||||
func TestKeyring_Serialize(t *testing.T) {
|
func TestKeyring_Serialize(t *testing.T) {
|
||||||
k := NewKeyring()
|
k := NewKeyring()
|
||||||
master := []byte("test")
|
master := []byte("test")
|
||||||
k = k.SetMasterKey(master)
|
k = k.SetRootKey(master)
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
testKey := []byte("testing")
|
testKey := []byte("testing")
|
||||||
|
@ -154,7 +154,7 @@ func TestKeyring_Serialize(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
out := k2.MasterKey()
|
out := k2.RootKey()
|
||||||
if !bytes.Equal(out, master) {
|
if !bytes.Equal(out, master) {
|
||||||
t.Fatalf("bad: %v", out)
|
t.Fatalf("bad: %v", out)
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,7 +156,7 @@ func (b *SystemBackend) configPaths() []*framework.Path {
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
"key": {
|
"key": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
Description: "Specifies a single master key share.",
|
Description: "Specifies a single unseal key share.",
|
||||||
},
|
},
|
||||||
"nonce": {
|
"nonce": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
|
@ -165,8 +165,8 @@ func (b *SystemBackend) configPaths() []*framework.Path {
|
||||||
},
|
},
|
||||||
Operations: map[logical.Operation]framework.OperationHandler{
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
logical.UpdateOperation: &framework.PathOperation{
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
Summary: "Enter a single master key share to progress the root generation attempt.",
|
Summary: "Enter a single unseal key share to progress the root generation attempt.",
|
||||||
Description: "If the threshold number of master key shares is reached, Vault will complete the root generation and issue the new token. Otherwise, this API must be called multiple times until that threshold is met. The attempt nonce must be provided with each call.",
|
Description: "If the threshold number of unseal key shares is reached, Vault will complete the root generation and issue the new token. Otherwise, this API must be called multiple times until that threshold is met. The attempt nonce must be provided with each call.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -239,11 +239,11 @@ func (b *SystemBackend) configPaths() []*framework.Path {
|
||||||
},
|
},
|
||||||
"secret_shares": {
|
"secret_shares": {
|
||||||
Type: framework.TypeInt,
|
Type: framework.TypeInt,
|
||||||
Description: "Specifies the number of shares to split the master key into.",
|
Description: "Specifies the number of shares to split the unseal key into.",
|
||||||
},
|
},
|
||||||
"secret_threshold": {
|
"secret_threshold": {
|
||||||
Type: framework.TypeInt,
|
Type: framework.TypeInt,
|
||||||
Description: "Specifies the number of shares required to reconstruct the master key. This must be less than or equal secret_shares. If using Vault HSM with auto-unsealing, this value must be the same as `secret_shares`.",
|
Description: "Specifies the number of shares required to reconstruct the unseal key. This must be less than or equal secret_shares. If using Vault HSM with auto-unsealing, this value must be the same as `secret_shares`.",
|
||||||
},
|
},
|
||||||
"stored_shares": {
|
"stored_shares": {
|
||||||
Type: framework.TypeInt,
|
Type: framework.TypeInt,
|
||||||
|
@ -299,11 +299,11 @@ func (b *SystemBackend) rekeyPaths() []*framework.Path {
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
"secret_shares": {
|
"secret_shares": {
|
||||||
Type: framework.TypeInt,
|
Type: framework.TypeInt,
|
||||||
Description: "Specifies the number of shares to split the master key into.",
|
Description: "Specifies the number of shares to split the unseal key into.",
|
||||||
},
|
},
|
||||||
"secret_threshold": {
|
"secret_threshold": {
|
||||||
Type: framework.TypeInt,
|
Type: framework.TypeInt,
|
||||||
Description: "Specifies the number of shares required to reconstruct the master key. This must be less than or equal secret_shares. If using Vault HSM with auto-unsealing, this value must be the same as secret_shares.",
|
Description: "Specifies the number of shares required to reconstruct the unseal key. This must be less than or equal secret_shares. If using Vault HSM with auto-unsealing, this value must be the same as secret_shares.",
|
||||||
},
|
},
|
||||||
"pgp_keys": {
|
"pgp_keys": {
|
||||||
Type: framework.TypeCommaStringSlice,
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
@ -372,7 +372,7 @@ func (b *SystemBackend) rekeyPaths() []*framework.Path {
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
"key": {
|
"key": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
Description: "Specifies a single master key share.",
|
Description: "Specifies a single unseal key share.",
|
||||||
},
|
},
|
||||||
"nonce": {
|
"nonce": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
|
@ -382,7 +382,7 @@ func (b *SystemBackend) rekeyPaths() []*framework.Path {
|
||||||
|
|
||||||
Operations: map[logical.Operation]framework.OperationHandler{
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
logical.UpdateOperation: &framework.PathOperation{
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
Summary: "Enter a single master key share to progress the rekey of the Vault.",
|
Summary: "Enter a single unseal key share to progress the rekey of the Vault.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -392,7 +392,7 @@ func (b *SystemBackend) rekeyPaths() []*framework.Path {
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
"key": {
|
"key": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
Description: "Specifies a single master share key from the new set of shares.",
|
Description: "Specifies a single unseal share key from the new set of shares.",
|
||||||
},
|
},
|
||||||
"nonce": {
|
"nonce": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
|
@ -430,7 +430,7 @@ func (b *SystemBackend) rekeyPaths() []*framework.Path {
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
"key": {
|
"key": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
Description: "Specifies a single master key share. This is required unless reset is true.",
|
Description: "Specifies a single unseal key share. This is required unless reset is true.",
|
||||||
},
|
},
|
||||||
"reset": {
|
"reset": {
|
||||||
Type: framework.TypeBool,
|
Type: framework.TypeBool,
|
||||||
|
|
|
@ -605,7 +605,7 @@ func (c *Core) checkRaftTLSKeyUpgrades(ctx context.Context) error {
|
||||||
|
|
||||||
// handleSnapshotRestore is for the raft backend to hook back into core after a
|
// handleSnapshotRestore is for the raft backend to hook back into core after a
|
||||||
// snapshot is restored so we can clear the necessary caches and handle changing
|
// snapshot is restored so we can clear the necessary caches and handle changing
|
||||||
// keyrings or master keys
|
// keyrings or root keys
|
||||||
func (c *Core) raftSnapshotRestoreCallback(grabLock bool, sealNode bool) func(context.Context) error {
|
func (c *Core) raftSnapshotRestoreCallback(grabLock bool, sealNode bool) func(context.Context) error {
|
||||||
return func(ctx context.Context) (retErr error) {
|
return func(ctx context.Context) (retErr error) {
|
||||||
c.logger.Info("running post snapshot restore invalidations")
|
c.logger.Info("running post snapshot restore invalidations")
|
||||||
|
@ -635,10 +635,10 @@ func (c *Core) raftSnapshotRestoreCallback(grabLock bool, sealNode bool) func(co
|
||||||
c.physicalCache.Purge(ctx)
|
c.physicalCache.Purge(ctx)
|
||||||
|
|
||||||
// Reload the keyring in case it changed. If this fails it's likely
|
// Reload the keyring in case it changed. If this fails it's likely
|
||||||
// we've changed master keys.
|
// we've changed root keys.
|
||||||
err := c.performKeyUpgrades(ctx)
|
err := c.performKeyUpgrades(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// The snapshot contained a master key or keyring we couldn't
|
// The snapshot contained a root key or keyring we couldn't
|
||||||
// recover
|
// recover
|
||||||
switch c.seal.BarrierType() {
|
switch c.seal.BarrierType() {
|
||||||
case wrapping.Shamir:
|
case wrapping.Shamir:
|
||||||
|
@ -667,7 +667,7 @@ func (c *Core) raftSnapshotRestoreCallback(grabLock bool, sealNode bool) func(co
|
||||||
c.logger.Error("raft snapshot restore failed to unseal barrier", "error", err)
|
c.logger.Error("raft snapshot restore failed to unseal barrier", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.logger.Info("done reloading master key using auto seal")
|
c.logger.Info("done reloading root key using auto seal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,7 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string)
|
||||||
// Get the seal configuration
|
// Get the seal configuration
|
||||||
var existingConfig *SealConfig
|
var existingConfig *SealConfig
|
||||||
var err error
|
var err error
|
||||||
var useRecovery bool // Determines whether recovery key is being used to rekey the master key
|
var useRecovery bool // Determines whether recovery key is being used to rekey the root key
|
||||||
if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedGeneric && c.seal.RecoveryKeySupported() {
|
if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedGeneric && c.seal.RecoveryKeySupported() {
|
||||||
existingConfig, err = c.seal.RecoveryConfig(ctx)
|
existingConfig, err = c.seal.RecoveryConfig(ctx)
|
||||||
useRecovery = true
|
useRecovery = true
|
||||||
|
@ -377,7 +377,7 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recover the master key or recovery key
|
// Recover the root key or recovery key
|
||||||
var recoveredKey []byte
|
var recoveredKey []byte
|
||||||
if existingConfig.SecretThreshold == 1 {
|
if existingConfig.SecretThreshold == 1 {
|
||||||
recoveredKey = c.barrierRekeyConfig.RekeyProgress[0]
|
recoveredKey = c.barrierRekeyConfig.RekeyProgress[0]
|
||||||
|
@ -386,7 +386,7 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string)
|
||||||
recoveredKey, err = shamir.Combine(c.barrierRekeyConfig.RekeyProgress)
|
recoveredKey, err = shamir.Combine(c.barrierRekeyConfig.RekeyProgress)
|
||||||
c.barrierRekeyConfig.RekeyProgress = nil
|
c.barrierRekeyConfig.RekeyProgress = nil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to compute master key: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to compute root key: %w", err).Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +397,7 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string)
|
||||||
return nil, logical.CodedError(http.StatusBadRequest, fmt.Errorf("recovery key verification failed: %w", err).Error())
|
return nil, logical.CodedError(http.StatusBadRequest, fmt.Errorf("recovery key verification failed: %w", err).Error())
|
||||||
}
|
}
|
||||||
case c.seal.BarrierType() == wrapping.Shamir:
|
case c.seal.BarrierType() == wrapping.Shamir:
|
||||||
if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedShamirMaster {
|
if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedShamirRoot {
|
||||||
testseal := NewDefaultSeal(&seal.Access{
|
testseal := NewDefaultSeal(&seal.Access{
|
||||||
Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{
|
Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{
|
||||||
Logger: c.logger.Named("testseal"),
|
Logger: c.logger.Named("testseal"),
|
||||||
|
@ -415,23 +415,23 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string)
|
||||||
testseal.SetCachedBarrierConfig(cfg)
|
testseal.SetCachedBarrierConfig(cfg)
|
||||||
stored, err := testseal.GetStoredKeys(ctx)
|
stored, err := testseal.GetStoredKeys(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to read master key: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to read root key: %w", err).Error())
|
||||||
}
|
}
|
||||||
recoveredKey = stored[0]
|
recoveredKey = stored[0]
|
||||||
}
|
}
|
||||||
if err := c.barrier.VerifyMaster(recoveredKey); err != nil {
|
if err := c.barrier.VerifyRoot(recoveredKey); err != nil {
|
||||||
c.logger.Error("master key verification failed", "error", err)
|
c.logger.Error("root key verification failed", "error", err)
|
||||||
return nil, logical.CodedError(http.StatusBadRequest, fmt.Errorf("master key verification failed: %w", err).Error())
|
return nil, logical.CodedError(http.StatusBadRequest, fmt.Errorf("rootter key verification failed: %w", err).Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new key: for AutoUnseal, this is a new master key; for Shamir,
|
// Generate a new key: for AutoUnseal, this is a new root key; for Shamir,
|
||||||
// this is a new unseal key, and performBarrierRekey will also generate a
|
// this is a new unseal key, and performBarrierRekey will also generate a
|
||||||
// new master key.
|
// new root key.
|
||||||
newKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
newKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("failed to generate master key", "error", err)
|
c.logger.Error("failed to generate root key", "error", err)
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("master key generation failed: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("root key generation failed: %w", err).Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
results := &RekeyResult{
|
results := &RekeyResult{
|
||||||
|
@ -538,17 +538,17 @@ func (c *Core) performBarrierRekey(ctx context.Context, newSealKey []byte) logic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newMasterKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
newRootKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to perform rekey: %w", err).Error())
|
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to perform rekey: %w", err).Error())
|
||||||
}
|
}
|
||||||
if err := c.seal.SetStoredKeys(ctx, [][]byte{newMasterKey}); err != nil {
|
if err := c.seal.SetStoredKeys(ctx, [][]byte{newRootKey}); err != nil {
|
||||||
c.logger.Error("failed to store keys", "error", err)
|
c.logger.Error("failed to store keys", "error", err)
|
||||||
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to store keys: %w", err).Error())
|
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to store keys: %w", err).Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rekey the barrier
|
// Rekey the barrier
|
||||||
if err := c.barrier.Rekey(ctx, newMasterKey); err != nil {
|
if err := c.barrier.Rekey(ctx, newRootKey); err != nil {
|
||||||
c.logger.Error("failed to rekey barrier", "error", err)
|
c.logger.Error("failed to rekey barrier", "error", err)
|
||||||
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to rekey barrier: %w", err).Error())
|
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to rekey barrier: %w", err).Error())
|
||||||
}
|
}
|
||||||
|
@ -655,7 +655,7 @@ func (c *Core) RecoveryRekeyUpdate(ctx context.Context, key []byte, nonce string
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recover the master key
|
// Recover the root key
|
||||||
var recoveryKey []byte
|
var recoveryKey []byte
|
||||||
if existingConfig.SecretThreshold == 1 {
|
if existingConfig.SecretThreshold == 1 {
|
||||||
recoveryKey = c.recoveryRekeyConfig.RekeyProgress[0]
|
recoveryKey = c.recoveryRekeyConfig.RekeyProgress[0]
|
||||||
|
@ -674,23 +674,23 @@ func (c *Core) RecoveryRekeyUpdate(ctx context.Context, key []byte, nonce string
|
||||||
return nil, logical.CodedError(http.StatusBadRequest, fmt.Errorf("recovery key verification failed: %w", err).Error())
|
return nil, logical.CodedError(http.StatusBadRequest, fmt.Errorf("recovery key verification failed: %w", err).Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new master key
|
// Generate a new root key
|
||||||
newMasterKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
newRecoveryKey, err := c.barrier.GenerateKey(c.secureRandomReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("failed to generate recovery key", "error", err)
|
c.logger.Error("failed to generate recovery key", "error", err)
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("recovery key generation failed: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("recovery key generation failed: %w", err).Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the master key if only a single key part is used
|
// Return the root key if only a single key part is used
|
||||||
results := &RekeyResult{
|
results := &RekeyResult{
|
||||||
Backup: c.recoveryRekeyConfig.Backup,
|
Backup: c.recoveryRekeyConfig.Backup,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.recoveryRekeyConfig.SecretShares == 1 {
|
if c.recoveryRekeyConfig.SecretShares == 1 {
|
||||||
results.SecretShares = append(results.SecretShares, newMasterKey)
|
results.SecretShares = append(results.SecretShares, newRecoveryKey)
|
||||||
} else {
|
} else {
|
||||||
// Split the master key using the Shamir algorithm
|
// Split the root key using the Shamir algorithm
|
||||||
shares, err := shamir.Split(newMasterKey, c.recoveryRekeyConfig.SecretShares, c.recoveryRekeyConfig.SecretThreshold)
|
shares, err := shamir.Split(newRecoveryKey, c.recoveryRekeyConfig.SecretShares, c.recoveryRekeyConfig.SecretThreshold)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("failed to generate shares", "error", err)
|
c.logger.Error("failed to generate shares", "error", err)
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to generate shares: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to generate shares: %w", err).Error())
|
||||||
|
@ -748,14 +748,14 @@ func (c *Core) RecoveryRekeyUpdate(ctx context.Context, key []byte, nonce string
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to generate verification nonce: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to generate verification nonce: %w", err).Error())
|
||||||
}
|
}
|
||||||
c.recoveryRekeyConfig.VerificationNonce = nonce
|
c.recoveryRekeyConfig.VerificationNonce = nonce
|
||||||
c.recoveryRekeyConfig.VerificationKey = newMasterKey
|
c.recoveryRekeyConfig.VerificationKey = newRecoveryKey
|
||||||
|
|
||||||
results.VerificationRequired = true
|
results.VerificationRequired = true
|
||||||
results.VerificationNonce = nonce
|
results.VerificationNonce = nonce
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.performRecoveryRekey(ctx, newMasterKey); err != nil {
|
if err := c.performRecoveryRekey(ctx, newRecoveryKey); err != nil {
|
||||||
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to perform recovery rekey: %w", err).Error())
|
return nil, logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to perform recovery rekey: %w", err).Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,8 +763,8 @@ func (c *Core) RecoveryRekeyUpdate(ctx context.Context, key []byte, nonce string
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) performRecoveryRekey(ctx context.Context, newMasterKey []byte) logical.HTTPCodedError {
|
func (c *Core) performRecoveryRekey(ctx context.Context, newRootKey []byte) logical.HTTPCodedError {
|
||||||
if err := c.seal.SetRecoveryKey(ctx, newMasterKey); err != nil {
|
if err := c.seal.SetRecoveryKey(ctx, newRootKey); err != nil {
|
||||||
c.logger.Error("failed to set recovery key", "error", err)
|
c.logger.Error("failed to set recovery key", "error", err)
|
||||||
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to set recovery key: %w", err).Error())
|
return logical.CodedError(http.StatusInternalServerError, fmt.Errorf("failed to set recovery key: %w", err).Error())
|
||||||
}
|
}
|
||||||
|
@ -867,7 +867,7 @@ func (c *Core) RekeyVerify(ctx context.Context, key []byte, nonce string, recove
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Recover the master key or recovery key
|
// Recover the root key or recovery key
|
||||||
var recoveredKey []byte
|
var recoveredKey []byte
|
||||||
if config.SecretThreshold == 1 {
|
if config.SecretThreshold == 1 {
|
||||||
recoveredKey = config.VerificationProgress[0]
|
recoveredKey = config.VerificationProgress[0]
|
||||||
|
|
|
@ -23,7 +23,7 @@ const (
|
||||||
// barrierSealConfigPath is the path used to store our seal configuration.
|
// barrierSealConfigPath is the path used to store our seal configuration.
|
||||||
// This value is stored in plaintext, since we must be able to read it even
|
// This value is stored in plaintext, since we must be able to read it even
|
||||||
// with the Vault sealed. This is required so that we know how many secret
|
// with the Vault sealed. This is required so that we know how many secret
|
||||||
// parts must be used to reconstruct the master key.
|
// parts must be used to reconstruct the unseal key.
|
||||||
barrierSealConfigPath = "core/seal-config"
|
barrierSealConfigPath = "core/seal-config"
|
||||||
|
|
||||||
// recoverySealConfigPath is the path to the recovery key seal
|
// recoverySealConfigPath is the path to the recovery key seal
|
||||||
|
@ -132,7 +132,7 @@ func (d *defaultSeal) StoredKeysSupported() seal.StoredKeysSupport {
|
||||||
case d.LegacySeal():
|
case d.LegacySeal():
|
||||||
return seal.StoredKeysNotSupported
|
return seal.StoredKeysNotSupported
|
||||||
default:
|
default:
|
||||||
return seal.StoredKeysSupportedShamirMaster
|
return seal.StoredKeysSupportedShamirRoot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ const (
|
||||||
StoredKeysInvalid StoredKeysSupport = iota
|
StoredKeysInvalid StoredKeysSupport = iota
|
||||||
StoredKeysNotSupported
|
StoredKeysNotSupported
|
||||||
StoredKeysSupportedGeneric
|
StoredKeysSupportedGeneric
|
||||||
StoredKeysSupportedShamirMaster
|
StoredKeysSupportedShamirRoot
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s StoredKeysSupport) String() string {
|
func (s StoredKeysSupport) String() string {
|
||||||
|
@ -24,7 +24,7 @@ func (s StoredKeysSupport) String() string {
|
||||||
return "Old-style Shamir"
|
return "Old-style Shamir"
|
||||||
case StoredKeysSupportedGeneric:
|
case StoredKeysSupportedGeneric:
|
||||||
return "AutoUnseal"
|
return "AutoUnseal"
|
||||||
case StoredKeysSupportedShamirMaster:
|
case StoredKeysSupportedShamirRoot:
|
||||||
return "New-style Shamir"
|
return "New-style Shamir"
|
||||||
default:
|
default:
|
||||||
return "Invalid StoredKeys type"
|
return "Invalid StoredKeys type"
|
||||||
|
|
|
@ -12,7 +12,7 @@ func TestCoreUnsealedWithConfigs(t testing.T, barrierConf, recoveryConf *SealCon
|
||||||
t.Helper()
|
t.Helper()
|
||||||
opts := &seal.TestSealOpts{}
|
opts := &seal.TestSealOpts{}
|
||||||
if recoveryConf == nil {
|
if recoveryConf == nil {
|
||||||
opts.StoredKeys = seal.StoredKeysSupportedShamirMaster
|
opts.StoredKeys = seal.StoredKeysSupportedShamirRoot
|
||||||
}
|
}
|
||||||
return TestCoreUnsealedWithConfigSealOpts(t, barrierConf, recoveryConf, opts)
|
return TestCoreUnsealedWithConfigSealOpts(t, barrierConf, recoveryConf, opts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch opts.StoredKeys {
|
switch opts.StoredKeys {
|
||||||
case seal.StoredKeysSupportedShamirMaster:
|
case seal.StoredKeysSupportedShamirRoot:
|
||||||
newSeal := NewDefaultSeal(&seal.Access{
|
newSeal := NewDefaultSeal(&seal.Access{
|
||||||
Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{
|
Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{
|
||||||
Logger: opts.Logger,
|
Logger: opts.Logger,
|
||||||
|
|
Loading…
Reference in New Issue