diff --git a/nomad/vault_test.go b/nomad/vault_test.go index 9b7389197..b6004a483 100644 --- a/nomad/vault_test.go +++ b/nomad/vault_test.go @@ -12,12 +12,20 @@ import ( "golang.org/x/time/rate" + "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/nomad/structs/config" "github.com/hashicorp/nomad/testutil" vapi "github.com/hashicorp/vault/api" ) +const ( + // authPolicy is a policy that allows token creation operations + authPolicy = `path "auth/token/create/*" { + capabilities = ["create", "read", "update", "delete", "list"] +}` +) + func TestVaultClient_BadConfig(t *testing.T) { conf := &config.VaultConfig{} logger := log.New(os.Stderr, "", log.LstdFlags) @@ -78,15 +86,20 @@ func TestVaultClient_EstablishConnection(t *testing.T) { } } -func TestVaultClient_RenewalLoop(t *testing.T) { - v := testutil.NewTestVault(t).Start() - defer v.Stop() +// testVaultRoleAndToken creates a test Vault role where children are created +// with the passed period. A token created in that role is returned +func testVaultRoleAndToken(v *testutil.TestVault, t *testing.T, rolePeriod int) string { + // Build the auth policy + sys := v.Client.Sys() + if err := sys.PutPolicy("auth", authPolicy); err != nil { + t.Fatalf("failed to create auth policy: %v", err) + } // Build a role l := v.Client.Logical() d := make(map[string]interface{}, 2) - d["allowed_policies"] = "default" - d["period"] = 5 + d["allowed_policies"] = "default,auth" + d["period"] = rolePeriod l.Write("auth/token/roles/test", d) // Create a new token with the role @@ -102,8 +115,15 @@ func TestVaultClient_RenewalLoop(t *testing.T) { t.Fatalf("bad secret response: %+v", s) } - // Set the configs token - v.Config.Token = s.Auth.ClientToken + return s.Auth.ClientToken +} + +func TestVaultClient_RenewalLoop(t *testing.T) { + v := testutil.NewTestVault(t).Start() + defer v.Stop() + + // Set the configs token in a new test role + v.Config.Token = testVaultRoleAndToken(v, t, 5) // Start the client logger := log.New(os.Stderr, "", log.LstdFlags) @@ -117,6 +137,7 @@ func TestVaultClient_RenewalLoop(t *testing.T) { time.Sleep(8 * time.Second) // Get the current TTL + a := v.Client.Auth().Token() s2, err := a.Lookup(v.Config.Token) if err != nil { t.Fatalf("failed to lookup token: %v", err) @@ -303,3 +324,90 @@ func TestVaultClient_LookupToken_RateLimit(t *testing.T) { t.Fatalf("Incorrect number of cancels; got %d; want %d", cancels, desired) } } + +func TestVaultClient_CreateToken_Root(t *testing.T) { + v := testutil.NewTestVault(t).Start() + defer v.Stop() + + logger := log.New(os.Stderr, "", log.LstdFlags) + client, err := NewVaultClient(v.Config, logger) + if err != nil { + t.Fatalf("failed to build vault client: %v", err) + } + + waitForConnection(client, t) + + // Create an allocation that requires a Vault policy + a := mock.Alloc() + task := a.Job.TaskGroups[0].Tasks[0] + task.Vault = &structs.Vault{Policies: []string{"default"}} + + s, err := client.CreateToken(context.Background(), a, task.Name) + if err != nil { + t.Fatalf("CreateToken failed: %v", err) + } + + // Ensure that created secret is a wrapped token + if s == nil || s.WrapInfo == nil { + t.Fatalf("Bad secret: %#v", s) + } + + d, err := time.ParseDuration(vaultTokenCreateTTL) + if err != nil { + t.Fatalf("bad: %v", err) + } + + if s.WrapInfo.WrappedAccessor == "" { + t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor) + } else if s.WrapInfo.Token == "" { + t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor) + } else if s.WrapInfo.TTL != int(d.Seconds()) { + t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor) + } +} + +func TestVaultClient_CreateToken_Role(t *testing.T) { + v := testutil.NewTestVault(t).Start() + defer v.Stop() + + // Set the configs token in a new test role + v.Config.Token = testVaultRoleAndToken(v, t, 5) + //testVaultRoleAndToken(v, t, 5) + // Start the client + logger := log.New(os.Stderr, "", log.LstdFlags) + client, err := NewVaultClient(v.Config, logger) + if err != nil { + t.Fatalf("failed to build vault client: %v", err) + } + defer client.Stop() + + waitForConnection(client, t) + + // Create an allocation that requires a Vault policy + a := mock.Alloc() + task := a.Job.TaskGroups[0].Tasks[0] + task.Vault = &structs.Vault{Policies: []string{"default"}} + + s, err := client.CreateToken(context.Background(), a, task.Name) + if err != nil { + t.Fatalf("CreateToken failed: %v", err) + } + + // Ensure that created secret is a wrapped token + if s == nil || s.WrapInfo == nil { + t.Fatalf("Bad secret: %#v", s) + } + + d, err := time.ParseDuration(vaultTokenCreateTTL) + if err != nil { + t.Fatalf("bad: %v", err) + } + + if s.WrapInfo.WrappedAccessor == "" { + t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor) + } else if s.WrapInfo.Token == "" { + t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor) + } else if s.WrapInfo.TTL != int(d.Seconds()) { + t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor) + } +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 2656d693a..6e0dcba03 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -833,6 +833,12 @@ "revision": "30db96677b74e24b967e23f911eb3364fc61a011", "revisionTime": "2016-05-25T13:11:03Z" }, + { + "checksumSHA1": "S0DP7Pn7sZUmXc55IzZnNvERu6s=", + "path": "golang.org/x/sync/errgroup", + "revision": "316e794f7b5e3df4e95175a45a5fb8b12f85cb4f", + "revisionTime": "2016-07-15T18:54:39Z" + }, { "path": "golang.org/x/sys/unix", "revision": "50c6bc5e4292a1d4e65c6e9be5f53be28bcbe28e"