vault: adding ability to reload master key

This commit is contained in:
Armon Dadgar 2015-05-29 14:29:55 -07:00
parent 716f8d9979
commit f6729b29f8
4 changed files with 126 additions and 0 deletions

View File

@ -43,6 +43,15 @@ const (
// are deleted after a few minutes, but this provides enough time for the
// standby instances to upgrade without causing any disruption.
keyringUpgradePrefix = "core/upgrade/"
// masterKeyPath is the location of the master key. This is encrypted
// 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,
// 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
// keyring to discover the new master key. The new master key is then
// used to reload the keyring itself.
masterKeyPath = "core/master"
)
// SecurityBarrier is a critical component of Vault. It is used to wrap
@ -82,6 +91,11 @@ type SecurityBarrier interface {
// is present in the leader.
ReloadKeyring() error
// ReloadMasterKey is used to re-read the underlying masterkey.
// This is used for HA deployments to ensure the latest master key
// is available for keyring reloading.
ReloadMasterKey() error
// Seal is used to re-seal the barrier. This requires the barrier to
// be unsealed again to perform any further operations.
Seal() error

View File

@ -1,6 +1,7 @@
package vault
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
@ -150,6 +151,35 @@ func (b *AESGCMBarrier) persistKeyring(keyring *Keyring) error {
if err := b.backend.Put(pe); err != nil {
return fmt.Errorf("failed to persist keyring: %v", err)
}
// Serialize the master key value
key := &Key{
Term: 1,
Version: 1,
Value: keyring.MasterKey(),
}
buf, err = key.Serialize()
if err != nil {
return fmt.Errorf("failed to serialize master key: %v", err)
}
defer memzero(buf)
// Encrypt the master key
activeKey := keyring.ActiveKey()
aead, err := b.aeadFromKey(activeKey.Value)
if err != nil {
return err
}
value = b.encrypt(activeKey.Term, aead, buf)
// Update the masterKeyPath for standby instances
pe = &physical.Entry{
Key: masterKeyPath,
Value: value,
}
if err := b.backend.Put(pe); err != nil {
return fmt.Errorf("failed to persist master key: %v", err)
}
return nil
}
@ -227,6 +257,42 @@ func (b *AESGCMBarrier) ReloadKeyring() error {
return nil
}
// ReloadMasterKey is used to re-read the underlying masterkey.
// This is used for HA deployments to ensure the latest master key
// is available for keyring reloading.
func (b *AESGCMBarrier) ReloadMasterKey() error {
// Read the masterKeyPath upgrade
out, err := b.Get(masterKeyPath)
if err != nil {
return fmt.Errorf("failed to read master key path: %v", err)
}
// The masterKeyPath could be missing (backwards incompatable),
// we can ignore this and attempt to make progress with the current
// master key.
if out == nil {
return nil
}
// Deserialize the master key
key, err := DeserializeKey(out.Value)
if err != nil {
return fmt.Errorf("failed to deserialize key: %v", err)
}
b.l.Lock()
defer b.l.Unlock()
// Check if the master key is the same
if bytes.Equal(b.keyring.MasterKey(), key.Value) {
return nil
}
// Update the master key
b.keyring = b.keyring.SetMasterKey(key.Value)
return nil
}
// Unseal is used to provide the master key which permits the barrier
// to be unsealed. If the key is not correct, the barrier remains sealed.
func (b *AESGCMBarrier) Unseal(key []byte) error {

View File

@ -54,6 +54,19 @@ func TestAESGCMBarrier_Upgrade(t *testing.T) {
testBarrier_Upgrade(t, b1, b2)
}
func TestAESGCMBarrier_Upgrade_Rekey(t *testing.T) {
inm := physical.NewInmem()
b1, err := NewAESGCMBarrier(inm)
if err != nil {
t.Fatalf("err: %v", err)
}
b2, err := NewAESGCMBarrier(inm)
if err != nil {
t.Fatalf("err: %v", err)
}
testBarrier_Upgrade_Rekey(t, b1, b2)
}
func TestAESGCMBarrier_Rekey(t *testing.T) {
inm := physical.NewInmem()
b, err := NewAESGCMBarrier(inm)

View File

@ -496,3 +496,36 @@ func testBarrier_Upgrade(t *testing.T, b1, b2 SecurityBarrier) {
t.Fatalf("should not have upgrade")
}
}
func testBarrier_Upgrade_Rekey(t *testing.T, b1, b2 SecurityBarrier) {
// Initialize the barrier
key, _ := b1.GenerateKey()
b1.Initialize(key)
err := b1.Unseal(key)
if err != nil {
t.Fatalf("err: %v", err)
}
err = b2.Unseal(key)
if err != nil {
t.Fatalf("err: %v", err)
}
// Rekey to a new key
newKey, _ := b1.GenerateKey()
err = b1.Rekey(newKey)
if err != nil {
t.Fatalf("err: %v", err)
}
// Reload the master key
err = b2.ReloadMasterKey()
if err != nil {
t.Fatalf("err: %v", err)
}
// Reload the keyring
err = b2.ReloadKeyring()
if err != nil {
t.Fatalf("err: %v", err)
}
}