1c98152fa0
Shamir seals now come in two varieties: legacy and new-style. Legacy Shamir is automatically converted to new-style when a rekey operation is performed. All new Vault initializations using Shamir are new-style. New-style Shamir writes an encrypted master key to storage, just like AutoUnseal. The stored master key is encrypted using the shared key that is split via Shamir's algorithm. Thus when unsealing, we take the key fragments given, combine them into a Key-Encryption-Key, and use that to decrypt the master key on disk. Then the master key is used to read the keyring that decrypts the barrier.
536 lines
11 KiB
Go
536 lines
11 KiB
Go
package vault
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
)
|
|
|
|
func testBarrier(t *testing.T, b SecurityBarrier) {
|
|
// Should not be initialized
|
|
init, err := b.Initialized(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if init {
|
|
t.Fatalf("should not be initialized")
|
|
}
|
|
|
|
// Should start sealed
|
|
sealed, err := b.Sealed()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if !sealed {
|
|
t.Fatalf("should be sealed")
|
|
}
|
|
|
|
// Sealing should be a no-op
|
|
if err := b.Seal(); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// All operations should fail
|
|
e := &logical.StorageEntry{Key: "test", Value: []byte("test")}
|
|
if err := b.Put(context.Background(), e); err != ErrBarrierSealed {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if _, err := b.Get(context.Background(), "test"); err != ErrBarrierSealed {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if err := b.Delete(context.Background(), "test"); err != ErrBarrierSealed {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if _, err := b.List(context.Background(), ""); err != ErrBarrierSealed {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Get a new key
|
|
key, err := b.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Validate minimum key length
|
|
min, max := b.KeyLength()
|
|
if min < 16 {
|
|
t.Fatalf("minimum key size too small: %d", min)
|
|
}
|
|
if max < min {
|
|
t.Fatalf("maximum key size smaller than min")
|
|
}
|
|
|
|
// Unseal should not work
|
|
if err := b.Unseal(context.Background(), key); err != ErrBarrierNotInit {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Initialize the vault
|
|
if err := b.Initialize(context.Background(), key, nil, rand.Reader); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Double Initialize should fail
|
|
if err := b.Initialize(context.Background(), key, nil, rand.Reader); err != ErrBarrierAlreadyInit {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Should be initialized
|
|
init, err = b.Initialized(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if !init {
|
|
t.Fatalf("should be initialized")
|
|
}
|
|
|
|
// Should still be sealed
|
|
sealed, err = b.Sealed()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if !sealed {
|
|
t.Fatalf("should sealed")
|
|
}
|
|
|
|
// Unseal should work
|
|
if err := b.Unseal(context.Background(), key); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Unseal should no-op when done twice
|
|
if err := b.Unseal(context.Background(), key); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Should no longer be sealed
|
|
sealed, err = b.Sealed()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if sealed {
|
|
t.Fatalf("should be unsealed")
|
|
}
|
|
|
|
// Verify the master key
|
|
if err := b.VerifyMaster(key); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Operations should work
|
|
out, err := b.Get(context.Background(), "test")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out != nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
// List should have only "core/"
|
|
keys, err := b.List(context.Background(), "")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if len(keys) != 1 || keys[0] != "core/" {
|
|
t.Fatalf("bad: %v", keys)
|
|
}
|
|
|
|
// Try to write
|
|
if err := b.Put(context.Background(), e); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Should be equal
|
|
out, err = b.Get(context.Background(), "test")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(out, e) {
|
|
t.Fatalf("bad: %v exp: %v", out, e)
|
|
}
|
|
|
|
// List should show the items
|
|
keys, err = b.List(context.Background(), "")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if len(keys) != 2 {
|
|
t.Fatalf("bad: %v", keys)
|
|
}
|
|
if keys[0] != "core/" || keys[1] != "test" {
|
|
t.Fatalf("bad: %v", keys)
|
|
}
|
|
|
|
// Delete should clear
|
|
err = b.Delete(context.Background(), "test")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Double Delete is fine
|
|
err = b.Delete(context.Background(), "test")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Should be nil
|
|
out, err = b.Get(context.Background(), "test")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out != nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
// List should have nothing
|
|
keys, err = b.List(context.Background(), "")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if len(keys) != 1 || keys[0] != "core/" {
|
|
t.Fatalf("bad: %v", keys)
|
|
}
|
|
|
|
// Add the item back
|
|
if err := b.Put(context.Background(), e); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reseal should prevent any updates
|
|
if err := b.Seal(); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// No access allowed
|
|
if _, err := b.Get(context.Background(), "test"); err != ErrBarrierSealed {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Unseal should work
|
|
if err := b.Unseal(context.Background(), key); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Should be equal
|
|
out, err = b.Get(context.Background(), "test")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(out, e) {
|
|
t.Fatalf("bad: %v exp: %v", out, e)
|
|
}
|
|
|
|
// Final cleanup
|
|
err = b.Delete(context.Background(), "test")
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reseal should prevent any updates
|
|
if err := b.Seal(); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Modify the key
|
|
key[0]++
|
|
|
|
// Unseal should fail
|
|
if err := b.Unseal(context.Background(), key); err != ErrBarrierInvalidKey {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
}
|
|
|
|
func testBarrier_Rotate(t *testing.T, b SecurityBarrier) {
|
|
// Initialize the barrier
|
|
key, _ := b.GenerateKey(rand.Reader)
|
|
b.Initialize(context.Background(), key, nil, rand.Reader)
|
|
err := b.Unseal(context.Background(), key)
|
|
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 != 1 {
|
|
t.Fatalf("Bad term: %d", info.Term)
|
|
}
|
|
if time.Since(info.InstallTime) > time.Second {
|
|
t.Fatalf("Bad install: %v", info.InstallTime)
|
|
}
|
|
first := info.InstallTime
|
|
|
|
// Write a key
|
|
e1 := &logical.StorageEntry{Key: "test", Value: []byte("test")}
|
|
if err := b.Put(context.Background(), e1); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Rotate the encryption key
|
|
newTerm, err := b.Rotate(context.Background(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if newTerm != 2 {
|
|
t.Fatalf("bad: %v", newTerm)
|
|
}
|
|
|
|
// Check the key info
|
|
info, err = b.ActiveKeyInfo()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if info.Term != 2 {
|
|
t.Fatalf("Bad term: %d", info.Term)
|
|
}
|
|
if !info.InstallTime.After(first) {
|
|
t.Fatalf("Bad install: %v", info.InstallTime)
|
|
}
|
|
|
|
// Write another key
|
|
e2 := &logical.StorageEntry{Key: "foo", Value: []byte("test")}
|
|
if err := b.Put(context.Background(), e2); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reading both should work
|
|
out, err := b.Get(context.Background(), e1.Key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out == nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
out, err = b.Get(context.Background(), e2.Key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out == nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
// Seal and unseal
|
|
err = b.Seal()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
err = b.Unseal(context.Background(), key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reading both should work
|
|
out, err = b.Get(context.Background(), e1.Key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out == nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
out, err = b.Get(context.Background(), e2.Key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out == nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
// Should be fine to reload keyring
|
|
err = b.ReloadKeyring(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
}
|
|
|
|
func testBarrier_Rekey(t *testing.T, b SecurityBarrier) {
|
|
// Initialize the barrier
|
|
key, _ := b.GenerateKey(rand.Reader)
|
|
b.Initialize(context.Background(), key, nil, rand.Reader)
|
|
err := b.Unseal(context.Background(), key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Write a key
|
|
e1 := &logical.StorageEntry{Key: "test", Value: []byte("test")}
|
|
if err := b.Put(context.Background(), e1); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Verify the master key
|
|
if err := b.VerifyMaster(key); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Rekey to a new key
|
|
newKey, _ := b.GenerateKey(rand.Reader)
|
|
err = b.Rekey(context.Background(), newKey)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Verify the old master key
|
|
if err := b.VerifyMaster(key); err != ErrBarrierInvalidKey {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Verify the new master key
|
|
if err := b.VerifyMaster(newKey); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reading should work
|
|
out, err := b.Get(context.Background(), e1.Key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out == nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
// Seal
|
|
err = b.Seal()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Unseal with old key should fail
|
|
err = b.Unseal(context.Background(), key)
|
|
if err == nil {
|
|
t.Fatalf("unseal should fail")
|
|
}
|
|
|
|
// Unseal with new keys should work
|
|
err = b.Unseal(context.Background(), newKey)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reading should work
|
|
out, err = b.Get(context.Background(), e1.Key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out == nil {
|
|
t.Fatalf("bad: %v", out)
|
|
}
|
|
|
|
// Should be fine to reload keyring
|
|
err = b.ReloadKeyring(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
}
|
|
|
|
func testBarrier_Upgrade(t *testing.T, b1, b2 SecurityBarrier) {
|
|
// Initialize the barrier
|
|
key, _ := b1.GenerateKey(rand.Reader)
|
|
b1.Initialize(context.Background(), key, nil, rand.Reader)
|
|
err := b1.Unseal(context.Background(), key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
err = b2.Unseal(context.Background(), key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Rotate the encryption key
|
|
newTerm, err := b1.Rotate(context.Background(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Create upgrade path
|
|
err = b1.CreateUpgrade(context.Background(), newTerm)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Check for an upgrade
|
|
did, updated, err := b2.CheckUpgrade(context.Background())
|
|
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(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if did {
|
|
t.Fatalf("should not have upgrade")
|
|
}
|
|
|
|
// Rotate the encryption key
|
|
newTerm, err = b1.Rotate(context.Background(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Create upgrade path
|
|
err = b1.CreateUpgrade(context.Background(), newTerm)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Destroy upgrade path
|
|
err = b1.DestroyUpgrade(context.Background(), newTerm)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Should have no upgrades pending
|
|
did, updated, err = b2.CheckUpgrade(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if did {
|
|
t.Fatalf("should not have upgrade")
|
|
}
|
|
}
|
|
|
|
func testBarrier_Upgrade_Rekey(t *testing.T, b1, b2 SecurityBarrier) {
|
|
// Initialize the barrier
|
|
key, _ := b1.GenerateKey(rand.Reader)
|
|
b1.Initialize(context.Background(), key, nil, rand.Reader)
|
|
err := b1.Unseal(context.Background(), key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
err = b2.Unseal(context.Background(), key)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Rekey to a new key
|
|
newKey, _ := b1.GenerateKey(rand.Reader)
|
|
err = b1.Rekey(context.Background(), newKey)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reload the master key
|
|
err = b2.ReloadMasterKey(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Reload the keyring
|
|
err = b2.ReloadKeyring(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
}
|