github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/nomad/vault_test.go (about)

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