github.com/jrxfive/nomad@v0.6.1-0.20170802162750-1fef470e89bf/nomad/vault_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"log"
     8  	"math/rand"
     9  	"os"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"golang.org/x/time/rate"
    16  
    17  	"github.com/hashicorp/nomad/helper"
    18  	"github.com/hashicorp/nomad/nomad/mock"
    19  	"github.com/hashicorp/nomad/nomad/structs"
    20  	"github.com/hashicorp/nomad/nomad/structs/config"
    21  	"github.com/hashicorp/nomad/testutil"
    22  	vapi "github.com/hashicorp/vault/api"
    23  )
    24  
    25  const (
    26  	// nomadRoleManagementPolicy is a policy that allows nomad to manage tokens
    27  	nomadRoleManagementPolicy = `
    28  path "auth/token/renew-self" {
    29  	capabilities = ["update"]
    30  }
    31  
    32  path "auth/token/lookup" {
    33  	capabilities = ["update"]
    34  }
    35  
    36  path "auth/token/roles/test" {
    37  	capabilities = ["read"]
    38  }
    39  
    40  path "auth/token/revoke-accessor" {
    41  	capabilities = ["update"]
    42  }
    43  `
    44  
    45  	// tokenLookupPolicy allows a token to be looked up
    46  	tokenLookupPolicy = `
    47  path "auth/token/lookup" {
    48  	capabilities = ["update"]
    49  }
    50  `
    51  
    52  	// nomadRoleCreatePolicy gives the ability to create the role and derive tokens
    53  	// from the test role
    54  	nomadRoleCreatePolicy = `
    55  path "auth/token/create/test" {
    56  	capabilities = ["create", "update"]
    57  }
    58  `
    59  
    60  	// secretPolicy gives access to the secret mount
    61  	secretPolicy = `
    62  path "secret/*" {
    63  	capabilities = ["create", "read", "update", "delete", "list"]
    64  }
    65  `
    66  )
    67  
    68  // defaultTestVaultWhitelistRoleAndToken creates a test Vault role and returns a token
    69  // created in that role
    70  func defaultTestVaultWhitelistRoleAndToken(v *testutil.TestVault, t *testing.T, rolePeriod int) string {
    71  	vaultPolicies := map[string]string{
    72  		"nomad-role-create":     nomadRoleCreatePolicy,
    73  		"nomad-role-management": nomadRoleManagementPolicy,
    74  	}
    75  	d := make(map[string]interface{}, 2)
    76  	d["allowed_policies"] = "nomad-role-create,nomad-role-management"
    77  	d["period"] = rolePeriod
    78  	return testVaultRoleAndToken(v, t, vaultPolicies, d,
    79  		[]string{"nomad-role-create", "nomad-role-management"})
    80  }
    81  
    82  // defaultTestVaultBlacklistRoleAndToken creates a test Vault role using
    83  // disallowed_policies and returns a token created in that role
    84  func defaultTestVaultBlacklistRoleAndToken(v *testutil.TestVault, t *testing.T, rolePeriod int) string {
    85  	vaultPolicies := map[string]string{
    86  		"nomad-role-create":     nomadRoleCreatePolicy,
    87  		"nomad-role-management": nomadRoleManagementPolicy,
    88  		"secrets":               secretPolicy,
    89  	}
    90  
    91  	// Create the role
    92  	d := make(map[string]interface{}, 2)
    93  	d["disallowed_policies"] = "nomad-role-create"
    94  	d["period"] = rolePeriod
    95  	testVaultRoleAndToken(v, t, vaultPolicies, d, []string{"default"})
    96  
    97  	// Create a token that can use the role
    98  	a := v.Client.Auth().Token()
    99  	req := &vapi.TokenCreateRequest{
   100  		Policies: []string{"nomad-role-create", "nomad-role-management"},
   101  	}
   102  	s, err := a.Create(req)
   103  	if err != nil {
   104  		t.Fatalf("failed to create child token: %v", err)
   105  	}
   106  
   107  	if s == nil || s.Auth == nil {
   108  		t.Fatalf("bad secret response: %+v", s)
   109  	}
   110  
   111  	return s.Auth.ClientToken
   112  }
   113  
   114  // testVaultRoleAndToken writes the vaultPolicies to vault and then creates a
   115  // test role with the passed data. After that it derives a token from the role
   116  // with the tokenPolicies
   117  func testVaultRoleAndToken(v *testutil.TestVault, t *testing.T, vaultPolicies map[string]string,
   118  	data map[string]interface{}, tokenPolicies []string) string {
   119  	// Write the policies
   120  	sys := v.Client.Sys()
   121  	for p, data := range vaultPolicies {
   122  		if err := sys.PutPolicy(p, data); err != nil {
   123  			t.Fatalf("failed to create %q policy: %v", p, err)
   124  		}
   125  	}
   126  
   127  	// Build a role
   128  	l := v.Client.Logical()
   129  	l.Write("auth/token/roles/test", data)
   130  
   131  	// Create a new token with the role
   132  	a := v.Client.Auth().Token()
   133  	req := vapi.TokenCreateRequest{
   134  		Policies: tokenPolicies,
   135  	}
   136  	s, err := a.CreateWithRole(&req, "test")
   137  	if err != nil {
   138  		t.Fatalf("failed to create child token: %v", err)
   139  	}
   140  
   141  	// Get the client token
   142  	if s == nil || s.Auth == nil {
   143  		t.Fatalf("bad secret response: %+v", s)
   144  	}
   145  
   146  	return s.Auth.ClientToken
   147  }
   148  
   149  func TestVaultClient_BadConfig(t *testing.T) {
   150  	t.Parallel()
   151  	conf := &config.VaultConfig{}
   152  	logger := log.New(os.Stderr, "", log.LstdFlags)
   153  
   154  	// Should be no error since Vault is not enabled
   155  	_, err := NewVaultClient(nil, logger, nil)
   156  	if err == nil || !strings.Contains(err.Error(), "valid") {
   157  		t.Fatalf("expected config error: %v", err)
   158  	}
   159  
   160  	tr := true
   161  	conf.Enabled = &tr
   162  	_, err = NewVaultClient(conf, logger, nil)
   163  	if err == nil || !strings.Contains(err.Error(), "token must be set") {
   164  		t.Fatalf("Expected token unset error: %v", err)
   165  	}
   166  
   167  	conf.Token = "123"
   168  	_, err = NewVaultClient(conf, logger, nil)
   169  	if err == nil || !strings.Contains(err.Error(), "address must be set") {
   170  		t.Fatalf("Expected address unset error: %v", err)
   171  	}
   172  }
   173  
   174  // started seperately.
   175  // Test that the Vault Client can establish a connection even if it is started
   176  // before Vault is available.
   177  func TestVaultClient_EstablishConnection(t *testing.T) {
   178  	t.Parallel()
   179  	for i := 10; i >= 0; i-- {
   180  		v := testutil.NewTestVaultDelayed(t)
   181  		logger := log.New(os.Stderr, "", log.LstdFlags)
   182  		v.Config.ConnectionRetryIntv = 100 * time.Millisecond
   183  		client, err := NewVaultClient(v.Config, logger, nil)
   184  		if err != nil {
   185  			t.Fatalf("failed to build vault client: %v", err)
   186  		}
   187  
   188  		// Sleep a little while and check that no connection has been established.
   189  		time.Sleep(100 * time.Duration(testutil.TestMultiplier()) * time.Millisecond)
   190  		if established, _ := client.ConnectionEstablished(); established {
   191  			t.Fatalf("ConnectionEstablished() returned true before Vault server started")
   192  		}
   193  
   194  		// Start Vault
   195  		if err := v.Start(); err != nil {
   196  			v.Stop()
   197  			client.Stop()
   198  
   199  			if i == 0 {
   200  				t.Fatalf("Failed to start vault: %v", err)
   201  			}
   202  
   203  			wait := time.Duration(rand.Int31n(2000)) * time.Millisecond
   204  			time.Sleep(wait)
   205  			continue
   206  		}
   207  
   208  		var waitErr error
   209  		testutil.WaitForResult(func() (bool, error) {
   210  			return client.ConnectionEstablished()
   211  		}, func(err error) {
   212  			waitErr = err
   213  		})
   214  
   215  		v.Stop()
   216  		client.Stop()
   217  		if waitErr != nil {
   218  			if i == 0 {
   219  				t.Fatalf("Failed to start vault: %v", err)
   220  			}
   221  
   222  			wait := time.Duration(rand.Int31n(2000)) * time.Millisecond
   223  			time.Sleep(wait)
   224  			continue
   225  		}
   226  
   227  		break
   228  	}
   229  }
   230  
   231  func TestVaultClient_ValidateRole(t *testing.T) {
   232  	t.Parallel()
   233  	v := testutil.NewTestVault(t)
   234  	defer v.Stop()
   235  
   236  	// Set the configs token in a new test role
   237  	vaultPolicies := map[string]string{
   238  		"nomad-role-create":     nomadRoleCreatePolicy,
   239  		"nomad-role-management": nomadRoleManagementPolicy,
   240  	}
   241  	data := map[string]interface{}{
   242  		"allowed_policies": "default,root",
   243  		"orphan":           true,
   244  		"renewable":        true,
   245  		"explicit_max_ttl": 10,
   246  	}
   247  	v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, nil)
   248  
   249  	logger := log.New(os.Stderr, "", log.LstdFlags)
   250  	v.Config.ConnectionRetryIntv = 100 * time.Millisecond
   251  	client, err := NewVaultClient(v.Config, logger, nil)
   252  	if err != nil {
   253  		t.Fatalf("failed to build vault client: %v", err)
   254  	}
   255  	defer client.Stop()
   256  
   257  	// Wait for an error
   258  	var conn bool
   259  	var connErr error
   260  	testutil.WaitForResult(func() (bool, error) {
   261  		conn, connErr = client.ConnectionEstablished()
   262  		if conn {
   263  			return false, fmt.Errorf("Should not connect")
   264  		}
   265  
   266  		if connErr == nil {
   267  			return false, fmt.Errorf("expect an error")
   268  		}
   269  
   270  		return true, nil
   271  	}, func(err error) {
   272  		t.Fatalf("bad: %v", err)
   273  	})
   274  
   275  	errStr := connErr.Error()
   276  	if !strings.Contains(errStr, "not allow orphans") {
   277  		t.Fatalf("Expect orphan error")
   278  	}
   279  	if !strings.Contains(errStr, "explicit max ttl") {
   280  		t.Fatalf("Expect explicit max ttl error")
   281  	}
   282  }
   283  
   284  func TestVaultClient_ValidateRole_NonExistant(t *testing.T) {
   285  	t.Parallel()
   286  	v := testutil.NewTestVault(t)
   287  	defer v.Stop()
   288  
   289  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   290  	v.Config.Token = v.RootToken
   291  	logger := log.New(os.Stderr, "", log.LstdFlags)
   292  	v.Config.ConnectionRetryIntv = 100 * time.Millisecond
   293  	v.Config.Role = "test-nonexistant"
   294  	client, err := NewVaultClient(v.Config, logger, nil)
   295  	if err != nil {
   296  		t.Fatalf("failed to build vault client: %v", err)
   297  	}
   298  	defer client.Stop()
   299  
   300  	// Wait for an error
   301  	var conn bool
   302  	var connErr error
   303  	testutil.WaitForResult(func() (bool, error) {
   304  		conn, connErr = client.ConnectionEstablished()
   305  		if conn {
   306  			return false, fmt.Errorf("Should not connect")
   307  		}
   308  
   309  		if connErr == nil {
   310  			return false, fmt.Errorf("expect an error")
   311  		}
   312  
   313  		return true, nil
   314  	}, func(err error) {
   315  		t.Fatalf("bad: %v", err)
   316  	})
   317  
   318  	errStr := connErr.Error()
   319  	if !strings.Contains(errStr, "does not exist") {
   320  		t.Fatalf("Expect orphan error")
   321  	}
   322  }
   323  
   324  func TestVaultClient_ValidateToken(t *testing.T) {
   325  	t.Parallel()
   326  	v := testutil.NewTestVault(t)
   327  	defer v.Stop()
   328  
   329  	// Set the configs token in a new test role
   330  	vaultPolicies := map[string]string{
   331  		"nomad-role-create": nomadRoleCreatePolicy,
   332  		"token-lookup":      tokenLookupPolicy,
   333  	}
   334  	data := map[string]interface{}{
   335  		"allowed_policies": "token-lookup,nomad-role-create",
   336  		"period":           10,
   337  	}
   338  	v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, []string{"token-lookup", "nomad-role-create"})
   339  
   340  	logger := log.New(os.Stderr, "", log.LstdFlags)
   341  	v.Config.ConnectionRetryIntv = 100 * time.Millisecond
   342  	client, err := NewVaultClient(v.Config, logger, nil)
   343  	if err != nil {
   344  		t.Fatalf("failed to build vault client: %v", err)
   345  	}
   346  	defer client.Stop()
   347  
   348  	// Wait for an error
   349  	var conn bool
   350  	var connErr error
   351  	testutil.WaitForResult(func() (bool, error) {
   352  		conn, connErr = client.ConnectionEstablished()
   353  		if conn {
   354  			return false, fmt.Errorf("Should not connect")
   355  		}
   356  
   357  		if connErr == nil {
   358  			return false, fmt.Errorf("expect an error")
   359  		}
   360  
   361  		return true, nil
   362  	}, func(err error) {
   363  		t.Fatalf("bad: %v", err)
   364  	})
   365  
   366  	errStr := connErr.Error()
   367  	if !strings.Contains(errStr, vaultTokenRevokePath) {
   368  		t.Fatalf("Expect orphan error")
   369  	}
   370  	if !strings.Contains(errStr, fmt.Sprintf(vaultRoleLookupPath, "test")) {
   371  		t.Fatalf("Expect explicit max ttl error")
   372  	}
   373  	if !strings.Contains(errStr, "token must have one of the following") {
   374  		t.Fatalf("Expect explicit max ttl error")
   375  	}
   376  }
   377  
   378  func TestVaultClient_SetActive(t *testing.T) {
   379  	t.Parallel()
   380  	v := testutil.NewTestVault(t)
   381  	defer v.Stop()
   382  
   383  	logger := log.New(os.Stderr, "", log.LstdFlags)
   384  	client, err := NewVaultClient(v.Config, logger, nil)
   385  	if err != nil {
   386  		t.Fatalf("failed to build vault client: %v", err)
   387  	}
   388  	defer client.Stop()
   389  
   390  	waitForConnection(client, t)
   391  
   392  	// Do a lookup and expect an error about not being active
   393  	_, err = client.LookupToken(context.Background(), "123")
   394  	if err == nil || !strings.Contains(err.Error(), "not active") {
   395  		t.Fatalf("Expected not-active error: %v", err)
   396  	}
   397  
   398  	client.SetActive(true)
   399  
   400  	// Do a lookup of ourselves
   401  	_, err = client.LookupToken(context.Background(), v.RootToken)
   402  	if err != nil {
   403  		t.Fatalf("Unexpected error: %v", err)
   404  	}
   405  }
   406  
   407  // Test that we can update the config and things keep working
   408  func TestVaultClient_SetConfig(t *testing.T) {
   409  	t.Parallel()
   410  	v := testutil.NewTestVault(t)
   411  	defer v.Stop()
   412  
   413  	v2 := testutil.NewTestVault(t)
   414  	defer v2.Stop()
   415  
   416  	// Set the configs token in a new test role
   417  	v2.Config.Token = defaultTestVaultWhitelistRoleAndToken(v2, t, 20)
   418  
   419  	logger := log.New(os.Stderr, "", log.LstdFlags)
   420  	client, err := NewVaultClient(v.Config, logger, nil)
   421  	if err != nil {
   422  		t.Fatalf("failed to build vault client: %v", err)
   423  	}
   424  	defer client.Stop()
   425  
   426  	waitForConnection(client, t)
   427  
   428  	if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
   429  		t.Fatalf("unexpected token: %v", client.tokenData)
   430  	}
   431  
   432  	// Update the config
   433  	if err := client.SetConfig(v2.Config); err != nil {
   434  		t.Fatalf("SetConfig failed: %v", err)
   435  	}
   436  
   437  	waitForConnection(client, t)
   438  
   439  	if client.tokenData == nil || len(client.tokenData.Policies) != 3 {
   440  		t.Fatalf("unexpected token: %v", client.tokenData)
   441  	}
   442  }
   443  
   444  // Test that we can disable vault
   445  func TestVaultClient_SetConfig_Disable(t *testing.T) {
   446  	t.Parallel()
   447  	v := testutil.NewTestVault(t)
   448  	defer v.Stop()
   449  
   450  	logger := log.New(os.Stderr, "", log.LstdFlags)
   451  	client, err := NewVaultClient(v.Config, logger, nil)
   452  	if err != nil {
   453  		t.Fatalf("failed to build vault client: %v", err)
   454  	}
   455  	defer client.Stop()
   456  
   457  	waitForConnection(client, t)
   458  
   459  	if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
   460  		t.Fatalf("unexpected token: %v", client.tokenData)
   461  	}
   462  
   463  	// Disable vault
   464  	f := false
   465  	config := config.VaultConfig{
   466  		Enabled: &f,
   467  	}
   468  
   469  	// Update the config
   470  	if err := client.SetConfig(&config); err != nil {
   471  		t.Fatalf("SetConfig failed: %v", err)
   472  	}
   473  
   474  	if client.Enabled() || client.Running() {
   475  		t.Fatalf("SetConfig should have stopped client")
   476  	}
   477  }
   478  
   479  func TestVaultClient_RenewalLoop(t *testing.T) {
   480  	t.Parallel()
   481  	v := testutil.NewTestVault(t)
   482  	defer v.Stop()
   483  
   484  	// Set the configs token in a new test role
   485  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   486  
   487  	// Start the client
   488  	logger := log.New(os.Stderr, "", log.LstdFlags)
   489  	client, err := NewVaultClient(v.Config, logger, nil)
   490  	if err != nil {
   491  		t.Fatalf("failed to build vault client: %v", err)
   492  	}
   493  	defer client.Stop()
   494  
   495  	// Sleep 8 seconds and ensure we have a non-zero TTL
   496  	time.Sleep(8 * time.Second)
   497  
   498  	// Get the current TTL
   499  	a := v.Client.Auth().Token()
   500  	s2, err := a.Lookup(v.Config.Token)
   501  	if err != nil {
   502  		t.Fatalf("failed to lookup token: %v", err)
   503  	}
   504  
   505  	ttl := parseTTLFromLookup(s2, t)
   506  	if ttl == 0 {
   507  		t.Fatalf("token renewal failed; ttl %v", ttl)
   508  	}
   509  }
   510  
   511  func parseTTLFromLookup(s *vapi.Secret, t *testing.T) int64 {
   512  	if s == nil {
   513  		t.Fatalf("nil secret")
   514  	} else if s.Data == nil {
   515  		t.Fatalf("nil data block in secret")
   516  	}
   517  
   518  	ttlRaw, ok := s.Data["ttl"]
   519  	if !ok {
   520  		t.Fatalf("no ttl")
   521  	}
   522  
   523  	ttlNumber, ok := ttlRaw.(json.Number)
   524  	if !ok {
   525  		t.Fatalf("failed to convert ttl %q to json Number", ttlRaw)
   526  	}
   527  
   528  	ttl, err := ttlNumber.Int64()
   529  	if err != nil {
   530  		t.Fatalf("Failed to get ttl from json.Number: %v", err)
   531  	}
   532  
   533  	return ttl
   534  }
   535  
   536  func TestVaultClient_LookupToken_Invalid(t *testing.T) {
   537  	t.Parallel()
   538  	tr := true
   539  	conf := &config.VaultConfig{
   540  		Enabled: &tr,
   541  		Addr:    "http://foobar:12345",
   542  		Token:   structs.GenerateUUID(),
   543  	}
   544  
   545  	// Enable vault but use a bad address so it never establishes a conn
   546  	logger := log.New(os.Stderr, "", log.LstdFlags)
   547  	client, err := NewVaultClient(conf, logger, nil)
   548  	if err != nil {
   549  		t.Fatalf("failed to build vault client: %v", err)
   550  	}
   551  	client.SetActive(true)
   552  	defer client.Stop()
   553  
   554  	_, err = client.LookupToken(context.Background(), "foo")
   555  	if err == nil || !strings.Contains(err.Error(), "established") {
   556  		t.Fatalf("Expected error because connection to Vault hasn't been made: %v", err)
   557  	}
   558  }
   559  
   560  func TestVaultClient_LookupToken_Root(t *testing.T) {
   561  	t.Parallel()
   562  	v := testutil.NewTestVault(t)
   563  	defer v.Stop()
   564  
   565  	logger := log.New(os.Stderr, "", log.LstdFlags)
   566  	client, err := NewVaultClient(v.Config, logger, nil)
   567  	if err != nil {
   568  		t.Fatalf("failed to build vault client: %v", err)
   569  	}
   570  	client.SetActive(true)
   571  	defer client.Stop()
   572  
   573  	waitForConnection(client, t)
   574  
   575  	// Lookup ourselves
   576  	s, err := client.LookupToken(context.Background(), v.Config.Token)
   577  	if err != nil {
   578  		t.Fatalf("self lookup failed: %v", err)
   579  	}
   580  
   581  	policies, err := PoliciesFrom(s)
   582  	if err != nil {
   583  		t.Fatalf("failed to parse policies: %v", err)
   584  	}
   585  
   586  	expected := []string{"root"}
   587  	if !reflect.DeepEqual(policies, expected) {
   588  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   589  	}
   590  
   591  	// Create a token with a different set of policies
   592  	expected = []string{"default"}
   593  	req := vapi.TokenCreateRequest{
   594  		Policies: expected,
   595  	}
   596  	s, err = v.Client.Auth().Token().Create(&req)
   597  	if err != nil {
   598  		t.Fatalf("failed to create child token: %v", err)
   599  	}
   600  
   601  	// Get the client token
   602  	if s == nil || s.Auth == nil {
   603  		t.Fatalf("bad secret response: %+v", s)
   604  	}
   605  
   606  	// Lookup new child
   607  	s, err = client.LookupToken(context.Background(), s.Auth.ClientToken)
   608  	if err != nil {
   609  		t.Fatalf("self lookup failed: %v", err)
   610  	}
   611  
   612  	policies, err = PoliciesFrom(s)
   613  	if err != nil {
   614  		t.Fatalf("failed to parse policies: %v", err)
   615  	}
   616  
   617  	if !reflect.DeepEqual(policies, expected) {
   618  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   619  	}
   620  }
   621  
   622  func TestVaultClient_LookupToken_Role(t *testing.T) {
   623  	t.Parallel()
   624  	v := testutil.NewTestVault(t)
   625  	defer v.Stop()
   626  
   627  	// Set the configs token in a new test role
   628  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   629  
   630  	logger := log.New(os.Stderr, "", log.LstdFlags)
   631  	client, err := NewVaultClient(v.Config, logger, nil)
   632  	if err != nil {
   633  		t.Fatalf("failed to build vault client: %v", err)
   634  	}
   635  	client.SetActive(true)
   636  	defer client.Stop()
   637  
   638  	waitForConnection(client, t)
   639  
   640  	// Lookup ourselves
   641  	s, err := client.LookupToken(context.Background(), v.Config.Token)
   642  	if err != nil {
   643  		t.Fatalf("self lookup failed: %v", err)
   644  	}
   645  
   646  	policies, err := PoliciesFrom(s)
   647  	if err != nil {
   648  		t.Fatalf("failed to parse policies: %v", err)
   649  	}
   650  
   651  	expected := []string{"default", "nomad-role-create", "nomad-role-management"}
   652  	if !reflect.DeepEqual(policies, expected) {
   653  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   654  	}
   655  
   656  	// Create a token with a different set of policies
   657  	expected = []string{"default"}
   658  	req := vapi.TokenCreateRequest{
   659  		Policies: expected,
   660  	}
   661  	s, err = v.Client.Auth().Token().Create(&req)
   662  	if err != nil {
   663  		t.Fatalf("failed to create child token: %v", err)
   664  	}
   665  
   666  	// Get the client token
   667  	if s == nil || s.Auth == nil {
   668  		t.Fatalf("bad secret response: %+v", s)
   669  	}
   670  
   671  	// Lookup new child
   672  	s, err = client.LookupToken(context.Background(), s.Auth.ClientToken)
   673  	if err != nil {
   674  		t.Fatalf("self lookup failed: %v", err)
   675  	}
   676  
   677  	policies, err = PoliciesFrom(s)
   678  	if err != nil {
   679  		t.Fatalf("failed to parse policies: %v", err)
   680  	}
   681  
   682  	if !reflect.DeepEqual(policies, expected) {
   683  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   684  	}
   685  }
   686  
   687  func TestVaultClient_LookupToken_RateLimit(t *testing.T) {
   688  	t.Parallel()
   689  	v := testutil.NewTestVault(t)
   690  	defer v.Stop()
   691  
   692  	logger := log.New(os.Stderr, "", log.LstdFlags)
   693  	client, err := NewVaultClient(v.Config, logger, nil)
   694  	if err != nil {
   695  		t.Fatalf("failed to build vault client: %v", err)
   696  	}
   697  	client.SetActive(true)
   698  	defer client.Stop()
   699  	client.setLimit(rate.Limit(1.0))
   700  
   701  	waitForConnection(client, t)
   702  
   703  	// Spin up many requests. These should block
   704  	ctx, cancel := context.WithCancel(context.Background())
   705  
   706  	cancels := 0
   707  	numRequests := 10
   708  	unblock := make(chan struct{})
   709  	for i := 0; i < numRequests; i++ {
   710  		go func() {
   711  			// Lookup ourselves
   712  			_, err := client.LookupToken(ctx, v.Config.Token)
   713  			if err != nil {
   714  				if err == context.Canceled {
   715  					cancels += 1
   716  					return
   717  				}
   718  				t.Fatalf("self lookup failed: %v", err)
   719  				return
   720  			}
   721  
   722  			// Cancel the context
   723  			close(unblock)
   724  		}()
   725  	}
   726  
   727  	select {
   728  	case <-time.After(5 * time.Second):
   729  		t.Fatalf("timeout")
   730  	case <-unblock:
   731  		cancel()
   732  	}
   733  
   734  	desired := numRequests - 1
   735  	testutil.WaitForResult(func() (bool, error) {
   736  		if cancels != desired {
   737  			return false, fmt.Errorf("Incorrect number of cancels; got %d; want %d", cancels, desired)
   738  		}
   739  
   740  		return true, nil
   741  	}, func(err error) {
   742  		t.Fatalf("Connection not established")
   743  	})
   744  }
   745  
   746  func TestVaultClient_CreateToken_Root(t *testing.T) {
   747  	t.Parallel()
   748  	v := testutil.NewTestVault(t)
   749  	defer v.Stop()
   750  
   751  	logger := log.New(os.Stderr, "", log.LstdFlags)
   752  	client, err := NewVaultClient(v.Config, logger, nil)
   753  	if err != nil {
   754  		t.Fatalf("failed to build vault client: %v", err)
   755  	}
   756  	client.SetActive(true)
   757  	defer client.Stop()
   758  
   759  	waitForConnection(client, t)
   760  
   761  	// Create an allocation that requires a Vault policy
   762  	a := mock.Alloc()
   763  	task := a.Job.TaskGroups[0].Tasks[0]
   764  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   765  
   766  	s, err := client.CreateToken(context.Background(), a, task.Name)
   767  	if err != nil {
   768  		t.Fatalf("CreateToken failed: %v", err)
   769  	}
   770  
   771  	// Ensure that created secret is a wrapped token
   772  	if s == nil || s.WrapInfo == nil {
   773  		t.Fatalf("Bad secret: %#v", s)
   774  	}
   775  
   776  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   777  	if err != nil {
   778  		t.Fatalf("bad: %v", err)
   779  	}
   780  
   781  	if s.WrapInfo.WrappedAccessor == "" {
   782  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   783  	} else if s.WrapInfo.Token == "" {
   784  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   785  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   786  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   787  	}
   788  }
   789  
   790  func TestVaultClient_CreateToken_Whitelist_Role(t *testing.T) {
   791  	t.Parallel()
   792  	v := testutil.NewTestVault(t)
   793  	defer v.Stop()
   794  
   795  	// Set the configs token in a new test role
   796  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   797  
   798  	// Start the client
   799  	logger := log.New(os.Stderr, "", log.LstdFlags)
   800  	client, err := NewVaultClient(v.Config, logger, nil)
   801  	if err != nil {
   802  		t.Fatalf("failed to build vault client: %v", err)
   803  	}
   804  	client.SetActive(true)
   805  	defer client.Stop()
   806  
   807  	waitForConnection(client, t)
   808  
   809  	// Create an allocation that requires a Vault policy
   810  	a := mock.Alloc()
   811  	task := a.Job.TaskGroups[0].Tasks[0]
   812  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   813  
   814  	s, err := client.CreateToken(context.Background(), a, task.Name)
   815  	if err != nil {
   816  		t.Fatalf("CreateToken failed: %v", err)
   817  	}
   818  
   819  	// Ensure that created secret is a wrapped token
   820  	if s == nil || s.WrapInfo == nil {
   821  		t.Fatalf("Bad secret: %#v", s)
   822  	}
   823  
   824  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   825  	if err != nil {
   826  		t.Fatalf("bad: %v", err)
   827  	}
   828  
   829  	if s.WrapInfo.WrappedAccessor == "" {
   830  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   831  	} else if s.WrapInfo.Token == "" {
   832  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   833  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   834  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   835  	}
   836  }
   837  
   838  func TestVaultClient_CreateToken_Root_Target_Role(t *testing.T) {
   839  	t.Parallel()
   840  	v := testutil.NewTestVault(t)
   841  	defer v.Stop()
   842  
   843  	// Create the test role
   844  	defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   845  
   846  	// Target the test role
   847  	v.Config.Role = "test"
   848  
   849  	// Start the client
   850  	logger := log.New(os.Stderr, "", log.LstdFlags)
   851  	client, err := NewVaultClient(v.Config, logger, nil)
   852  	if err != nil {
   853  		t.Fatalf("failed to build vault client: %v", err)
   854  	}
   855  	client.SetActive(true)
   856  	defer client.Stop()
   857  
   858  	waitForConnection(client, t)
   859  
   860  	// Create an allocation that requires a Vault policy
   861  	a := mock.Alloc()
   862  	task := a.Job.TaskGroups[0].Tasks[0]
   863  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   864  
   865  	s, err := client.CreateToken(context.Background(), a, task.Name)
   866  	if err != nil {
   867  		t.Fatalf("CreateToken failed: %v", err)
   868  	}
   869  
   870  	// Ensure that created secret is a wrapped token
   871  	if s == nil || s.WrapInfo == nil {
   872  		t.Fatalf("Bad secret: %#v", s)
   873  	}
   874  
   875  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   876  	if err != nil {
   877  		t.Fatalf("bad: %v", err)
   878  	}
   879  
   880  	if s.WrapInfo.WrappedAccessor == "" {
   881  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   882  	} else if s.WrapInfo.Token == "" {
   883  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   884  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   885  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   886  	}
   887  }
   888  
   889  func TestVaultClient_CreateToken_Blacklist_Role(t *testing.T) {
   890  	t.Parallel()
   891  	// Need to skip if test is 0.6.4
   892  	version, err := testutil.VaultVersion()
   893  	if err != nil {
   894  		t.Fatalf("failed to determine version: %v", err)
   895  	}
   896  
   897  	if strings.Contains(version, "v0.6.4") {
   898  		t.Skipf("Vault has a regression in v0.6.4 that this test hits")
   899  	}
   900  
   901  	v := testutil.NewTestVault(t)
   902  	defer v.Stop()
   903  
   904  	// Set the configs token in a new test role
   905  	v.Config.Token = defaultTestVaultBlacklistRoleAndToken(v, t, 5)
   906  	v.Config.Role = "test"
   907  
   908  	// Start the client
   909  	logger := log.New(os.Stderr, "", log.LstdFlags)
   910  	client, err := NewVaultClient(v.Config, logger, nil)
   911  	if err != nil {
   912  		t.Fatalf("failed to build vault client: %v", err)
   913  	}
   914  	client.SetActive(true)
   915  	defer client.Stop()
   916  
   917  	waitForConnection(client, t)
   918  
   919  	// Create an allocation that requires a Vault policy
   920  	a := mock.Alloc()
   921  	task := a.Job.TaskGroups[0].Tasks[0]
   922  	task.Vault = &structs.Vault{Policies: []string{"secrets"}}
   923  
   924  	s, err := client.CreateToken(context.Background(), a, task.Name)
   925  	if err != nil {
   926  		t.Fatalf("CreateToken failed: %v", err)
   927  	}
   928  
   929  	// Ensure that created secret is a wrapped token
   930  	if s == nil || s.WrapInfo == nil {
   931  		t.Fatalf("Bad secret: %#v", s)
   932  	}
   933  
   934  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   935  	if err != nil {
   936  		t.Fatalf("bad: %v", err)
   937  	}
   938  
   939  	if s.WrapInfo.WrappedAccessor == "" {
   940  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   941  	} else if s.WrapInfo.Token == "" {
   942  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   943  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   944  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   945  	}
   946  }
   947  
   948  func TestVaultClient_CreateToken_Role_InvalidToken(t *testing.T) {
   949  	t.Parallel()
   950  	v := testutil.NewTestVault(t)
   951  	defer v.Stop()
   952  
   953  	// Set the configs token in a new test role
   954  	defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   955  	v.Config.Token = "foo-bar"
   956  
   957  	// Start the client
   958  	logger := log.New(os.Stderr, "", log.LstdFlags)
   959  	client, err := NewVaultClient(v.Config, logger, nil)
   960  	if err != nil {
   961  		t.Fatalf("failed to build vault client: %v", err)
   962  	}
   963  	client.SetActive(true)
   964  	defer client.Stop()
   965  
   966  	testutil.WaitForResult(func() (bool, error) {
   967  		established, err := client.ConnectionEstablished()
   968  		if established {
   969  			return false, fmt.Errorf("Shouldn't establish")
   970  		}
   971  
   972  		return err != nil, nil
   973  	}, func(err error) {
   974  		t.Fatalf("Connection not established")
   975  	})
   976  
   977  	// Create an allocation that requires a Vault policy
   978  	a := mock.Alloc()
   979  	task := a.Job.TaskGroups[0].Tasks[0]
   980  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   981  
   982  	_, err = client.CreateToken(context.Background(), a, task.Name)
   983  	if err == nil || !strings.Contains(err.Error(), "Connection to Vault failed") {
   984  		t.Fatalf("CreateToken should have failed: %v", err)
   985  	}
   986  }
   987  
   988  func TestVaultClient_CreateToken_Role_Unrecoverable(t *testing.T) {
   989  	t.Parallel()
   990  	v := testutil.NewTestVault(t)
   991  	defer v.Stop()
   992  
   993  	// Set the configs token in a new test role
   994  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   995  
   996  	// Start the client
   997  	logger := log.New(os.Stderr, "", log.LstdFlags)
   998  	client, err := NewVaultClient(v.Config, logger, nil)
   999  	if err != nil {
  1000  		t.Fatalf("failed to build vault client: %v", err)
  1001  	}
  1002  	client.SetActive(true)
  1003  	defer client.Stop()
  1004  
  1005  	waitForConnection(client, t)
  1006  
  1007  	// Create an allocation that requires a Vault policy
  1008  	a := mock.Alloc()
  1009  	task := a.Job.TaskGroups[0].Tasks[0]
  1010  	task.Vault = &structs.Vault{Policies: []string{"unknown_policy"}}
  1011  
  1012  	_, err = client.CreateToken(context.Background(), a, task.Name)
  1013  	if err == nil {
  1014  		t.Fatalf("CreateToken should have failed: %v", err)
  1015  	}
  1016  
  1017  	_, ok := err.(structs.Recoverable)
  1018  	if ok {
  1019  		t.Fatalf("CreateToken should not be a recoverable error type: %v (%T)", err, err)
  1020  	}
  1021  }
  1022  
  1023  func TestVaultClient_CreateToken_Prestart(t *testing.T) {
  1024  	t.Parallel()
  1025  	vconfig := &config.VaultConfig{
  1026  		Enabled: helper.BoolToPtr(true),
  1027  		Token:   structs.GenerateUUID(),
  1028  		Addr:    "http://127.0.0.1:0",
  1029  	}
  1030  
  1031  	logger := log.New(os.Stderr, "", log.LstdFlags)
  1032  	client, err := NewVaultClient(vconfig, logger, nil)
  1033  	if err != nil {
  1034  		t.Fatalf("failed to build vault client: %v", err)
  1035  	}
  1036  	client.SetActive(true)
  1037  	defer client.Stop()
  1038  
  1039  	// Create an allocation that requires a Vault policy
  1040  	a := mock.Alloc()
  1041  	task := a.Job.TaskGroups[0].Tasks[0]
  1042  	task.Vault = &structs.Vault{Policies: []string{"default"}}
  1043  
  1044  	_, err = client.CreateToken(context.Background(), a, task.Name)
  1045  	if err == nil {
  1046  		t.Fatalf("CreateToken should have failed: %v", err)
  1047  	}
  1048  
  1049  	if rerr, ok := err.(*structs.RecoverableError); !ok {
  1050  		t.Fatalf("Err should have been type recoverable error")
  1051  	} else if ok && !rerr.IsRecoverable() {
  1052  		t.Fatalf("Err should have been recoverable")
  1053  	}
  1054  }
  1055  
  1056  func TestVaultClient_RevokeTokens_PreEstablishs(t *testing.T) {
  1057  	t.Parallel()
  1058  	vconfig := &config.VaultConfig{
  1059  		Enabled: helper.BoolToPtr(true),
  1060  		Token:   structs.GenerateUUID(),
  1061  		Addr:    "http://127.0.0.1:0",
  1062  	}
  1063  	logger := log.New(os.Stderr, "", log.LstdFlags)
  1064  	client, err := NewVaultClient(vconfig, logger, nil)
  1065  	if err != nil {
  1066  		t.Fatalf("failed to build vault client: %v", err)
  1067  	}
  1068  	client.SetActive(true)
  1069  	defer client.Stop()
  1070  
  1071  	// Create some VaultAccessors
  1072  	vas := []*structs.VaultAccessor{
  1073  		mock.VaultAccessor(),
  1074  		mock.VaultAccessor(),
  1075  	}
  1076  
  1077  	if err := client.RevokeTokens(context.Background(), vas, false); err != nil {
  1078  		t.Fatalf("RevokeTokens failed: %v", err)
  1079  	}
  1080  
  1081  	// Wasn't committed
  1082  	if len(client.revoking) != 0 {
  1083  		t.Fatalf("didn't add to revoke loop")
  1084  	}
  1085  
  1086  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1087  		t.Fatalf("RevokeTokens failed: %v", err)
  1088  	}
  1089  
  1090  	// Was committed
  1091  	if len(client.revoking) != 2 {
  1092  		t.Fatalf("didn't add to revoke loop")
  1093  	}
  1094  
  1095  	if client.Stats().TrackedForRevoke != 2 {
  1096  		t.Fatalf("didn't add to revoke loop")
  1097  	}
  1098  }
  1099  
  1100  func TestVaultClient_RevokeTokens_Root(t *testing.T) {
  1101  	t.Parallel()
  1102  	v := testutil.NewTestVault(t)
  1103  	defer v.Stop()
  1104  
  1105  	purged := 0
  1106  	purge := func(accessors []*structs.VaultAccessor) error {
  1107  		purged += len(accessors)
  1108  		return nil
  1109  	}
  1110  
  1111  	logger := log.New(os.Stderr, "", log.LstdFlags)
  1112  	client, err := NewVaultClient(v.Config, logger, purge)
  1113  	if err != nil {
  1114  		t.Fatalf("failed to build vault client: %v", err)
  1115  	}
  1116  	client.SetActive(true)
  1117  	defer client.Stop()
  1118  
  1119  	waitForConnection(client, t)
  1120  
  1121  	// Create some vault tokens
  1122  	auth := v.Client.Auth().Token()
  1123  	req := vapi.TokenCreateRequest{
  1124  		Policies: []string{"default"},
  1125  	}
  1126  	t1, err := auth.Create(&req)
  1127  	if err != nil {
  1128  		t.Fatalf("Failed to create vault token: %v", err)
  1129  	}
  1130  	if t1 == nil || t1.Auth == nil {
  1131  		t.Fatalf("bad secret response: %+v", t1)
  1132  	}
  1133  	t2, err := auth.Create(&req)
  1134  	if err != nil {
  1135  		t.Fatalf("Failed to create vault token: %v", err)
  1136  	}
  1137  	if t2 == nil || t2.Auth == nil {
  1138  		t.Fatalf("bad secret response: %+v", t2)
  1139  	}
  1140  
  1141  	// Create two VaultAccessors
  1142  	vas := []*structs.VaultAccessor{
  1143  		&structs.VaultAccessor{Accessor: t1.Auth.Accessor},
  1144  		&structs.VaultAccessor{Accessor: t2.Auth.Accessor},
  1145  	}
  1146  
  1147  	// Issue a token revocation
  1148  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1149  		t.Fatalf("RevokeTokens failed: %v", err)
  1150  	}
  1151  
  1152  	// Lookup the token and make sure we get an error
  1153  	if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
  1154  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1155  	}
  1156  	if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
  1157  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1158  	}
  1159  
  1160  	if purged != 2 {
  1161  		t.Fatalf("Expected purged 2; got %d", purged)
  1162  	}
  1163  }
  1164  
  1165  func TestVaultClient_RevokeTokens_Role(t *testing.T) {
  1166  	t.Parallel()
  1167  	v := testutil.NewTestVault(t)
  1168  	defer v.Stop()
  1169  
  1170  	// Set the configs token in a new test role
  1171  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
  1172  
  1173  	purged := 0
  1174  	purge := func(accessors []*structs.VaultAccessor) error {
  1175  		purged += len(accessors)
  1176  		return nil
  1177  	}
  1178  
  1179  	logger := log.New(os.Stderr, "", log.LstdFlags)
  1180  	client, err := NewVaultClient(v.Config, logger, purge)
  1181  	if err != nil {
  1182  		t.Fatalf("failed to build vault client: %v", err)
  1183  	}
  1184  	client.SetActive(true)
  1185  	defer client.Stop()
  1186  
  1187  	waitForConnection(client, t)
  1188  
  1189  	// Create some vault tokens
  1190  	auth := v.Client.Auth().Token()
  1191  	req := vapi.TokenCreateRequest{
  1192  		Policies: []string{"default"},
  1193  	}
  1194  	t1, err := auth.Create(&req)
  1195  	if err != nil {
  1196  		t.Fatalf("Failed to create vault token: %v", err)
  1197  	}
  1198  	if t1 == nil || t1.Auth == nil {
  1199  		t.Fatalf("bad secret response: %+v", t1)
  1200  	}
  1201  	t2, err := auth.Create(&req)
  1202  	if err != nil {
  1203  		t.Fatalf("Failed to create vault token: %v", err)
  1204  	}
  1205  	if t2 == nil || t2.Auth == nil {
  1206  		t.Fatalf("bad secret response: %+v", t2)
  1207  	}
  1208  
  1209  	// Create two VaultAccessors
  1210  	vas := []*structs.VaultAccessor{
  1211  		&structs.VaultAccessor{Accessor: t1.Auth.Accessor},
  1212  		&structs.VaultAccessor{Accessor: t2.Auth.Accessor},
  1213  	}
  1214  
  1215  	// Issue a token revocation
  1216  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1217  		t.Fatalf("RevokeTokens failed: %v", err)
  1218  	}
  1219  
  1220  	// Lookup the token and make sure we get an error
  1221  	if purged != 2 {
  1222  		t.Fatalf("Expected purged 2; got %d", purged)
  1223  	}
  1224  	if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
  1225  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1226  	}
  1227  	if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
  1228  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1229  	}
  1230  }
  1231  
  1232  func waitForConnection(v *vaultClient, t *testing.T) {
  1233  	testutil.WaitForResult(func() (bool, error) {
  1234  		return v.ConnectionEstablished()
  1235  	}, func(err error) {
  1236  		t.Fatalf("Connection not established")
  1237  	})
  1238  }