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.
331 lines
7.8 KiB
Go
331 lines
7.8 KiB
Go
// +build !enterprise
|
|
|
|
package command
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"testing"
|
|
|
|
hclog "github.com/hashicorp/go-hclog"
|
|
"github.com/hashicorp/vault/api"
|
|
vaulthttp "github.com/hashicorp/vault/http"
|
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
|
"github.com/hashicorp/vault/sdk/physical"
|
|
physInmem "github.com/hashicorp/vault/sdk/physical/inmem"
|
|
"github.com/hashicorp/vault/shamir"
|
|
"github.com/hashicorp/vault/vault"
|
|
"github.com/hashicorp/vault/vault/seal"
|
|
shamirseal "github.com/hashicorp/vault/vault/seal/shamir"
|
|
)
|
|
|
|
func TestSealMigration(t *testing.T) {
|
|
logger := logging.NewVaultLogger(hclog.Trace).Named(t.Name())
|
|
phys, err := physInmem.NewInmem(nil, logger)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
haPhys, err := physInmem.NewInmemHA(nil, logger)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
shamirSeal := vault.NewDefaultSeal(shamirseal.NewSeal(logger.Named("shamir")))
|
|
coreConfig := &vault.CoreConfig{
|
|
Seal: shamirSeal,
|
|
Physical: phys,
|
|
HAPhysical: haPhys.(physical.HABackend),
|
|
DisableSealWrap: true,
|
|
}
|
|
clusterConfig := &vault.TestClusterOptions{
|
|
Logger: logger,
|
|
HandlerFunc: vaulthttp.Handler,
|
|
SkipInit: true,
|
|
NumCores: 1,
|
|
}
|
|
|
|
ctx := context.Background()
|
|
var keys []string
|
|
var rootToken string
|
|
|
|
{
|
|
logger.Info("integ: start up as normal with shamir seal, init it")
|
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
client := cluster.Cores[0].Client
|
|
coreConfig = cluster.Cores[0].CoreConfig
|
|
|
|
// Init
|
|
resp, err := client.Sys().Init(&api.InitRequest{
|
|
SecretShares: 2,
|
|
SecretThreshold: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
keys = resp.KeysB64
|
|
rootToken = resp.RootToken
|
|
|
|
// Now seal
|
|
cluster.Cleanup()
|
|
// This will prevent cleanup from running again on the defer
|
|
cluster.Cores = nil
|
|
}
|
|
|
|
{
|
|
logger.SetLevel(hclog.Trace)
|
|
logger.Info("integ: start up as normal with shamir seal and unseal, make sure everything is normal")
|
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
client := cluster.Cores[0].Client
|
|
client.SetToken(rootToken)
|
|
|
|
var resp *api.SealStatusResponse
|
|
for _, key := range keys {
|
|
resp, err = client.Sys().Unseal(key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected response")
|
|
}
|
|
}
|
|
if resp.Sealed {
|
|
t.Fatal("expected unsealed state")
|
|
}
|
|
|
|
cluster.Cleanup()
|
|
cluster.Cores = nil
|
|
}
|
|
|
|
var autoSeal vault.Seal
|
|
|
|
{
|
|
logger.SetLevel(hclog.Trace)
|
|
logger.Info("integ: creating an autoseal and activating migration")
|
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
core := cluster.Cores[0].Core
|
|
|
|
newSeal := vault.NewAutoSeal(seal.NewTestSeal(nil))
|
|
newSeal.SetCore(core)
|
|
autoSeal = newSeal
|
|
if err := adjustCoreForSealMigration(logger, core, newSeal, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
client := cluster.Cores[0].Client
|
|
client.SetToken(rootToken)
|
|
|
|
var resp *api.SealStatusResponse
|
|
unsealOpts := &api.UnsealOpts{}
|
|
for _, key := range keys {
|
|
unsealOpts.Key = key
|
|
unsealOpts.Migrate = false
|
|
resp, err = client.Sys().UnsealWithOptions(unsealOpts)
|
|
if err == nil {
|
|
t.Fatal("expected error due to lack of migrate parameter")
|
|
}
|
|
unsealOpts.Migrate = true
|
|
resp, err = client.Sys().UnsealWithOptions(unsealOpts)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected response")
|
|
}
|
|
}
|
|
if resp.Sealed {
|
|
t.Fatalf("expected unsealed state; got %#v", *resp)
|
|
}
|
|
|
|
cluster.Cleanup()
|
|
cluster.Cores = nil
|
|
}
|
|
|
|
{
|
|
logger.SetLevel(hclog.Trace)
|
|
logger.Info("integ: verify autoseal and recovery key usage")
|
|
coreConfig.Seal = autoSeal
|
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
core := cluster.Cores[0].Core
|
|
client := cluster.Cores[0].Client
|
|
client.SetToken(rootToken)
|
|
|
|
if err := core.UnsealWithStoredKeys(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resp, err := client.Sys().SealStatus()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected response")
|
|
}
|
|
if resp.Sealed {
|
|
t.Fatalf("expected unsealed state; got %#v", *resp)
|
|
}
|
|
|
|
keyParts := [][]byte{}
|
|
for _, key := range keys {
|
|
raw, err := base64.StdEncoding.DecodeString(key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
keyParts = append(keyParts, raw)
|
|
}
|
|
recoveredKey, err := shamir.Combine(keyParts)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sealAccess := core.SealAccess()
|
|
if err := sealAccess.VerifyRecoveryKey(ctx, recoveredKey); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
cluster.Cleanup()
|
|
cluster.Cores = nil
|
|
}
|
|
|
|
// We should see stored barrier keys; after the sixth test, we shouldn't
|
|
if entry, err := phys.Get(ctx, vault.StoredBarrierKeysPath); err != nil || entry == nil {
|
|
t.Fatalf("expected nil error and non-nil entry, got error %#v and entry %#v", err, entry)
|
|
}
|
|
|
|
altTestSeal := seal.NewTestSeal(nil)
|
|
altTestSeal.Type = "test-alternate"
|
|
altSeal := vault.NewAutoSeal(altTestSeal)
|
|
|
|
{
|
|
logger.SetLevel(hclog.Trace)
|
|
logger.Info("integ: migrate from auto-seal to auto-seal")
|
|
coreConfig.Seal = autoSeal
|
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
core := cluster.Cores[0].Core
|
|
|
|
if err := adjustCoreForSealMigration(logger, core, altSeal, autoSeal); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
client := cluster.Cores[0].Client
|
|
client.SetToken(rootToken)
|
|
|
|
var resp *api.SealStatusResponse
|
|
unsealOpts := &api.UnsealOpts{}
|
|
for _, key := range keys {
|
|
unsealOpts.Key = key
|
|
unsealOpts.Migrate = true
|
|
resp, err = client.Sys().UnsealWithOptions(unsealOpts)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected response")
|
|
}
|
|
}
|
|
if resp.Sealed {
|
|
t.Fatalf("expected unsealed state; got %#v", *resp)
|
|
}
|
|
|
|
cluster.Cleanup()
|
|
cluster.Cores = nil
|
|
}
|
|
|
|
{
|
|
logger.SetLevel(hclog.Trace)
|
|
logger.Info("integ: create a Shamir seal and activate migration; verify it doesn't work if disabled isn't set.")
|
|
coreConfig.Seal = altSeal
|
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
core := cluster.Cores[0].Core
|
|
|
|
if err := adjustCoreForSealMigration(logger, core, shamirSeal, altSeal); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
client := cluster.Cores[0].Client
|
|
client.SetToken(rootToken)
|
|
|
|
var resp *api.SealStatusResponse
|
|
unsealOpts := &api.UnsealOpts{}
|
|
for _, key := range keys {
|
|
unsealOpts.Key = key
|
|
unsealOpts.Migrate = false
|
|
resp, err = client.Sys().UnsealWithOptions(unsealOpts)
|
|
if err == nil {
|
|
t.Fatal("expected error due to lack of migrate parameter")
|
|
}
|
|
unsealOpts.Migrate = true
|
|
resp, err = client.Sys().UnsealWithOptions(unsealOpts)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected response")
|
|
}
|
|
}
|
|
if resp.Sealed {
|
|
t.Fatalf("expected unsealed state; got %#v", *resp)
|
|
}
|
|
|
|
cluster.Cleanup()
|
|
cluster.Cores = nil
|
|
}
|
|
|
|
{
|
|
logger.SetLevel(hclog.Trace)
|
|
logger.Info("integ: verify autoseal is off and the expected key shares work")
|
|
coreConfig.Seal = shamirSeal
|
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
|
|
core := cluster.Cores[0].Core
|
|
client := cluster.Cores[0].Client
|
|
client.SetToken(rootToken)
|
|
|
|
if err := core.UnsealWithStoredKeys(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resp, err := client.Sys().SealStatus()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected response")
|
|
}
|
|
if !resp.Sealed {
|
|
t.Fatalf("expected sealed state; got %#v", *resp)
|
|
}
|
|
|
|
for _, key := range keys {
|
|
resp, err = client.Sys().Unseal(key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected response")
|
|
}
|
|
}
|
|
if resp.Sealed {
|
|
t.Fatal("expected unsealed state")
|
|
}
|
|
|
|
cluster.Cleanup()
|
|
cluster.Cores = nil
|
|
}
|
|
}
|