mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 18:48:08 +00:00 
			
		
		
		
	 ef6d8cc8d0
			
		
	
	ef6d8cc8d0
	
	
	
		
			
			* use internal docker mirror for CI * maybe it needs to be https * no just kidding it's docker:// * apparently overriding it globally causes creates to fail. time to override each image individually lol * maybe this works
		
			
				
	
	
		
			709 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			709 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) HashiCorp, Inc.
 | |
| // SPDX-License-Identifier: MPL-2.0
 | |
| 
 | |
| package nomad
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	nomadapi "github.com/hashicorp/nomad/api"
 | |
| 	"github.com/hashicorp/vault/helper/testhelpers"
 | |
| 	"github.com/hashicorp/vault/sdk/helper/docker"
 | |
| 	"github.com/hashicorp/vault/sdk/logical"
 | |
| 	"github.com/mitchellh/mapstructure"
 | |
| )
 | |
| 
 | |
| type Config struct {
 | |
| 	docker.ServiceURL
 | |
| 	Token string
 | |
| }
 | |
| 
 | |
| func (c *Config) APIConfig() *nomadapi.Config {
 | |
| 	apiConfig := nomadapi.DefaultConfig()
 | |
| 	apiConfig.Address = c.URL().String()
 | |
| 	apiConfig.SecretID = c.Token
 | |
| 	return apiConfig
 | |
| }
 | |
| 
 | |
| func (c *Config) Client() (*nomadapi.Client, error) {
 | |
| 	apiConfig := c.APIConfig()
 | |
| 
 | |
| 	return nomadapi.NewClient(apiConfig)
 | |
| }
 | |
| 
 | |
| func prepareTestContainer(t *testing.T, bootstrap bool) (func(), *Config) {
 | |
| 	if retAddress := os.Getenv("NOMAD_ADDR"); retAddress != "" {
 | |
| 		s, err := docker.NewServiceURLParse(retAddress)
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 		return func() {}, &Config{*s, os.Getenv("NOMAD_TOKEN")}
 | |
| 	}
 | |
| 
 | |
| 	runner, err := docker.NewServiceRunner(docker.RunOptions{
 | |
| 		ImageRepo:     "docker.mirror.hashicorp.services/multani/nomad",
 | |
| 		ImageTag:      "1.1.6",
 | |
| 		ContainerName: "nomad",
 | |
| 		Ports:         []string{"4646/tcp"},
 | |
| 		Cmd:           []string{"agent", "-dev"},
 | |
| 		Env:           []string{`NOMAD_LOCAL_CONFIG=bind_addr = "0.0.0.0" acl { enabled = true }`},
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Could not start docker Nomad: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	var nomadToken string
 | |
| 	svc, err := runner.StartService(context.Background(), func(ctx context.Context, host string, port int) (docker.ServiceConfig, error) {
 | |
| 		var err error
 | |
| 		nomadapiConfig := nomadapi.DefaultConfig()
 | |
| 		nomadapiConfig.Address = fmt.Sprintf("http://%s:%d/", host, port)
 | |
| 		nomad, err := nomadapi.NewClient(nomadapiConfig)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		_, err = nomad.Status().Leader()
 | |
| 		if err != nil {
 | |
| 			t.Logf("[DEBUG] Nomad is not ready yet: %s", err)
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		if bootstrap {
 | |
| 			aclbootstrap, _, err := nomad.ACLTokens().Bootstrap(nil)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			nomadToken = aclbootstrap.SecretID
 | |
| 			t.Logf("[WARN] Generated Master token: %s", nomadToken)
 | |
| 		}
 | |
| 
 | |
| 		nomadAuthConfig := nomadapi.DefaultConfig()
 | |
| 		nomadAuthConfig.Address = nomad.Address()
 | |
| 
 | |
| 		if bootstrap {
 | |
| 			nomadAuthConfig.SecretID = nomadToken
 | |
| 
 | |
| 			nomadAuth, err := nomadapi.NewClient(nomadAuthConfig)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 
 | |
| 			err = preprePolicies(nomadAuth)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		u, _ := docker.NewServiceURLParse(nomadapiConfig.Address)
 | |
| 		return &Config{
 | |
| 			ServiceURL: *u,
 | |
| 			Token:      nomadToken,
 | |
| 		}, nil
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Could not start docker Nomad: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	return svc.Cleanup, svc.Config.(*Config)
 | |
| }
 | |
| 
 | |
| func preprePolicies(nomadClient *nomadapi.Client) error {
 | |
| 	policy := &nomadapi.ACLPolicy{
 | |
| 		Name:        "test",
 | |
| 		Description: "test",
 | |
| 		Rules: `namespace "default" {
 | |
|         policy = "read"
 | |
|       }
 | |
|       `,
 | |
| 	}
 | |
| 	anonPolicy := &nomadapi.ACLPolicy{
 | |
| 		Name:        "anonymous",
 | |
| 		Description: "Deny all access for anonymous requests",
 | |
| 		Rules: `namespace "default" {
 | |
|             policy = "deny"
 | |
|         }
 | |
|         agent {
 | |
|             policy = "deny"
 | |
|         }
 | |
|         node {
 | |
|             policy = "deny"
 | |
|         }
 | |
|         `,
 | |
| 	}
 | |
| 
 | |
| 	_, err := nomadClient.ACLPolicies().Upsert(policy, nil)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	_, err = nomadClient.ACLPolicies().Upsert(anonPolicy, nil)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func TestBackend_config_Bootstrap(t *testing.T) {
 | |
| 	config := logical.TestBackendConfig()
 | |
| 	config.StorageView = &logical.InmemStorage{}
 | |
| 	b, err := Factory(context.Background(), config)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	cleanup, svccfg := prepareTestContainer(t, false)
 | |
| 	defer cleanup()
 | |
| 
 | |
| 	connData := map[string]interface{}{
 | |
| 		"address": svccfg.URL().String(),
 | |
| 		"token":   "",
 | |
| 	}
 | |
| 
 | |
| 	confReq := &logical.Request{
 | |
| 		Operation: logical.UpdateOperation,
 | |
| 		Path:      "config/access",
 | |
| 		Storage:   config.StorageView,
 | |
| 		Data:      connData,
 | |
| 	}
 | |
| 
 | |
| 	resp, err := b.HandleRequest(context.Background(), confReq)
 | |
| 	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)
 | |
| 	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),
 | |
| 		"max_token_name_length": 0,
 | |
| 		"ca_cert":               "",
 | |
| 		"client_cert":           "",
 | |
| 	}
 | |
| 	if !reflect.DeepEqual(expected, resp.Data) {
 | |
| 		t.Fatalf("bad: expected:%#v\nactual:%#v\n", expected, resp.Data)
 | |
| 	}
 | |
| 
 | |
| 	nomadClient, err := svccfg.Client()
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("failed to construct nomaad client, %v", err)
 | |
| 	}
 | |
| 
 | |
| 	token, _, err := nomadClient.ACLTokens().Bootstrap(nil)
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("expected acl system to be bootstrapped already, but was able to get the bootstrap token : %v", token)
 | |
| 	}
 | |
| 	// NOTE: fragile test, but it's the only way, AFAIK, to check that nomad is
 | |
| 	// bootstrapped
 | |
| 	if !strings.Contains(err.Error(), "bootstrap already done") {
 | |
| 		t.Fatalf("expected acl system to be bootstrapped already: err: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestBackend_config_access(t *testing.T) {
 | |
| 	config := logical.TestBackendConfig()
 | |
| 	config.StorageView = &logical.InmemStorage{}
 | |
| 	b, err := Factory(context.Background(), config)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	cleanup, svccfg := prepareTestContainer(t, true)
 | |
| 	defer cleanup()
 | |
| 
 | |
| 	connData := map[string]interface{}{
 | |
| 		"address": svccfg.URL().String(),
 | |
| 		"token":   svccfg.Token,
 | |
| 	}
 | |
| 
 | |
| 	confReq := &logical.Request{
 | |
| 		Operation: logical.UpdateOperation,
 | |
| 		Path:      "config/access",
 | |
| 		Storage:   config.StorageView,
 | |
| 		Data:      connData,
 | |
| 	}
 | |
| 
 | |
| 	resp, err := b.HandleRequest(context.Background(), confReq)
 | |
| 	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)
 | |
| 	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),
 | |
| 		"max_token_name_length": 0,
 | |
| 		"ca_cert":               "",
 | |
| 		"client_cert":           "",
 | |
| 	}
 | |
| 	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_config_access_with_certs(t *testing.T) {
 | |
| 	config := logical.TestBackendConfig()
 | |
| 	config.StorageView = &logical.InmemStorage{}
 | |
| 	b, err := Factory(context.Background(), config)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	cleanup, svccfg := prepareTestContainer(t, true)
 | |
| 	defer cleanup()
 | |
| 
 | |
| 	connData := map[string]interface{}{
 | |
| 		"address":     svccfg.URL().String(),
 | |
| 		"token":       svccfg.Token,
 | |
| 		"ca_cert":     caCert,
 | |
| 		"client_cert": clientCert,
 | |
| 		"client_key":  clientKey,
 | |
| 	}
 | |
| 
 | |
| 	confReq := &logical.Request{
 | |
| 		Operation: logical.UpdateOperation,
 | |
| 		Path:      "config/access",
 | |
| 		Storage:   config.StorageView,
 | |
| 		Data:      connData,
 | |
| 	}
 | |
| 
 | |
| 	resp, err := b.HandleRequest(context.Background(), confReq)
 | |
| 	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)
 | |
| 	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),
 | |
| 		"max_token_name_length": 0,
 | |
| 		"ca_cert":               caCert,
 | |
| 		"client_cert":           clientCert,
 | |
| 	}
 | |
| 	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)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	cleanup, svccfg := prepareTestContainer(t, true)
 | |
| 	defer cleanup()
 | |
| 
 | |
| 	connData := map[string]interface{}{
 | |
| 		"address": svccfg.URL().String(),
 | |
| 		"token":   svccfg.Token,
 | |
| 	}
 | |
| 
 | |
| 	req := &logical.Request{
 | |
| 		Storage:   config.StorageView,
 | |
| 		Operation: logical.UpdateOperation,
 | |
| 		Path:      "config/access",
 | |
| 		Data:      connData,
 | |
| 	}
 | |
| 	resp, err := b.HandleRequest(context.Background(), req)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	req.Path = "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)
 | |
| 	}
 | |
| 
 | |
| 	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())
 | |
| 	}
 | |
| 
 | |
| 	generatedSecret := resp.Secret
 | |
| 	generatedSecret.TTL = 6 * time.Hour
 | |
| 
 | |
| 	var d struct {
 | |
| 		Token    string `mapstructure:"secret_id"`
 | |
| 		Accessor string `mapstructure:"accessor_id"`
 | |
| 	}
 | |
| 	if err := mapstructure.Decode(resp.Data, &d); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	t.Logf("[WARN] Generated token: %s with accessor %s", d.Token, d.Accessor)
 | |
| 
 | |
| 	// 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)
 | |
| 	}
 | |
| 
 | |
| 	t.Log("[WARN] Verifying that the generated token works...")
 | |
| 	_, err = client.Agent().Members, nil
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	req.Operation = logical.RenewOperation
 | |
| 	req.Secret = generatedSecret
 | |
| 	resp, err = b.HandleRequest(context.Background(), req)
 | |
| 	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)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// 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)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	q := &nomadapi.QueryOptions{
 | |
| 		Namespace: "default",
 | |
| 	}
 | |
| 
 | |
| 	t.Log("[WARN] Verifying that the generated token does not exist...")
 | |
| 	_, _, err = mgmtclient.ACLTokens().Info(d.Accessor, q)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("err: expected error")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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, svccfg := prepareTestContainer(t, true)
 | |
| 	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", svccfg.Token)
 | |
| 	defer os.Unsetenv("NOMAD_TOKEN")
 | |
| 	os.Setenv("NOMAD_ADDR", svccfg.URL().String())
 | |
| 	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())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestBackend_max_token_name_length(t *testing.T) {
 | |
| 	config := logical.TestBackendConfig()
 | |
| 	config.StorageView = &logical.InmemStorage{}
 | |
| 	b, err := Factory(context.Background(), config)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	cleanup, svccfg := prepareTestContainer(t, true)
 | |
| 	defer cleanup()
 | |
| 
 | |
| 	testCases := []struct {
 | |
| 		title       string
 | |
| 		roleName    string
 | |
| 		tokenLength int
 | |
| 	}{
 | |
| 		{
 | |
| 			title: "Default",
 | |
| 		},
 | |
| 		{
 | |
| 			title:       "ConfigOverride",
 | |
| 			tokenLength: 64,
 | |
| 		},
 | |
| 		{
 | |
| 			title:       "ConfigOverride-LongName",
 | |
| 			roleName:    "testlongerrolenametoexceed64charsdddddddddddddddddddddddd",
 | |
| 			tokenLength: 64,
 | |
| 		},
 | |
| 		{
 | |
| 			title:    "Notrim",
 | |
| 			roleName: "testlongersubrolenametoexceed64charsdddddddddddddddddddddddd",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tc := range testCases {
 | |
| 		t.Run(tc.title, func(t *testing.T) {
 | |
| 			// setup config/access
 | |
| 			connData := map[string]interface{}{
 | |
| 				"address":               svccfg.URL().String(),
 | |
| 				"token":                 svccfg.Token,
 | |
| 				"max_token_name_length": tc.tokenLength,
 | |
| 			}
 | |
| 			expected := map[string]interface{}{
 | |
| 				"address":               svccfg.URL().String(),
 | |
| 				"max_token_name_length": tc.tokenLength,
 | |
| 				"ca_cert":               "",
 | |
| 				"client_cert":           "",
 | |
| 			}
 | |
| 
 | |
| 			expectedMaxTokenNameLength := maxTokenNameLength
 | |
| 			if tc.tokenLength != 0 {
 | |
| 				expectedMaxTokenNameLength = tc.tokenLength
 | |
| 			}
 | |
| 
 | |
| 			confReq := logical.Request{
 | |
| 				Operation: logical.UpdateOperation,
 | |
| 				Path:      "config/access",
 | |
| 				Storage:   config.StorageView,
 | |
| 				Data:      connData,
 | |
| 			}
 | |
| 
 | |
| 			resp, err := b.HandleRequest(context.Background(), &confReq)
 | |
| 			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)
 | |
| 			if err != nil || (resp != nil && resp.IsError()) {
 | |
| 				t.Fatalf("failed to write configuration: resp:%#v err:%s", resp, err)
 | |
| 			}
 | |
| 
 | |
| 			// verify token length is returned in the config/access query
 | |
| 			if !reflect.DeepEqual(expected, resp.Data) {
 | |
| 				t.Fatalf("bad: expected:%#v\nactual:%#v\n", expected, resp.Data)
 | |
| 			}
 | |
| 			// verify token is not returned
 | |
| 			if resp.Data["token"] != nil {
 | |
| 				t.Fatalf("token should not be set in the response")
 | |
| 			}
 | |
| 
 | |
| 			// create a role to create nomad credentials with
 | |
| 			// Seeds random with current timestamp
 | |
| 
 | |
| 			if tc.roleName == "" {
 | |
| 				tc.roleName = "test"
 | |
| 			}
 | |
| 			roleTokenName := testhelpers.RandomWithPrefix(tc.roleName)
 | |
| 
 | |
| 			confReq.Path = "role/" + roleTokenName
 | |
| 			confReq.Operation = logical.UpdateOperation
 | |
| 			confReq.Data = map[string]interface{}{
 | |
| 				"policies": []string{"policy"},
 | |
| 				"lease":    "6h",
 | |
| 			}
 | |
| 			resp, err = b.HandleRequest(context.Background(), &confReq)
 | |
| 			if err != nil {
 | |
| 				t.Fatal(err)
 | |
| 			}
 | |
| 
 | |
| 			confReq.Operation = logical.ReadOperation
 | |
| 			confReq.Path = "creds/" + roleTokenName
 | |
| 			resp, err = b.HandleRequest(context.Background(), &confReq)
 | |
| 			if err != nil {
 | |
| 				t.Fatal(err)
 | |
| 			}
 | |
| 			if resp == nil {
 | |
| 				t.Fatal("resp nil")
 | |
| 			}
 | |
| 			if resp.IsError() {
 | |
| 				t.Fatalf("resp is error: %v", resp.Error())
 | |
| 			}
 | |
| 
 | |
| 			// extract the secret, so we can query nomad directly
 | |
| 			generatedSecret := resp.Secret
 | |
| 			generatedSecret.TTL = 6 * time.Hour
 | |
| 
 | |
| 			var d struct {
 | |
| 				Token    string `mapstructure:"secret_id"`
 | |
| 				Accessor string `mapstructure:"accessor_id"`
 | |
| 			}
 | |
| 			if err := mapstructure.Decode(resp.Data, &d); err != nil {
 | |
| 				t.Fatal(err)
 | |
| 			}
 | |
| 
 | |
| 			// 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)
 | |
| 			}
 | |
| 
 | |
| 			// default query options for Nomad queries ... not sure if needed
 | |
| 			qOpts := &nomadapi.QueryOptions{
 | |
| 				Namespace: "default",
 | |
| 			}
 | |
| 
 | |
| 			// connect to Nomad and verify the token name does not exceed the
 | |
| 			// max_token_name_length
 | |
| 			token, _, err := client.ACLTokens().Self(qOpts)
 | |
| 			if err != nil {
 | |
| 				t.Fatal(err)
 | |
| 			}
 | |
| 
 | |
| 			if len(token.Name) > expectedMaxTokenNameLength {
 | |
| 				t.Fatalf("token name exceeds max length (%d): %s (%d)", expectedMaxTokenNameLength, token.Name, len(token.Name))
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| const caCert = `-----BEGIN CERTIFICATE-----
 | |
| MIIF7zCCA9egAwIBAgIINVVQic4bju8wDQYJKoZIhvcNAQELBQAwaDELMAkGA1UE
 | |
| BhMCVVMxFDASBgNVBAoMC1Vuc3BlY2lmaWVkMR8wHQYDVQQLDBZjYS0zODQzMDY2
 | |
| NDA5ODI5MjQwNTU5MSIwIAYDVQQDDBl4cHMxNS5sb2NhbC5jaXBoZXJib3kuY29t
 | |
| MB4XDTIyMDYwMjIxMTgxN1oXDTIzMDcwNTIxMTgxN1owaDELMAkGA1UEBhMCVVMx
 | |
| FDASBgNVBAoMC1Vuc3BlY2lmaWVkMR8wHQYDVQQLDBZjYS0zODQzMDY2NDA5ODI5
 | |
| MjQwNTU5MSIwIAYDVQQDDBl4cHMxNS5sb2NhbC5jaXBoZXJib3kuY29tMIICIjAN
 | |
| BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA35VilgfqMUKhword7wORXRFyPbpz
 | |
| 8uqO7eRaylMnkAkbk5eoQB/iYfXjJ6ZBs5mJGQVz5ZNvh9EzZsk1J6wqYgbwVKUx
 | |
| fh4kvW6sXtDirtb4ZQAK7OTLEoapUQGnGcvm+aEYfvC1sTBl4fbex7yyN5FYMJTM
 | |
| TAUumhdq2pwujaj2xkN9DwZa89Tk7tbj9HE9DTRji7bnciEtrmTAOIOfOrT/1l3x
 | |
| YW1BwYXpQ0TamJ58pC/iNgEp5FAxKt9d3RggesMA7pvG/f8fNgsa/Tku/PeEXNPA
 | |
| +Yx4CcAipujmqpBKiKwJ6TOzp80m2zrZ7Da4Av5vVS5GsNJxhFYD1h8hU1ptK9BS
 | |
| 2CaTwBpV421C9BfEmtSAksGDIWYujfiHb6XNaQrt8Hu85GBuPUudVn0lpoXLn2xD
 | |
| rGK8WEK2gWZ4eez3ZDLbpLui6c1m7AVlMtj374s+LHcD7JIxY475Na7pXmEWReqM
 | |
| RUyCEq1spOOn70fOdhphhmpY6DoklOTOriPawCLNmkPWRnhrIwqyP1gse9YMqQ2n
 | |
| LhWUkv/08m/0pb4e5ijVhsZNzv+1PXPWCk968nzt0BMDgJT+0ZiXsaU7FILXuo7Y
 | |
| Ijgrj7dpXWx2MBdMGPFQdveog7Pa80Yb7r4ERW0DL78TxYC6m/S1p14PHwZpDZzQ
 | |
| LrPrBcpI5XzI7osCAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAqQwDAYDVR0TBAUw
 | |
| AwEB/zA0BgNVHR4ELTAroCkwG4IZeHBzMTUubG9jYWwuY2lwaGVyYm95LmNvbTAK
 | |
| hwh/AAAB/wAAADAkBgNVHREEHTAbghl4cHMxNS5sb2NhbC5jaXBoZXJib3kuY29t
 | |
| MB0GA1UdDgQWBBR3bHgDp5RpzerMKRkaGDFN/ZeImjANBgkqhkiG9w0BAQsFAAOC
 | |
| AgEArkuDYYWYHYxIoTeZkQz5L1y0H27ZWPJx5jBBuktPonDLQxBGAwkl6NZbJGLU
 | |
| v+usII+eyjPKIgjhCiTXJAmeIngwWoN3PHOLMIPe9axuNt6qVoP4dQtzfpPR3buK
 | |
| CWj9i3H0ixK73klk7QWZiBUDinYfEMSNRpU3G7NsqmqCXD4s5gB+8y9c7+zIiJyN
 | |
| IaJBWpzI4eQBi/4cBhtM7Xa+CMB/8whhWYR6H+GXGZdNcP5f7bwneMstWKceTadk
 | |
| IEzFucJHDySpEkIA2A9t33pV54FmEp+JVwvxAH4FABCnjPmhg0j1IonWV5pySWpG
 | |
| hhEZpnRRH1XfpTA5i6dlyUA5DJjL8X1lYrgOK+LaoR52mQh5JBsMoVHFzN50DiMA
 | |
| RTsbq4Qzozf23hU1BqW4NOzPTukgSGEcbT/DhXKPPPLL8JD0rPelJPq76X3TJjgZ
 | |
| C9uMnZaDnxjppDXp5oBIXqC05FDxJ5sSODNOpKGyuzOU2qQLMau33yYOgaSAttBk
 | |
| r29+LNFJ+0QzMuPjYXPznpxbsI+lrlZ3F2tDGGs8+JVceC1YX+cBEsEOiqNGTIip
 | |
| /DY3b9gu5oiTwhcFyQW8+WFsirRS/g5t+M40WLKVPdK09z96krFXQMkL6a7LHLY1
 | |
| n9ivwj+sTG1XmJYXp8naLg4wdzIUf2fJxaFNI5Yq4elZ8sY=
 | |
| -----END CERTIFICATE-----`
 | |
| 
 | |
| const clientCert = `-----BEGIN CERTIFICATE-----
 | |
| MIIEsDCCApigAwIBAgIIRY1JBRIynFYwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UE
 | |
| BhMCVVMxFDASBgNVBAoMC1Vuc3BlY2lmaWVkMR8wHQYDVQQLDBZjYS0zODQzMDY2
 | |
| NDA5ODI5MjQwNTU5MSIwIAYDVQQDDBl4cHMxNS5sb2NhbC5jaXBoZXJib3kuY29t
 | |
| MB4XDTIyMDYwMjIxMTgxOFoXDTIzMDcwNTIxMTgxOFowRzELMAkGA1UEBhMCVVMx
 | |
| FDASBgNVBAoMC1Vuc3BlY2lmaWVkMSIwIAYDVQQDDBl4cHMxNS5sb2NhbC5jaXBo
 | |
| ZXJib3kuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs+XYhsW2
 | |
| vTwN7gY3xMxgbNN8d3aoeqCswOp05BBf0Vgv3febahm422ubXXd5Mg2UGiU7sJVe
 | |
| 4tUpDeupVVRX5Qr/hpiXgEyfRDAAAJKqrl65KSS62TCbT/eJZ0ah25HV1evI4uM2
 | |
| 0kl5QWhtQjDyaVlTS38YFqXXQvpOuU5DG6UbKnpMcpsCPTyUKEJvJ95ZLcz0HJ8I
 | |
| kIHrnX0Lt0pOhkllj5Nk4cXhU8CFk8IGNz7SVAycrUsffAUMNNEbrIOIfOTPHR1c
 | |
| q3X9hO4/5pt80uIDMFwwumoA7nQR0AhlKkw9SskCIzJhKwKwssQY7fmovNG0fOEd
 | |
| /+vSHK7OsYW+gwIDAQABo38wfTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI
 | |
| KwYBBQUHAwIwCQYDVR0TBAIwADAqBgNVHREEIzAhghl4cHMxNS5sb2NhbC5jaXBo
 | |
| ZXJib3kuY29thwR/AAABMB8GA1UdIwQYMBaAFHdseAOnlGnN6swpGRoYMU39l4ia
 | |
| MA0GCSqGSIb3DQEBCwUAA4ICAQBUSP4ZJglCCrYkM5Le7McdvfkM5uYv1aQn0sM4
 | |
| gbyDEWO0fnv50vLpD3y4ckgHLoD52pAZ0hN8a7rwAUae21GA6DvEchSH5x/yvJiS
 | |
| 7FBlq39sAafe03ZlzDErNYJRkLcnPAqG74lJ1SSsMcs9gCPHM8R7HtNnhAga06L7
 | |
| K8/G43dsGZCmEb+xcX2B9McCt8jBG6TJPTGafb3BJ0JTmR/tHdoLFIiNwI+qzd2U
 | |
| lMnGlkIApULX8tmIMsWO0rjdiFkPWGcmfn9ChC0iDpQOAcKSDBcZlWrDNpzKk0mK
 | |
| l0TbE6cxcmCUUpiwaXFrbkwVWQw4W0c4b3sWFtWifFbiR1qZ/OT2Y2sHbkbxwvPl
 | |
| PjjXMDBAdRRwtNcTP1E55I5zvwzzBxUpxOob0miorhTJrZR9So0rgv7Roce4ED6M
 | |
| WETYa/mGhe+Q7gBQygIVoryfQLgGBsHC+7V4RDvYTazwZkz9nLQxHLI/TAZU5ofM
 | |
| WqdoUkMd68rxTTEUoMfGbftxjKA0raxGcO7/PjLR3O743EwCqeqYJ7OKWgGRLnui
 | |
| kIKNUJlZ9umURUFzL++Bx4Pr95jWXb2WYqYYQxhDz0oR5q5smnFm5+/1/MLDMvDU
 | |
| TrgBK6pey4QF33B/I55H1+7tGdv85Q57Z8UrNi/IQxR2sFlsOTeCwStpBQ56sdZk
 | |
| Wi4+cQ==
 | |
| -----END CERTIFICATE-----`
 | |
| 
 | |
| const clientKey = `-----BEGIN PRIVATE KEY-----
 | |
| MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCz5diGxba9PA3u
 | |
| BjfEzGBs03x3dqh6oKzA6nTkEF/RWC/d95tqGbjba5tdd3kyDZQaJTuwlV7i1SkN
 | |
| 66lVVFflCv+GmJeATJ9EMAAAkqquXrkpJLrZMJtP94lnRqHbkdXV68ji4zbSSXlB
 | |
| aG1CMPJpWVNLfxgWpddC+k65TkMbpRsqekxymwI9PJQoQm8n3lktzPQcnwiQgeud
 | |
| fQu3Sk6GSWWPk2ThxeFTwIWTwgY3PtJUDJytSx98BQw00Rusg4h85M8dHVyrdf2E
 | |
| 7j/mm3zS4gMwXDC6agDudBHQCGUqTD1KyQIjMmErArCyxBjt+ai80bR84R3/69Ic
 | |
| rs6xhb6DAgMBAAECggEAPBcja2kxcCZWNNKo4DiwYMmHwtPE1SlEazAlmWSKzP+b
 | |
| BZbGt/sdj1VzURYuSnTUqqMTPBm41yYCj57PMix5K42v6sKfoIB3lqw94/MZxiLn
 | |
| 0IFvVErzJhP2NqQWPqSI++rFcFwbHMTkFuAN1tVIs73dn9M1NaNxsvKvRyCIM/wz
 | |
| 5YQSDyTkdW4jQM2RvUFOoqwmeyAlQoBRMgQ4bHfLHxmPEjFgw1MAmmG8bJdkupin
 | |
| MVzhZyKj4Fh80Xa2MU4KokijjG41hmYbg/sjNHaHJFDA92Rwq13dhWytrauJDxa/
 | |
| 3yj8pHWc23Y3hXvRAf/cibDVzXmmLj49W1i06KuUCQKBgQDj5yF/DJV0IOkhfbol
 | |
| +f5AGH4ZrEXA/JwA5SxHU+aKhUuPEqK/LeUWqiy3szFjOz2JOnCC0LMN42nsmMyK
 | |
| sdQEKHp2SPd2wCxsAKZAuxrEi6yBt1mEPFFU5yzvZbdMqYChKJjm9fbRHtuc63s8
 | |
| PyVw67Ii9o4ij+PxfTobIs18xwKBgQDKE59w3uUDt2uoqNC8x4m5onL2p2vtcTHC
 | |
| CxU57mu1+9CRM8N2BEp2VI5JaXjqt6W4u9ISrmOqmsPgTwosAquKpA/nu3bVvR9g
 | |
| WlN9dh2Xgza0/AFaA9CB++ier8RJq5xFlcasMUmgkhYt3zgKNgRDfjfREWM0yamm
 | |
| P++hAYRcZQKBgHEuYQk6k6J3ka/rQ54GmEj2oPFZB88+5K7hIWtO9IhIiGzGYYK2
 | |
| ZTYrT0fvuxA/5GCZYDTnNnUoQnuYqsQaamOiQqcpt5QG/kiozegJw9JmV0aYauFs
 | |
| HyweHsfJaQ2uhE4E3mKdNnVGcORuYeZaqdp5gx8v+QibEyXj/g5p60kTAoGBALKp
 | |
| TMOHXmW9yqKwtvThWoRU+13WQlcJSFvuXpL8mCCrBgkLAhqaypb6RV7ksLKdMhk1
 | |
| fhNkOdxBv0LXvv+QUMhgK2vP084/yrjuw3hecOVfboPvduZ2DuiNp2p9rocQAjeH
 | |
| p8LgRN+Bqbhe7fYhMf3WX1UqEVM/pQ3G43+vjq39AoGAOyD2/hFSIx6BMddUNTHG
 | |
| BEsMUc/DHYslZebbF1zAWnkKdTt+URhtHAFB2tYRDgkZfwW+wr/w12dJTIkX965o
 | |
| HO7tI4FgpU9b0i8FTuwYkBfjwp2j0Xd2/VBR8Qpd17qKl3I6NXDsf3ykjGZAvldH
 | |
| Tll+qwEZpXSRa5OWWTpGV8I=
 | |
| -----END PRIVATE KEY-----`
 |