vault: moving upgrade path into barrier

This commit is contained in:
Armon Dadgar 2015-05-28 16:42:32 -07:00
parent 82ef0b1ac7
commit 67ed0a3c16
4 changed files with 179 additions and 40 deletions

View File

@ -88,11 +88,16 @@ type SecurityBarrier interface {
// Rotate is used to create a new encryption key. All future writes
// should use the new key, while old values should still be decryptable.
Rotate() error
Rotate() (uint32, error)
// AddKey is used to add a new key to the keyring. This assumes the keyring
// has already been updated and does not persist a new keyring.
AddKey(k *Key) error
// CreateUpgrade creates an upgrade path key to the given term from the previous term
CreateUpgrade(term uint32) error
// DestroyUpgrade destroys the upgrade path key to the given term
DestroyUpgrade(term uint32) error
// CheckUpgrade looks for an upgrade to the current term and installs it
CheckUpgrade() (bool, uint32, error)
// ActiveKeyInfo is used to inform details about the active key
ActiveKeyInfo() (*KeyInfo, error)

View File

@ -339,54 +339,123 @@ func (b *AESGCMBarrier) Seal() error {
// Rotate is used to create a new encryption key. All future writes
// should use the new key, while old values should still be decryptable.
func (b *AESGCMBarrier) Rotate() error {
func (b *AESGCMBarrier) Rotate() (uint32, error) {
b.l.Lock()
defer b.l.Unlock()
if b.sealed {
return ErrBarrierSealed
return 0, ErrBarrierSealed
}
// Generate a new key
encrypt, err := b.GenerateKey()
if err != nil {
return fmt.Errorf("failed to generate encryption key: %v", err)
return 0, fmt.Errorf("failed to generate encryption key: %v", err)
}
// Get the next term
term := b.keyring.ActiveTerm()
newTerm := term + 1
// Add a new encryption key
newKeyring, err := b.keyring.AddKey(&Key{
Term: term + 1,
Term: newTerm,
Version: 1,
Value: encrypt,
})
if err != nil {
return fmt.Errorf("failed to add new encryption key: %v", err)
return 0, fmt.Errorf("failed to add new encryption key: %v", err)
}
// Persist the new keyring
if err := b.persistKeyring(newKeyring); err != nil {
return err
return 0, err
}
// Swap the keyrings
b.keyring = newKeyring
return nil
return newTerm, nil
}
// AddKey is used to add a new key to the keyring. This assumes the keyring
// has already been updated and does not persist a new keyring.
func (b *AESGCMBarrier) AddKey(k *Key) error {
// CreateUpgrade creates an upgrade path key to the given term from the previous term
func (b *AESGCMBarrier) CreateUpgrade(term uint32) error {
b.l.RLock()
defer b.l.RUnlock()
if b.sealed {
return ErrBarrierSealed
}
// Get the key for this term
termKey := b.keyring.TermKey(term)
buf, err := termKey.Serialize()
if err != nil {
return err
}
// Get the AEAD for the previous term
prevTerm := term - 1
primary, err := b.aeadForTerm(prevTerm)
if err != nil {
return err
}
// Create upgrade key
pe := &physical.Entry{
Key: fmt.Sprintf("%s%d", keyringUpgradePrefix, prevTerm),
Value: b.encrypt(prevTerm, primary, buf),
}
return b.backend.Put(pe)
}
// DestroyUpgrade destroys the upgrade path key to the given term
func (b *AESGCMBarrier) DestroyUpgrade(term uint32) error {
path := fmt.Sprintf("%s%d", keyringUpgradePrefix, term-1)
return b.Delete(path)
}
// CheckUpgrade looks for an upgrade to the current term and installs it
func (b *AESGCMBarrier) CheckUpgrade() (bool, uint32, error) {
b.l.RLock()
defer b.l.RUnlock()
if b.sealed {
return false, 0, ErrBarrierSealed
}
// Get the current term
activeTerm := b.keyring.ActiveTerm()
// Check for an upgrade key
upgrade := fmt.Sprintf("%s%d", keyringUpgradePrefix, activeTerm)
entry, err := b.Get(upgrade)
if err != nil {
return false, 0, err
}
// Nothing to do if no upgrade
if entry == nil {
return false, 0, nil
}
// Deserialize the key
key, err := DeserializeKey(entry.Value)
if err != nil {
return false, 0, err
}
// Upgrade from read lock to write lock
b.l.RUnlock()
defer b.l.RLock()
b.l.Lock()
defer b.l.Unlock()
newKeyring, err := b.keyring.AddKey(k)
// Update the keyring
newKeyring, err := b.keyring.AddKey(key)
if err != nil {
return fmt.Errorf("failed to add new encryption key: %v", err)
return false, 0, fmt.Errorf("failed to add new encryption key: %v", err)
}
b.keyring = newKeyring
return nil
// Done!
return true, key.Term, nil
}
// ActiveKeyInfo is used to inform details about the active key

View File

@ -41,6 +41,19 @@ func TestAESGCMBarrier_Rotate(t *testing.T) {
testBarrier_Rotate(t, b)
}
func TestAESGCMBarrier_Upgrade(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(t, b1, b2)
}
func TestAESGCMBarrier_Rekey(t *testing.T) {
inm := physical.NewInmem()
b, err := NewAESGCMBarrier(inm)

View File

@ -269,10 +269,13 @@ func testBarrier_Rotate(t *testing.T, b SecurityBarrier) {
}
// Rotate the encryption key
err = b.Rotate()
newTerm, err := b.Rotate()
if err != nil {
t.Fatalf("err: %v", err)
}
if newTerm != 2 {
t.Fatalf("bad: %v", newTerm)
}
// Check the key info
info, err = b.ActiveKeyInfo()
@ -336,28 +339,6 @@ func testBarrier_Rotate(t *testing.T, b SecurityBarrier) {
t.Fatalf("bad: %v", out)
}
// Attempt to do AddKey
randKey, _ := b.GenerateKey()
newKey := &Key{
Term: 3,
Version: 1,
Value: randKey,
InstallTime: time.Now(),
}
err = b.AddKey(newKey)
if err != nil {
t.Fatalf("err: %v", err)
}
// Check the key info
info, err = b.ActiveKeyInfo()
if err != nil {
t.Fatalf("err: %v", err)
}
if info.Term != 3 {
t.Fatalf("Bad term: %d", info.Term)
}
// Should be fine to reload keyring
err = b.ReloadKeyring()
if err != nil {
@ -444,3 +425,74 @@ func testBarrier_Rekey(t *testing.T, b SecurityBarrier) {
t.Fatalf("err: %v", err)
}
}
func testBarrier_Upgrade(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)
}
// Rotate the encryption key
newTerm, err := b1.Rotate()
if err != nil {
t.Fatalf("err: %v", err)
}
// Create upgrade path
err = b1.CreateUpgrade(newTerm)
if err != nil {
t.Fatalf("err: %v", err)
}
// Check for an upgrade
did, updated, err := b2.CheckUpgrade()
if err != nil {
t.Fatalf("err: %v", err)
}
if !did || updated != newTerm {
t.Fatalf("failed to upgrade")
}
// Should have no upgrades pending
did, updated, err = b2.CheckUpgrade()
if err != nil {
t.Fatalf("err: %v", err)
}
if did {
t.Fatalf("should not have upgrade")
}
// Rotate the encryption key
newTerm, err = b1.Rotate()
if err != nil {
t.Fatalf("err: %v", err)
}
// Create upgrade path
err = b1.CreateUpgrade(newTerm)
if err != nil {
t.Fatalf("err: %v", err)
}
// Destroy upgrade path
err = b1.DestroyUpgrade(newTerm)
if err != nil {
t.Fatalf("err: %v", err)
}
// Should have no upgrades pending
did, updated, err = b2.CheckUpgrade()
if err != nil {
t.Fatalf("err: %v", err)
}
if did {
t.Fatalf("should not have upgrade")
}
}