diff --git a/command/seal_migration_oss_test.go b/command/seal_migration_oss_test.go index 465dbafa1d..b2a700c339 100644 --- a/command/seal_migration_oss_test.go +++ b/command/seal_migration_oss_test.go @@ -18,35 +18,38 @@ import ( "github.com/hashicorp/vault/vault/seal" ) -func TestSealMigration_AutoToShamir(t *testing.T) { +func TestSealMigration_TransitToShamir(t *testing.T) { t.Parallel() t.Run("inmem", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToShamir(t, teststorage.InmemBackendSetup) + testSealMigrationTransitToShamir(t, teststorage.InmemBackendSetup) }) t.Run("file", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToShamir(t, teststorage.FileBackendSetup) + testSealMigrationTransitToShamir(t, teststorage.FileBackendSetup) }) t.Run("consul", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToShamir(t, teststorage.ConsulBackendSetup) + testSealMigrationTransitToShamir(t, teststorage.ConsulBackendSetup) }) t.Run("raft", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToShamir(t, teststorage.RaftBackendSetup) + testSealMigrationTransitToShamir(t, teststorage.RaftBackendSetup) }) } -func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupMutator) { +func testSealMigrationTransitToShamir(t *testing.T, setup teststorage.ClusterSetupMutator) { + + // Create the transit server. tcluster := sealhelper.NewTransitSealServer(t) defer tcluster.Cleanup() - tcluster.MakeKey(t, "key1") - var seals []vault.Seal + var transitSeal vault.Seal + + // Create a cluster that uses transit. conf, opts := teststorage.ClusterSetup(&vault.CoreConfig{ DisableSealWrap: true, }, &vault.TestClusterOptions{ @@ -54,9 +57,8 @@ func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupM SkipInit: true, NumCores: 3, SealFunc: func() vault.Seal { - tseal := tcluster.MakeSeal(t, "key1") - seals = append(seals, tseal) - return tseal + transitSeal = tcluster.MakeSeal(t, "key1") + return transitSeal }, }, setup, @@ -66,6 +68,7 @@ func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupM cluster.Start() defer cluster.Cleanup() + // Initialize the cluster, and fetch the recovery keys. client := cluster.Cores[0].Client initResp, err := client.Sys().Init(&api.InitRequest{ RecoveryShares: 5, @@ -78,7 +81,6 @@ func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupM b, _ := base64.RawStdEncoding.DecodeString(k) cluster.RecoveryKeys = append(cluster.RecoveryKeys, b) } - testhelpers.WaitForActiveNode(t, cluster) rootToken := initResp.RootToken @@ -87,6 +89,7 @@ func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupM t.Fatal(err) } + // Create a Shamir seal. logger := cluster.Logger.Named("shamir") shamirSeal := vault.NewDefaultSeal(&seal.Access{ Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ @@ -94,10 +97,12 @@ func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupM }), }) - if err := adjustCoreForSealMigration(logger, cluster.Cores[0].Core, shamirSeal, seals[0]); err != nil { + // Transition to Shamir seal. + if err := adjustCoreForSealMigration(logger, cluster.Cores[0].Core, shamirSeal, transitSeal); err != nil { t.Fatal(err) } + // Unseal and migrate to Shamir. // Although we're unsealing using the recovery keys, this is still an // autounseal; if we stopped the transit cluster this would fail. var resp *api.SealStatusResponse @@ -119,16 +124,18 @@ func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupM } testhelpers.WaitForActiveNode(t, cluster) - // Seal and unseal again to verify that things are working fine + // Seal the cluster. if err := client.Sys().Seal(); err != nil { t.Fatal(err) } + // Nuke the transit server; assign nil to Cores so the deferred Cleanup + // doesn't break. tcluster.Cleanup() - // Assign nil to Cores so the deferred Cleanup doesn't break. tcluster.Cores = nil - // Now the recovery keys are actually the barrier unseal keys. + // Unseal the cluster. Now the recovery keys are actually the barrier + // unseal keys. for _, key := range initResp.RecoveryKeysB64 { resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) if err != nil { @@ -142,6 +149,7 @@ func testSealMigrationAutoToShamir(t *testing.T, setup teststorage.ClusterSetupM t.Fatalf("expected unsealed state; got %#v", resp) } + // Make sure the seal configs were updated correctly. b, r, err := cluster.Cores[0].Core.PhysicalSealConfigs(context.Background()) if err != nil { t.Fatal(err) diff --git a/command/seal_migration_test.go b/command/seal_migration_test.go index 3bb40ea0ad..b5558568e7 100644 --- a/command/seal_migration_test.go +++ b/command/seal_migration_test.go @@ -3,16 +3,16 @@ package command import ( "context" "encoding/base64" - "path" "testing" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/helper/testhelpers" - "github.com/hashicorp/vault/helper/testhelpers/seal" + sealhelper "github.com/hashicorp/vault/helper/testhelpers/seal" "github.com/hashicorp/vault/helper/testhelpers/teststorage" vaulthttp "github.com/hashicorp/vault/http" "github.com/hashicorp/vault/vault" + vaultseal "github.com/hashicorp/vault/vault/seal" ) func verifyBarrierConfig(t *testing.T, cfg *vault.SealConfig, sealType string, shares, threshold, stored int) { @@ -31,33 +31,32 @@ func verifyBarrierConfig(t *testing.T, cfg *vault.SealConfig, sealType string, s } } -func TestSealMigration_ShamirToAuto(t *testing.T) { +func TestSealMigration_ShamirToTransit(t *testing.T) { t.Parallel() t.Run("inmem", func(t *testing.T) { t.Parallel() - testSealMigrationShamirToAuto(t, teststorage.InmemBackendSetup) + testSealMigrationShamirToTransit(t, teststorage.InmemBackendSetup) }) t.Run("file", func(t *testing.T) { t.Parallel() - testSealMigrationShamirToAuto(t, teststorage.FileBackendSetup) + testSealMigrationShamirToTransit(t, teststorage.FileBackendSetup) }) t.Run("consul", func(t *testing.T) { t.Parallel() - testSealMigrationShamirToAuto(t, teststorage.ConsulBackendSetup) + testSealMigrationShamirToTransit(t, teststorage.ConsulBackendSetup) }) t.Run("raft", func(t *testing.T) { t.Parallel() - testSealMigrationShamirToAuto(t, teststorage.RaftBackendSetup) + testSealMigrationShamirToTransit(t, teststorage.RaftBackendSetup) }) } -func testSealMigrationShamirToAuto(t *testing.T, setup teststorage.ClusterSetupMutator) { - tcluster := seal.NewTransitSealServer(t) - defer tcluster.Cleanup() +func testSealMigrationShamirToTransit(t *testing.T, setup teststorage.ClusterSetupMutator) { + // Create a cluster that uses shamir. conf, opts := teststorage.ClusterSetup(&vault.CoreConfig{ DisableSealWrap: true, }, &vault.TestClusterOptions{ @@ -69,11 +68,10 @@ func testSealMigrationShamirToAuto(t *testing.T, setup teststorage.ClusterSetupM ) opts.SetupFunc = nil cluster := vault.NewTestCluster(t, conf, opts) - tcluster.MakeKey(t, "key1") - autoSeal := tcluster.MakeSeal(t, "key1") cluster.Start() defer cluster.Cleanup() + // Initialize the cluster, and unseal it using the shamir keys. client := cluster.Cores[0].Client initResp, err := client.Sys().Init(&api.InitRequest{ SecretShares: 5, @@ -98,16 +96,25 @@ func testSealMigrationShamirToAuto(t *testing.T, setup teststorage.ClusterSetupM } testhelpers.WaitForActiveNode(t, cluster) + rootToken := initResp.RootToken client.SetToken(rootToken) if err := client.Sys().Seal(); err != nil { t.Fatal(err) } - if err := adjustCoreForSealMigration(cluster.Logger, cluster.Cores[0].Core, autoSeal, nil); err != nil { + // Create the transit server. + tcluster := sealhelper.NewTransitSealServer(t) + defer tcluster.Cleanup() + tcluster.MakeKey(t, "key1") + transitSeal := tcluster.MakeSeal(t, "key1") + + // Transition to transit seal. + if err := adjustCoreForSealMigration(cluster.Logger, cluster.Cores[0].Core, transitSeal, nil); err != nil { t.Fatal(err) } + // Unseal and migrate to transit. for _, key := range initResp.KeysB64 { resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) if err == nil { @@ -126,15 +133,18 @@ func testSealMigrationShamirToAuto(t *testing.T, setup teststorage.ClusterSetupM } testhelpers.WaitForActiveNode(t, cluster) - // Seal and unseal again to verify that things are working fine + + // Seal the cluster. if err := client.Sys().Seal(); err != nil { t.Fatal(err) } - // Now the barrier unseal keys are actually the recovery keys. - // Seal the transit cluster; we expect the unseal of our other cluster + // Seal the transit cluster; we expect the unseal of our main cluster // to fail as a result. tcluster.EnsureCoresSealed(t) + + // Verify that we cannot unseal. Now the barrier unseal keys are actually + // the recovery keys. for _, key := range initResp.KeysB64 { resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) if err != nil { @@ -148,7 +158,11 @@ func testSealMigrationShamirToAuto(t *testing.T, setup teststorage.ClusterSetupM t.Fatalf("expected sealed state; got %#v", resp) } + // Unseal the transit server; we expect the unseal to work now on our main + // cluster. tcluster.UnsealCores(t) + + // Verify that we can unseal. for _, key := range initResp.KeysB64 { resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) if err != nil { @@ -162,7 +176,7 @@ func testSealMigrationShamirToAuto(t *testing.T, setup teststorage.ClusterSetupM t.Fatalf("expected unsealed state; got %#v", resp) } - // Make sure the seal configs were updated correctly + // Make sure the seal configs were updated correctly. b, r, err := cluster.Cores[0].Core.PhysicalSealConfigs(context.Background()) if err != nil { t.Fatal(err) @@ -171,33 +185,317 @@ func testSealMigrationShamirToAuto(t *testing.T, setup teststorage.ClusterSetupM verifyBarrierConfig(t, r, wrapping.Shamir, 5, 3, 0) } -/* -func TestSealMigration_AutoToAuto(t *testing.T) { +func TestSealMigration_ShamirToTestSeal(t *testing.T) { t.Parallel() t.Run("inmem", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToAuto(t, teststorage.InmemBackendSetup) + testSealMigrationShamirToTestSeal(t, teststorage.InmemBackendSetup) }) t.Run("file", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToAuto(t, teststorage.FileBackendSetup) + testSealMigrationShamirToTestSeal(t, teststorage.FileBackendSetup) }) t.Run("consul", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToAuto(t, teststorage.ConsulBackendSetup) + testSealMigrationShamirToTestSeal(t, teststorage.ConsulBackendSetup) }) t.Run("raft", func(t *testing.T) { t.Parallel() - testSealMigrationAutoToAuto(t, teststorage.RaftBackendSetup) + testSealMigrationShamirToTestSeal(t, teststorage.RaftBackendSetup) }) } -*/ -func testSealMigrationAutoToAuto(t *testing.T, setup teststorage.ClusterSetupMutator) { - tcluster := seal.NewTransitSealServer(t) +func testSealMigrationShamirToTestSeal(t *testing.T, setup teststorage.ClusterSetupMutator) { + + // Create a cluster that uses shamir. + conf, opts := teststorage.ClusterSetup(&vault.CoreConfig{ + DisableSealWrap: true, + }, &vault.TestClusterOptions{ + HandlerFunc: vaulthttp.Handler, + SkipInit: true, + NumCores: 3, + }, + setup, + ) + opts.SetupFunc = nil + cluster := vault.NewTestCluster(t, conf, opts) + cluster.Start() + defer cluster.Cleanup() + + // Initialize the cluster, and unseal it using the shamir keys. + client := cluster.Cores[0].Client + initResp, err := client.Sys().Init(&api.InitRequest{ + SecretShares: 5, + SecretThreshold: 3, + }) + if err != nil { + t.Fatal(err) + } + + var resp *api.SealStatusResponse + for _, key := range initResp.KeysB64 { + resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) + if err != nil { + t.Fatal(err) + } + if resp == nil || !resp.Sealed { + break + } + } + if resp == nil || resp.Sealed { + t.Fatalf("expected unsealed state; got %#v", resp) + } + + testhelpers.WaitForActiveNode(t, cluster) + + rootToken := initResp.RootToken + client.SetToken(rootToken) + if err := client.Sys().Seal(); err != nil { + t.Fatal(err) + } + + // Create a test seal + testSeal := vault.NewAutoSeal(vaultseal.NewTestSeal(&vaultseal.TestSealOpts{})) + + // Transition to test seal. + if err := adjustCoreForSealMigration(cluster.Logger, cluster.Cores[0].Core, testSeal, nil); err != nil { + t.Fatal(err) + } + + // Unseal and migrate to test seal. + for _, key := range initResp.KeysB64 { + resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) + if err == nil { + t.Fatal("expected error due to lack of migrate parameter") + } + resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key, Migrate: true}) + if err != nil { + t.Fatal(err) + } + if resp == nil || !resp.Sealed { + break + } + } + if resp == nil || resp.Sealed { + t.Fatalf("expected unsealed state; got %#v", resp) + } + testhelpers.WaitForActiveNode(t, cluster) + + // Seal the cluster. + if err := client.Sys().Seal(); err != nil { + t.Fatal(err) + } + + ////// Seal the transit cluster; we expect the unseal of our main cluster + ////// to fail as a result. + ////tcluster.EnsureCoresSealed(t) + + ////// Verify that we cannot unseal. Now the barrier unseal keys are actually + ////// the recovery keys. + ////for _, key := range initResp.KeysB64 { + //// resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) + //// if err != nil { + //// break + //// } + //// if resp == nil || !resp.Sealed { + //// break + //// } + ////} + ////if err == nil || resp != nil { + //// t.Fatalf("expected sealed state; got %#v", resp) + ////} + + ////// Unseal the transit server; we expect the unseal to work now on our main + ////// cluster. + ////tcluster.UnsealCores(t) + + // Verify that we can unseal. + for _, key := range initResp.KeysB64 { + resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) + if err != nil { + t.Fatal(err) + } + if resp == nil || !resp.Sealed { + break + } + } + if resp == nil || resp.Sealed { + t.Fatalf("expected unsealed state; got %#v", resp) + } + + // Make sure the seal configs were updated correctly. + b, r, err := cluster.Cores[0].Core.PhysicalSealConfigs(context.Background()) + if err != nil { + t.Fatal(err) + } + verifyBarrierConfig(t, b, wrapping.Test, 1, 1, 1) + verifyBarrierConfig(t, r, wrapping.Shamir, 5, 3, 0) +} + +func TestSealMigration_TransitToTestSeal(t *testing.T) { + t.Parallel() + t.Run("inmem", func(t *testing.T) { + t.Parallel() + testSealMigrationTransitToTestSeal(t, teststorage.InmemBackendSetup) + }) + + //t.Run("file", func(t *testing.T) { + // t.Parallel() + // testSealMigrationTransitToTestSeal(t, teststorage.FileBackendSetup) + //}) + + //t.Run("consul", func(t *testing.T) { + // t.Parallel() + // testSealMigrationTransitToTestSeal(t, teststorage.ConsulBackendSetup) + //}) + + //t.Run("raft", func(t *testing.T) { + // t.Parallel() + // testSealMigrationTransitToTestSeal(t, teststorage.RaftBackendSetup) + //}) +} + +func testSealMigrationTransitToTestSeal(t *testing.T, setup teststorage.ClusterSetupMutator) { + + // Create the transit server. + tcluster := sealhelper.NewTransitSealServer(t) + defer tcluster.Cleanup() + tcluster.MakeKey(t, "key1") + var transitSeal vault.Seal + + // Create a cluster that uses transit. + conf, opts := teststorage.ClusterSetup(&vault.CoreConfig{ + DisableSealWrap: true, + }, &vault.TestClusterOptions{ + HandlerFunc: vaulthttp.Handler, + SkipInit: true, + NumCores: 3, + SealFunc: func() vault.Seal { + transitSeal = tcluster.MakeSeal(t, "key1") + return transitSeal + }, + }, + setup, + ) + opts.SetupFunc = nil + cluster := vault.NewTestCluster(t, conf, opts) + cluster.Start() + defer cluster.Cleanup() + + // Initialize the cluster, and fetch the recovery keys. + client := cluster.Cores[0].Client + initResp, err := client.Sys().Init(&api.InitRequest{ + RecoveryShares: 5, + RecoveryThreshold: 3, + }) + if err != nil { + t.Fatal(err) + } + for _, k := range initResp.RecoveryKeysB64 { + b, _ := base64.RawStdEncoding.DecodeString(k) + cluster.RecoveryKeys = append(cluster.RecoveryKeys, b) + } + testhelpers.WaitForActiveNode(t, cluster) + + rootToken := initResp.RootToken + client.SetToken(rootToken) + if err := client.Sys().Seal(); err != nil { + t.Fatal(err) + } + + // Create a test seal + testSeal := vault.NewAutoSeal(vaultseal.NewTestSeal(&vaultseal.TestSealOpts{})) + + // Transition to test seal. + if err := adjustCoreForSealMigration(cluster.Logger, cluster.Cores[0].Core, testSeal, transitSeal); err != nil { + t.Fatal(err) + } + + // Unseal and migrate to Test Seal. + // Although we're unsealing using the recovery keys, this is still an + // autounseal; if we stopped the transit cluster this would fail. + var resp *api.SealStatusResponse + for _, key := range initResp.RecoveryKeysB64 { + resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) + if err == nil { + t.Fatal("expected error due to lack of migrate parameter") + } + resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key, Migrate: true}) + if err != nil { + t.Fatal(err) + } + if resp == nil || !resp.Sealed { + break + } + } + if resp == nil || resp.Sealed { + t.Fatalf("expected unsealed state; got %#v", resp) + } + testhelpers.WaitForActiveNode(t, cluster) + + // Seal the cluster. + if err := client.Sys().Seal(); err != nil { + t.Fatal(err) + } + + // Nuke the transit server; assign nil to Cores so the deferred Cleanup + // doesn't break. + tcluster.Cleanup() + tcluster.Cores = nil + + // Unseal the cluster. Now the recovery keys are actually the barrier + // unseal keys. + for _, key := range initResp.RecoveryKeysB64 { + resp, err = client.Sys().UnsealWithOptions(&api.UnsealOpts{Key: key}) + if err != nil { + t.Fatal(err) + } + if resp == nil || !resp.Sealed { + break + } + } + if resp == nil || resp.Sealed { + t.Fatalf("expected unsealed state; got %#v", resp) + } + + // Make sure the seal configs were updated correctly. + b, r, err := cluster.Cores[0].Core.PhysicalSealConfigs(context.Background()) + if err != nil { + t.Fatal(err) + } + verifyBarrierConfig(t, b, wrapping.Test, 1, 1, 1) + verifyBarrierConfig(t, r, wrapping.Shamir, 5, 3, 0) +} + +/* +func TestSealMigration_TransitToTransit(t *testing.T) { + t.Parallel() + t.Run("inmem", func(t *testing.T) { + t.Parallel() + testSealMigrationTransitToTransit(t, teststorage.InmemBackendSetup) + }) + + t.Run("file", func(t *testing.T) { + t.Parallel() + testSealMigrationTransitToTransit(t, teststorage.FileBackendSetup) + }) + + t.Run("consul", func(t *testing.T) { + t.Parallel() + testSealMigrationTransitToTransit(t, teststorage.ConsulBackendSetup) + }) + + t.Run("raft", func(t *testing.T) { + t.Parallel() + testSealMigrationTransitToTransit(t, teststorage.RaftBackendSetup) + }) +} + +func testSealMigrationTransitToTransit(t *testing.T, setup teststorage.ClusterSetupMutator) { + tcluster := sealhelper.NewTransitSealServer(t) defer tcluster.Cleanup() tcluster.MakeKey(t, "key1") tcluster.MakeKey(t, "key2") @@ -287,3 +585,4 @@ func testSealMigrationAutoToAuto(t *testing.T, setup teststorage.ClusterSetupMut t.Fatal(err) } } +*/ diff --git a/helper/testhelpers/seal/seal.go b/helper/testhelpers/seal/sealhelper.go similarity index 94% rename from helper/testhelpers/seal/seal.go rename to helper/testhelpers/seal/sealhelper.go index 585f8e627c..73425f9f23 100644 --- a/helper/testhelpers/seal/seal.go +++ b/helper/testhelpers/seal/sealhelper.go @@ -1,6 +1,8 @@ -package seal +package sealhelper import ( + "path" + "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/builtin/logical/transit" @@ -10,9 +12,8 @@ import ( "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/vault" - seal2 "github.com/hashicorp/vault/vault/seal" + vaultseal "github.com/hashicorp/vault/vault/seal" "github.com/mitchellh/go-testing-interface" - "path" ) type TransitSealServer struct { @@ -69,7 +70,7 @@ func (tss *TransitSealServer) MakeSeal(t testing.T, key string) vault.Seal { t.Fatalf("error setting wrapper config: %v", err) } - return vault.NewAutoSeal(&seal2.Access{ + return vault.NewAutoSeal(&vaultseal.Access{ Wrapper: transitSeal, }) }