From d9535101c39f61a66714a8e5ec951bf67e4ef160 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Sun, 20 May 2018 18:42:14 -0400 Subject: [PATCH] More work on recovery test --- api/sys_rekey_ext_test.go | 89 +++++++++++++++++++++++---------------- http/sys_rekey.go | 4 +- vault/seal_access.go | 24 ++++++++++- 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/api/sys_rekey_ext_test.go b/api/sys_rekey_ext_test.go index f10d4ade8b..eeaa451f20 100644 --- a/api/sys_rekey_ext_test.go +++ b/api/sys_rekey_ext_test.go @@ -1,18 +1,18 @@ package api_test import ( - "context" "encoding/base64" "strings" "testing" "github.com/hashicorp/vault/api" vaulthttp "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/shamir" "github.com/hashicorp/vault/vault" ) func TestSysRekey_Verification(t *testing.T) { - testSysRekey_Verification(t, false) + //testSysRekey_Verification(t, false) testSysRekey_Verification(t, true) } @@ -40,17 +40,19 @@ func testSysRekey_Verification(t *testing.T, recovery bool) { verificationCancelFunc = client.Sys().RekeyRecoveryKeyVerificationCancel } - seal, err := cluster.Cores[0].Core.SealAccess().BarrierConfig(context.Background()) - if err != nil { - t.Fatal(err) - } + sealAccess := cluster.Cores[0].Core.SealAccess() + sealTestingParams := &vault.SealAccessTestingParams{} // This first block verifies that if we are using recovery keys to force a // rekey of a stored-shares barrier that verification is not allowed since // the keys aren't returned if !recovery { - seal.PretendToAllowStoredShares = true - seal.PretendToAllowRecoveryKeys = true + sealTestingParams.PretendToAllowRecoveryKeys = true + sealTestingParams.PretendToAllowStoredShares = true + if err := sealAccess.SetTestingParams(sealTestingParams); err != nil { + t.Fatal(err) + } + _, err := initFunc(&api.RekeyInitRequest{ StoredShares: 1, RequireVerification: true, @@ -62,10 +64,21 @@ func testSysRekey_Verification(t *testing.T, recovery bool) { t.Fatalf("unexpected error: %v", err) } // Now we set things back and start a normal rekey with the verification process - seal.PretendToAllowStoredShares = false - seal.PretendToAllowRecoveryKeys = false + sealTestingParams.PretendToAllowRecoveryKeys = false + sealTestingParams.PretendToAllowStoredShares = false + if err := sealAccess.SetTestingParams(sealTestingParams); err != nil { + t.Fatal(err) + } } else { - seal.PretendToAllowRecoveryKeys = true + sealTestingParams.PretendToAllowRecoveryKeys = true + recoveryKey, err := shamir.Combine(cluster.BarrierKeys) + if err != nil { + t.Fatal(err) + } + sealTestingParams.PretendRecoveryKey = recoveryKey + if err := sealAccess.SetTestingParams(sealTestingParams); err != nil { + t.Fatal(err) + } } var verificationNonce string @@ -191,14 +204,16 @@ func testSysRekey_Verification(t *testing.T, recovery bool) { verificationNonce = vStatus.Nonce doStartVerify() - // Sealing should clear state, but we never actually finished, so it should - // still be the old keys (which are still currently set) - cluster.EnsureCoresSealed(t) - cluster.UnsealCores(t) + if !recovery { + // Sealing should clear state, but we never actually finished, so it should + // still be the old keys (which are still currently set) + cluster.EnsureCoresSealed(t) + cluster.UnsealCores(t) - // Should be able to init again and get back to where we were - doRekeyInitialSteps() - doStartVerify() + // Should be able to init again and get back to where we were + doRekeyInitialSteps() + doStartVerify() + } // Provide the final new key vuStatus, err := verificationUpdateFunc(newKeys[2], verificationNonce) @@ -212,24 +227,26 @@ func testSysRekey_Verification(t *testing.T, recovery bool) { t.Fatal("expected completion") } - // Seal and unseal -- it should fail to unseal because the key has now been - // rotated - cluster.EnsureCoresSealed(t) - if err := cluster.UnsealCoresWithError(); err == nil { - t.Fatal("expected error") - } - - // Swap out the keys with our new ones and try again - var newKeyBytes [][]byte - for _, key := range newKeys { - val, err := base64.StdEncoding.DecodeString(key) - if err != nil { - t.Fatal(err) + if !recovery { + // Seal and unseal -- it should fail to unseal because the key has now been + // rotated + cluster.EnsureCoresSealed(t) + if err := cluster.UnsealCoresWithError(); err == nil { + t.Fatal("expected error") + } + + // Swap out the keys with our new ones and try again + var newKeyBytes [][]byte + for _, key := range newKeys { + val, err := base64.StdEncoding.DecodeString(key) + if err != nil { + t.Fatal(err) + } + newKeyBytes = append(newKeyBytes, val) + } + cluster.BarrierKeys = newKeyBytes + if err := cluster.UnsealCoresWithError(); err != nil { + t.Fatal("expected error") } - newKeyBytes = append(newKeyBytes, val) - } - cluster.BarrierKeys = newKeyBytes - if err := cluster.UnsealCoresWithError(); err != nil { - t.Fatal("expected error") } } diff --git a/http/sys_rekey.go b/http/sys_rekey.go index eb0300a114..e145d9915a 100644 --- a/http/sys_rekey.go +++ b/http/sys_rekey.go @@ -205,7 +205,7 @@ func handleSysRekeyUpdate(core *vault.Core, recovery bool) http.Handler { // Use the key to make progress on rekey result, rekeyErr := core.RekeyUpdate(ctx, key, req.Nonce, recovery) if rekeyErr != nil { - respondError(w, rekeyErr.Code(), err) + respondError(w, rekeyErr.Code(), rekeyErr) return } @@ -356,7 +356,7 @@ func handleSysRekeyVerifyPut(ctx context.Context, core *vault.Core, recovery boo // Use the key to make progress on rekey result, rekeyErr := core.RekeyVerify(ctx, key, req.Nonce, recovery) if rekeyErr != nil { - respondError(w, rekeyErr.Code(), err) + respondError(w, rekeyErr.Code(), rekeyErr) return } diff --git a/vault/seal_access.go b/vault/seal_access.go index 92a016faae..5c44bd184f 100644 --- a/vault/seal_access.go +++ b/vault/seal_access.go @@ -1,6 +1,9 @@ package vault -import "context" +import ( + "context" + "fmt" +) // SealAccess is a wrapper around Seal that exposes accessor methods // through Core.SealAccess() while restricting the ability to modify @@ -39,3 +42,22 @@ func (s *SealAccess) ClearCaches(ctx context.Context) { s.seal.SetRecoveryConfig(ctx, nil) } } + +type SealAccessTestingParams struct { + PretendToAllowStoredShares bool + PretendToAllowRecoveryKeys bool + PretendRecoveryKey []byte +} + +func (s *SealAccess) SetTestingParams(params *SealAccessTestingParams) error { + d, ok := s.seal.(*defaultSeal) + if !ok { + return fmt.Errorf("not a defaultseal") + } + d.PretendToAllowRecoveryKeys = params.PretendToAllowRecoveryKeys + d.PretendToAllowStoredShares = params.PretendToAllowStoredShares + if params.PretendRecoveryKey != nil { + d.PretendRecoveryKey = params.PretendRecoveryKey + } + return nil +}