open-vault/builtin/logical/nomad/backend_test.go

303 lines
7.5 KiB
Go
Raw Normal View History

2017-09-28 20:44:30 +00:00
package nomad
import (
"context"
2017-09-28 20:44:30 +00:00
"fmt"
"os"
"reflect"
"testing"
"time"
nomadapi "github.com/hashicorp/nomad/api"
"github.com/hashicorp/vault/logical"
"github.com/mitchellh/mapstructure"
dockertest "gopkg.in/ory-am/dockertest.v3"
)
func prepareTestContainer(t *testing.T) (cleanup func(), retAddress string, nomadToken string) {
nomadToken = os.Getenv("NOMAD_TOKEN")
retAddress = os.Getenv("NOMAD_ADDR")
if retAddress != "" {
return func() {}, retAddress, nomadToken
}
pool, err := dockertest.NewPool("")
if err != nil {
t.Fatalf("Failed to connect to docker: %s", err)
}
dockerOptions := &dockertest.RunOptions{
Repository: "djenriquez/nomad",
Tag: "latest",
2017-09-28 20:44:30 +00:00
Cmd: []string{"agent", "-dev"},
Env: []string{`NOMAD_LOCAL_CONFIG=bind_addr = "0.0.0.0" acl { enabled = true }`},
2017-09-28 20:44:30 +00:00
}
resource, err := pool.RunWithOptions(dockerOptions)
if err != nil {
t.Fatalf("Could not start local Nomad docker container: %s", err)
}
cleanup = func() {
err := pool.Purge(resource)
if err != nil {
t.Fatalf("Failed to cleanup local container: %s", err)
}
}
retAddress = fmt.Sprintf("http://localhost:%s/", resource.GetPort("4646/tcp"))
// Give Nomad time to initialize
2017-09-28 20:44:30 +00:00
time.Sleep(5000 * time.Millisecond)
2017-09-28 20:44:30 +00:00
// exponential backoff-retry
if err = pool.Retry(func() error {
var err error
nomadapiConfig := nomadapi.DefaultConfig()
nomadapiConfig.Address = retAddress
nomad, err := nomadapi.NewClient(nomadapiConfig)
if err != nil {
return err
}
aclbootstrap, _, err := nomad.ACLTokens().Bootstrap(nil)
if err != nil {
t.Fatalf("err: %v", err)
}
2017-09-28 20:44:30 +00:00
nomadToken = aclbootstrap.SecretID
2017-12-16 00:50:20 +00:00
t.Logf("[WARN] Generated Master token: %s", nomadToken)
2017-09-28 20:44:30 +00:00
policy := &nomadapi.ACLPolicy{
Name: "test",
Description: "test",
Rules: `namespace "default" {
policy = "read"
}
`,
2017-09-29 08:33:58 +00:00
}
anonPolicy := &nomadapi.ACLPolicy{
Name: "anonymous",
Description: "Deny all access for anonymous requests",
Rules: `namespace "default" {
policy = "deny"
}
agent {
policy = "deny"
}
node {
policy = "deny"
}
`,
2017-09-28 20:44:30 +00:00
}
nomadAuthConfig := nomadapi.DefaultConfig()
nomadAuthConfig.Address = retAddress
nomadAuthConfig.SecretID = nomadToken
nomadAuth, err := nomadapi.NewClient(nomadAuthConfig)
_, err = nomadAuth.ACLPolicies().Upsert(policy, nil)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
2017-09-29 08:33:58 +00:00
_, err = nomadAuth.ACLPolicies().Upsert(anonPolicy, nil)
if err != nil {
t.Fatal(err)
}
2017-09-28 20:44:30 +00:00
return err
}); err != nil {
cleanup()
t.Fatalf("Could not connect to docker: %s", err)
}
return cleanup, retAddress, nomadToken
}
func TestBackend_config_access(t *testing.T) {
config := logical.TestBackendConfig()
config.StorageView = &logical.InmemStorage{}
b, err := Factory(context.Background(), config)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
cleanup, connURL, connToken := prepareTestContainer(t)
defer cleanup()
connData := map[string]interface{}{
"address": connURL,
"token": connToken,
}
confReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "config/access",
Storage: config.StorageView,
Data: connData,
}
resp, err := b.HandleRequest(context.Background(), confReq)
2017-09-28 20:44:30 +00:00
if err != nil || (resp != nil && resp.IsError()) || resp != nil {
t.Fatalf("failed to write configuration: resp:%#v err:%s", resp, err)
}
confReq.Operation = logical.ReadOperation
resp, err = b.HandleRequest(context.Background(), confReq)
2017-09-28 20:44:30 +00:00
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("failed to write configuration: resp:%#v err:%s", resp, err)
}
expected := map[string]interface{}{
"address": connData["address"].(string),
}
if !reflect.DeepEqual(expected, resp.Data) {
t.Fatalf("bad: expected:%#v\nactual:%#v\n", expected, resp.Data)
}
if resp.Data["token"] != nil {
t.Fatalf("token should not be set in the response")
}
}
func TestBackend_renew_revoke(t *testing.T) {
config := logical.TestBackendConfig()
config.StorageView = &logical.InmemStorage{}
b, err := Factory(context.Background(), config)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
2017-09-29 08:35:17 +00:00
cleanup, connURL, connToken := prepareTestContainer(t)
defer cleanup()
2017-09-28 20:44:30 +00:00
connData := map[string]interface{}{
"address": connURL,
"token": connToken,
}
req := &logical.Request{
Storage: config.StorageView,
Operation: logical.UpdateOperation,
Path: "config/access",
Data: connData,
}
resp, err := b.HandleRequest(context.Background(), req)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
2017-10-31 20:56:56 +00:00
req.Path = "role/test"
2017-09-28 20:44:30 +00:00
req.Data = map[string]interface{}{
2017-11-29 16:31:17 +00:00
"policies": []string{"policy"},
"lease": "6h",
2017-09-28 20:44:30 +00:00
}
resp, err = b.HandleRequest(context.Background(), req)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
req.Operation = logical.ReadOperation
req.Path = "creds/test"
resp, err = b.HandleRequest(context.Background(), req)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("resp nil")
}
if resp.IsError() {
t.Fatalf("resp is error: %v", resp.Error())
}
generatedSecret := resp.Secret
generatedSecret.TTL = 6 * time.Hour
var d struct {
2017-09-29 08:33:58 +00:00
Token string `mapstructure:"secret_id"`
Accessor string `mapstructure:"accessor_id"`
2017-09-28 20:44:30 +00:00
}
if err := mapstructure.Decode(resp.Data, &d); err != nil {
t.Fatal(err)
}
2018-03-20 18:54:10 +00:00
t.Logf("[WARN] Generated token: %s with accessor %s", d.Token, d.Accessor)
2017-09-28 20:44:30 +00:00
// Build a client and verify that the credentials work
nomadapiConfig := nomadapi.DefaultConfig()
nomadapiConfig.Address = connData["address"].(string)
nomadapiConfig.SecretID = d.Token
client, err := nomadapi.NewClient(nomadapiConfig)
if err != nil {
t.Fatal(err)
}
2017-10-31 19:11:24 +00:00
t.Log("[WARN] Verifying that the generated token works...")
2017-09-29 08:33:58 +00:00
_, err = client.Agent().Members, nil
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
req.Operation = logical.RenewOperation
req.Secret = generatedSecret
resp, err = b.HandleRequest(context.Background(), req)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("got nil response from renew")
}
req.Operation = logical.RevokeOperation
resp, err = b.HandleRequest(context.Background(), req)
2017-09-28 20:44:30 +00:00
if err != nil {
t.Fatal(err)
}
2017-09-29 08:33:58 +00:00
// Build a management client and verify that the token does not exist anymore
nomadmgmtConfig := nomadapi.DefaultConfig()
nomadmgmtConfig.Address = connData["address"].(string)
nomadmgmtConfig.SecretID = connData["token"].(string)
mgmtclient, err := nomadapi.NewClient(nomadmgmtConfig)
q := &nomadapi.QueryOptions{
Namespace: "default",
}
2017-10-31 19:11:24 +00:00
t.Log("[WARN] Verifying that the generated token does not exist...")
2017-09-29 08:33:58 +00:00
_, _, err = mgmtclient.ACLTokens().Info(d.Accessor, q)
2017-09-28 20:44:30 +00:00
if err == nil {
2017-09-29 08:33:58 +00:00
t.Fatal("err: expected error")
2017-09-28 20:44:30 +00:00
}
}
func TestBackend_CredsCreateEnvVar(t *testing.T) {
config := logical.TestBackendConfig()
config.StorageView = &logical.InmemStorage{}
b, err := Factory(context.Background(), config)
if err != nil {
t.Fatal(err)
}
cleanup, connURL, connToken := prepareTestContainer(t)
defer cleanup()
req := logical.TestRequest(t, logical.UpdateOperation, "role/test")
req.Data = map[string]interface{}{
"policies": []string{"policy"},
"lease": "6h",
}
resp, err := b.HandleRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
os.Setenv("NOMAD_TOKEN", connToken)
defer os.Unsetenv("NOMAD_TOKEN")
os.Setenv("NOMAD_ADDR", connURL)
defer os.Unsetenv("NOMAD_ADDR")
req.Operation = logical.ReadOperation
req.Path = "creds/test"
resp, err = b.HandleRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("resp nil")
}
if resp.IsError() {
t.Fatalf("resp is error: %v", resp.Error())
}
}