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