1package misc 2 3import ( 4 "path" 5 "testing" 6 7 "github.com/go-test/deep" 8 "github.com/hashicorp/go-hclog" 9 "github.com/hashicorp/vault/helper/testhelpers" 10 "github.com/hashicorp/vault/http" 11 "github.com/hashicorp/vault/sdk/helper/logging" 12 "github.com/hashicorp/vault/sdk/physical/inmem" 13 "github.com/hashicorp/vault/vault" 14 "go.uber.org/atomic" 15) 16 17func TestRecovery(t *testing.T) { 18 logger := logging.NewVaultLogger(hclog.Debug).Named(t.Name()) 19 inm, err := inmem.NewInmemHA(nil, logger) 20 if err != nil { 21 t.Fatal(err) 22 } 23 24 var keys [][]byte 25 var secretUUID string 26 var rootToken string 27 { 28 conf := vault.CoreConfig{ 29 Physical: inm, 30 Logger: logger, 31 } 32 opts := vault.TestClusterOptions{ 33 HandlerFunc: http.Handler, 34 NumCores: 1, 35 } 36 37 cluster := vault.NewTestCluster(t, &conf, &opts) 38 cluster.Start() 39 defer cluster.Cleanup() 40 41 client := cluster.Cores[0].Client 42 rootToken = client.Token() 43 var fooVal = map[string]interface{}{"bar": 1.0} 44 _, err = client.Logical().Write("secret/foo", fooVal) 45 if err != nil { 46 t.Fatal(err) 47 } 48 secret, err := client.Logical().List("secret/") 49 if err != nil { 50 t.Fatal(err) 51 } 52 if diff := deep.Equal(secret.Data["keys"], []interface{}{"foo"}); len(diff) > 0 { 53 t.Fatalf("got=%v, want=%v, diff: %v", secret.Data["keys"], []string{"foo"}, diff) 54 } 55 mounts, err := cluster.Cores[0].Client.Sys().ListMounts() 56 if err != nil { 57 t.Fatal(err) 58 } 59 secretMount := mounts["secret/"] 60 if secretMount == nil { 61 t.Fatalf("secret mount not found, mounts: %v", mounts) 62 } 63 secretUUID = secretMount.UUID 64 cluster.EnsureCoresSealed(t) 65 keys = cluster.BarrierKeys 66 } 67 68 { 69 // Now bring it up in recovery mode. 70 var tokenRef atomic.String 71 conf := vault.CoreConfig{ 72 Physical: inm, 73 Logger: logger, 74 RecoveryMode: true, 75 } 76 opts := vault.TestClusterOptions{ 77 HandlerFunc: http.Handler, 78 NumCores: 1, 79 SkipInit: true, 80 DefaultHandlerProperties: vault.HandlerProperties{ 81 RecoveryMode: true, 82 RecoveryToken: &tokenRef, 83 }, 84 } 85 cluster := vault.NewTestCluster(t, &conf, &opts) 86 cluster.BarrierKeys = keys 87 cluster.Start() 88 defer cluster.Cleanup() 89 90 client := cluster.Cores[0].Client 91 recoveryToken := testhelpers.GenerateRoot(t, cluster, testhelpers.GenerateRecovery) 92 _, err = testhelpers.GenerateRootWithError(t, cluster, testhelpers.GenerateRecovery) 93 if err == nil { 94 t.Fatal("expected second generate-root to fail") 95 } 96 client.SetToken(recoveryToken) 97 98 secret, err := client.Logical().List(path.Join("sys/raw/logical", secretUUID)) 99 if err != nil { 100 t.Fatal(err) 101 } 102 if diff := deep.Equal(secret.Data["keys"], []interface{}{"foo"}); len(diff) > 0 { 103 t.Fatalf("got=%v, want=%v, diff: %v", secret.Data, []string{"foo"}, diff) 104 } 105 106 _, err = client.Logical().Delete(path.Join("sys/raw/logical", secretUUID, "foo")) 107 if err != nil { 108 t.Fatal(err) 109 } 110 cluster.EnsureCoresSealed(t) 111 } 112 113 { 114 // Now go back to regular mode and verify that our changes are present 115 conf := vault.CoreConfig{ 116 Physical: inm, 117 Logger: logger, 118 } 119 opts := vault.TestClusterOptions{ 120 HandlerFunc: http.Handler, 121 NumCores: 1, 122 SkipInit: true, 123 } 124 cluster := vault.NewTestCluster(t, &conf, &opts) 125 cluster.BarrierKeys = keys 126 cluster.Start() 127 testhelpers.EnsureCoresUnsealed(t, cluster) 128 defer cluster.Cleanup() 129 130 client := cluster.Cores[0].Client 131 client.SetToken(rootToken) 132 secret, err := client.Logical().List("secret/") 133 if err != nil { 134 t.Fatal(err) 135 } 136 if secret != nil { 137 t.Fatal("expected no data in secret mount") 138 } 139 } 140} 141