vault: moving upgrade path into barrier
This commit is contained in:
parent
82ef0b1ac7
commit
67ed0a3c16
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue