github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/vault_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math/rand"
     8  	"reflect"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"golang.org/x/time/rate"
    14  
    15  	"github.com/hashicorp/nomad/helper"
    16  	"github.com/hashicorp/nomad/helper/testlog"
    17  	"github.com/hashicorp/nomad/helper/uuid"
    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 := testlog.Logger(t)
   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 separately.
   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 := testlog.Logger(t)
   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 := testlog.Logger(t)
   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 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, "explicit max ttl") {
   277  		t.Fatalf("Expect explicit max ttl error")
   278  	}
   279  }
   280  
   281  func TestVaultClient_ValidateRole_NonExistant(t *testing.T) {
   282  	t.Parallel()
   283  	v := testutil.NewTestVault(t)
   284  	defer v.Stop()
   285  
   286  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   287  	v.Config.Token = v.RootToken
   288  	logger := testlog.Logger(t)
   289  	v.Config.ConnectionRetryIntv = 100 * time.Millisecond
   290  	v.Config.Role = "test-nonexistent"
   291  	client, err := NewVaultClient(v.Config, logger, nil)
   292  	if err != nil {
   293  		t.Fatalf("failed to build vault client: %v", err)
   294  	}
   295  	defer client.Stop()
   296  
   297  	// Wait for an error
   298  	var conn bool
   299  	var connErr error
   300  	testutil.WaitForResult(func() (bool, error) {
   301  		conn, connErr = client.ConnectionEstablished()
   302  		if !conn {
   303  			return false, fmt.Errorf("Should connect")
   304  		}
   305  
   306  		if connErr == nil {
   307  			return false, fmt.Errorf("expect an error")
   308  		}
   309  
   310  		return true, nil
   311  	}, func(err error) {
   312  		t.Fatalf("bad: %v", err)
   313  	})
   314  
   315  	errStr := connErr.Error()
   316  	if !strings.Contains(errStr, "does not exist") {
   317  		t.Fatalf("Expect does not exist error")
   318  	}
   319  }
   320  
   321  func TestVaultClient_ValidateToken(t *testing.T) {
   322  	t.Parallel()
   323  	v := testutil.NewTestVault(t)
   324  	defer v.Stop()
   325  
   326  	// Set the configs token in a new test role
   327  	vaultPolicies := map[string]string{
   328  		"nomad-role-create": nomadRoleCreatePolicy,
   329  		"token-lookup":      tokenLookupPolicy,
   330  	}
   331  	data := map[string]interface{}{
   332  		"allowed_policies": "token-lookup,nomad-role-create",
   333  		"period":           10,
   334  	}
   335  	v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, []string{"token-lookup", "nomad-role-create"})
   336  
   337  	logger := testlog.Logger(t)
   338  	v.Config.ConnectionRetryIntv = 100 * time.Millisecond
   339  	client, err := NewVaultClient(v.Config, logger, nil)
   340  	if err != nil {
   341  		t.Fatalf("failed to build vault client: %v", err)
   342  	}
   343  	defer client.Stop()
   344  
   345  	// Wait for an error
   346  	var conn bool
   347  	var connErr error
   348  	testutil.WaitForResult(func() (bool, error) {
   349  		conn, connErr = client.ConnectionEstablished()
   350  		if !conn {
   351  			return false, fmt.Errorf("Should connect")
   352  		}
   353  
   354  		if connErr == nil {
   355  			return false, fmt.Errorf("expect an error")
   356  		}
   357  
   358  		return true, nil
   359  	}, func(err error) {
   360  		t.Fatalf("bad: %v", err)
   361  	})
   362  
   363  	errStr := connErr.Error()
   364  	if !strings.Contains(errStr, vaultTokenRevokePath) {
   365  		t.Fatalf("Expect revoke error")
   366  	}
   367  	if !strings.Contains(errStr, fmt.Sprintf(vaultRoleLookupPath, "test")) {
   368  		t.Fatalf("Expect explicit max ttl error")
   369  	}
   370  	if !strings.Contains(errStr, "token must have one of the following") {
   371  		t.Fatalf("Expect explicit max ttl error")
   372  	}
   373  }
   374  
   375  func TestVaultClient_SetActive(t *testing.T) {
   376  	t.Parallel()
   377  	v := testutil.NewTestVault(t)
   378  	defer v.Stop()
   379  
   380  	logger := testlog.Logger(t)
   381  	client, err := NewVaultClient(v.Config, logger, nil)
   382  	if err != nil {
   383  		t.Fatalf("failed to build vault client: %v", err)
   384  	}
   385  	defer client.Stop()
   386  
   387  	waitForConnection(client, t)
   388  
   389  	// Do a lookup and expect an error about not being active
   390  	_, err = client.LookupToken(context.Background(), "123")
   391  	if err == nil || !strings.Contains(err.Error(), "not active") {
   392  		t.Fatalf("Expected not-active error: %v", err)
   393  	}
   394  
   395  	client.SetActive(true)
   396  
   397  	// Do a lookup of ourselves
   398  	_, err = client.LookupToken(context.Background(), v.RootToken)
   399  	if err != nil {
   400  		t.Fatalf("Unexpected error: %v", err)
   401  	}
   402  }
   403  
   404  // Test that we can update the config and things keep working
   405  func TestVaultClient_SetConfig(t *testing.T) {
   406  	t.Parallel()
   407  	v := testutil.NewTestVault(t)
   408  	defer v.Stop()
   409  
   410  	v2 := testutil.NewTestVault(t)
   411  	defer v2.Stop()
   412  
   413  	// Set the configs token in a new test role
   414  	v2.Config.Token = defaultTestVaultWhitelistRoleAndToken(v2, t, 20)
   415  
   416  	logger := testlog.Logger(t)
   417  	client, err := NewVaultClient(v.Config, logger, nil)
   418  	if err != nil {
   419  		t.Fatalf("failed to build vault client: %v", err)
   420  	}
   421  	defer client.Stop()
   422  
   423  	waitForConnection(client, t)
   424  
   425  	if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
   426  		t.Fatalf("unexpected token: %v", client.tokenData)
   427  	}
   428  
   429  	// Update the config
   430  	if err := client.SetConfig(v2.Config); err != nil {
   431  		t.Fatalf("SetConfig failed: %v", err)
   432  	}
   433  
   434  	waitForConnection(client, t)
   435  
   436  	if client.tokenData == nil || len(client.tokenData.Policies) != 3 {
   437  		t.Fatalf("unexpected token: %v", client.tokenData)
   438  	}
   439  
   440  	// Test that when SetConfig is called with the same configuration, it is a
   441  	// no-op
   442  	failCh := make(chan struct{}, 1)
   443  	go func() {
   444  		tomb := client.tomb
   445  		select {
   446  		case <-tomb.Dying():
   447  			close(failCh)
   448  		case <-time.After(1 * time.Second):
   449  			return
   450  		}
   451  	}()
   452  
   453  	// Update the config
   454  	if err := client.SetConfig(v2.Config); err != nil {
   455  		t.Fatalf("SetConfig failed: %v", err)
   456  	}
   457  
   458  	select {
   459  	case <-failCh:
   460  		t.Fatalf("Tomb shouldn't have exited")
   461  	case <-time.After(1 * time.Second):
   462  		return
   463  	}
   464  }
   465  
   466  // Test that we can disable vault
   467  func TestVaultClient_SetConfig_Disable(t *testing.T) {
   468  	t.Parallel()
   469  	v := testutil.NewTestVault(t)
   470  	defer v.Stop()
   471  
   472  	logger := testlog.Logger(t)
   473  	client, err := NewVaultClient(v.Config, logger, nil)
   474  	if err != nil {
   475  		t.Fatalf("failed to build vault client: %v", err)
   476  	}
   477  	defer client.Stop()
   478  
   479  	waitForConnection(client, t)
   480  
   481  	if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
   482  		t.Fatalf("unexpected token: %v", client.tokenData)
   483  	}
   484  
   485  	// Disable vault
   486  	f := false
   487  	config := config.VaultConfig{
   488  		Enabled: &f,
   489  	}
   490  
   491  	// Update the config
   492  	if err := client.SetConfig(&config); err != nil {
   493  		t.Fatalf("SetConfig failed: %v", err)
   494  	}
   495  
   496  	if client.Enabled() || client.Running() {
   497  		t.Fatalf("SetConfig should have stopped client")
   498  	}
   499  }
   500  
   501  func TestVaultClient_RenewalLoop(t *testing.T) {
   502  	t.Parallel()
   503  	v := testutil.NewTestVault(t)
   504  	defer v.Stop()
   505  
   506  	// Set the configs token in a new test role
   507  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   508  
   509  	// Start the client
   510  	logger := testlog.Logger(t)
   511  	client, err := NewVaultClient(v.Config, logger, nil)
   512  	if err != nil {
   513  		t.Fatalf("failed to build vault client: %v", err)
   514  	}
   515  	defer client.Stop()
   516  
   517  	// Sleep 8 seconds and ensure we have a non-zero TTL
   518  	time.Sleep(8 * time.Second)
   519  
   520  	// Get the current TTL
   521  	a := v.Client.Auth().Token()
   522  	s2, err := a.Lookup(v.Config.Token)
   523  	if err != nil {
   524  		t.Fatalf("failed to lookup token: %v", err)
   525  	}
   526  
   527  	ttl := parseTTLFromLookup(s2, t)
   528  	if ttl == 0 {
   529  		t.Fatalf("token renewal failed; ttl %v", ttl)
   530  	}
   531  }
   532  
   533  func parseTTLFromLookup(s *vapi.Secret, t *testing.T) int64 {
   534  	if s == nil {
   535  		t.Fatalf("nil secret")
   536  	} else if s.Data == nil {
   537  		t.Fatalf("nil data block in secret")
   538  	}
   539  
   540  	ttlRaw, ok := s.Data["ttl"]
   541  	if !ok {
   542  		t.Fatalf("no ttl")
   543  	}
   544  
   545  	ttlNumber, ok := ttlRaw.(json.Number)
   546  	if !ok {
   547  		t.Fatalf("failed to convert ttl %q to json Number", ttlRaw)
   548  	}
   549  
   550  	ttl, err := ttlNumber.Int64()
   551  	if err != nil {
   552  		t.Fatalf("Failed to get ttl from json.Number: %v", err)
   553  	}
   554  
   555  	return ttl
   556  }
   557  
   558  func TestVaultClient_LookupToken_Invalid(t *testing.T) {
   559  	t.Parallel()
   560  	tr := true
   561  	conf := &config.VaultConfig{
   562  		Enabled: &tr,
   563  		Addr:    "http://foobar:12345",
   564  		Token:   uuid.Generate(),
   565  	}
   566  
   567  	// Enable vault but use a bad address so it never establishes a conn
   568  	logger := testlog.Logger(t)
   569  	client, err := NewVaultClient(conf, logger, nil)
   570  	if err != nil {
   571  		t.Fatalf("failed to build vault client: %v", err)
   572  	}
   573  	client.SetActive(true)
   574  	defer client.Stop()
   575  
   576  	_, err = client.LookupToken(context.Background(), "foo")
   577  	if err == nil || !strings.Contains(err.Error(), "established") {
   578  		t.Fatalf("Expected error because connection to Vault hasn't been made: %v", err)
   579  	}
   580  }
   581  
   582  func TestVaultClient_LookupToken_Root(t *testing.T) {
   583  	t.Parallel()
   584  	v := testutil.NewTestVault(t)
   585  	defer v.Stop()
   586  
   587  	logger := testlog.Logger(t)
   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{"root"}
   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_Role(t *testing.T) {
   645  	t.Parallel()
   646  	v := testutil.NewTestVault(t)
   647  	defer v.Stop()
   648  
   649  	// Set the configs token in a new test role
   650  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   651  
   652  	logger := testlog.Logger(t)
   653  	client, err := NewVaultClient(v.Config, logger, nil)
   654  	if err != nil {
   655  		t.Fatalf("failed to build vault client: %v", err)
   656  	}
   657  	client.SetActive(true)
   658  	defer client.Stop()
   659  
   660  	waitForConnection(client, t)
   661  
   662  	// Lookup ourselves
   663  	s, err := client.LookupToken(context.Background(), v.Config.Token)
   664  	if err != nil {
   665  		t.Fatalf("self lookup failed: %v", err)
   666  	}
   667  
   668  	policies, err := PoliciesFrom(s)
   669  	if err != nil {
   670  		t.Fatalf("failed to parse policies: %v", err)
   671  	}
   672  
   673  	expected := []string{"default", "nomad-role-create", "nomad-role-management"}
   674  	if !reflect.DeepEqual(policies, expected) {
   675  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   676  	}
   677  
   678  	// Create a token with a different set of policies
   679  	expected = []string{"default"}
   680  	req := vapi.TokenCreateRequest{
   681  		Policies: expected,
   682  	}
   683  	s, err = v.Client.Auth().Token().Create(&req)
   684  	if err != nil {
   685  		t.Fatalf("failed to create child token: %v", err)
   686  	}
   687  
   688  	// Get the client token
   689  	if s == nil || s.Auth == nil {
   690  		t.Fatalf("bad secret response: %+v", s)
   691  	}
   692  
   693  	// Lookup new child
   694  	s, err = client.LookupToken(context.Background(), s.Auth.ClientToken)
   695  	if err != nil {
   696  		t.Fatalf("self lookup failed: %v", err)
   697  	}
   698  
   699  	policies, err = PoliciesFrom(s)
   700  	if err != nil {
   701  		t.Fatalf("failed to parse policies: %v", err)
   702  	}
   703  
   704  	if !reflect.DeepEqual(policies, expected) {
   705  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   706  	}
   707  }
   708  
   709  func TestVaultClient_LookupToken_RateLimit(t *testing.T) {
   710  	t.Parallel()
   711  	v := testutil.NewTestVault(t)
   712  	defer v.Stop()
   713  
   714  	logger := testlog.Logger(t)
   715  	client, err := NewVaultClient(v.Config, logger, nil)
   716  	if err != nil {
   717  		t.Fatalf("failed to build vault client: %v", err)
   718  	}
   719  	client.SetActive(true)
   720  	defer client.Stop()
   721  
   722  	waitForConnection(client, t)
   723  
   724  	client.setLimit(rate.Limit(1.0))
   725  
   726  	// Spin up many requests. These should block
   727  	ctx, cancel := context.WithCancel(context.Background())
   728  
   729  	cancels := 0
   730  	numRequests := 20
   731  	unblock := make(chan struct{})
   732  	for i := 0; i < numRequests; i++ {
   733  		go func() {
   734  			// Lookup ourselves
   735  			_, err := client.LookupToken(ctx, v.Config.Token)
   736  			if err != nil {
   737  				if err == context.Canceled {
   738  					cancels += 1
   739  					return
   740  				}
   741  				t.Fatalf("self lookup failed: %v", err)
   742  				return
   743  			}
   744  
   745  			// Cancel the context
   746  			close(unblock)
   747  		}()
   748  	}
   749  
   750  	select {
   751  	case <-time.After(5 * time.Second):
   752  		t.Fatalf("timeout")
   753  	case <-unblock:
   754  		cancel()
   755  	}
   756  
   757  	desired := numRequests - 1
   758  	testutil.WaitForResult(func() (bool, error) {
   759  		if desired-cancels > 2 {
   760  			return false, fmt.Errorf("Incorrect number of cancels; got %d; want %d", cancels, desired)
   761  		}
   762  
   763  		return true, nil
   764  	}, func(err error) {
   765  		t.Fatal(err)
   766  	})
   767  }
   768  
   769  func TestVaultClient_CreateToken_Root(t *testing.T) {
   770  	t.Parallel()
   771  	v := testutil.NewTestVault(t)
   772  	defer v.Stop()
   773  
   774  	logger := testlog.Logger(t)
   775  	client, err := NewVaultClient(v.Config, logger, nil)
   776  	if err != nil {
   777  		t.Fatalf("failed to build vault client: %v", err)
   778  	}
   779  	client.SetActive(true)
   780  	defer client.Stop()
   781  
   782  	waitForConnection(client, t)
   783  
   784  	// Create an allocation that requires a Vault policy
   785  	a := mock.Alloc()
   786  	task := a.Job.TaskGroups[0].Tasks[0]
   787  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   788  
   789  	s, err := client.CreateToken(context.Background(), a, task.Name)
   790  	if err != nil {
   791  		t.Fatalf("CreateToken failed: %v", err)
   792  	}
   793  
   794  	// Ensure that created secret is a wrapped token
   795  	if s == nil || s.WrapInfo == nil {
   796  		t.Fatalf("Bad secret: %#v", s)
   797  	}
   798  
   799  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   800  	if err != nil {
   801  		t.Fatalf("bad: %v", err)
   802  	}
   803  
   804  	if s.WrapInfo.WrappedAccessor == "" {
   805  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   806  	} else if s.WrapInfo.Token == "" {
   807  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   808  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   809  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   810  	}
   811  }
   812  
   813  func TestVaultClient_CreateToken_Whitelist_Role(t *testing.T) {
   814  	t.Parallel()
   815  	v := testutil.NewTestVault(t)
   816  	defer v.Stop()
   817  
   818  	// Set the configs token in a new test role
   819  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   820  
   821  	// Start the client
   822  	logger := testlog.Logger(t)
   823  	client, err := NewVaultClient(v.Config, logger, nil)
   824  	if err != nil {
   825  		t.Fatalf("failed to build vault client: %v", err)
   826  	}
   827  	client.SetActive(true)
   828  	defer client.Stop()
   829  
   830  	waitForConnection(client, t)
   831  
   832  	// Create an allocation that requires a Vault policy
   833  	a := mock.Alloc()
   834  	task := a.Job.TaskGroups[0].Tasks[0]
   835  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   836  
   837  	s, err := client.CreateToken(context.Background(), a, task.Name)
   838  	if err != nil {
   839  		t.Fatalf("CreateToken failed: %v", err)
   840  	}
   841  
   842  	// Ensure that created secret is a wrapped token
   843  	if s == nil || s.WrapInfo == nil {
   844  		t.Fatalf("Bad secret: %#v", s)
   845  	}
   846  
   847  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   848  	if err != nil {
   849  		t.Fatalf("bad: %v", err)
   850  	}
   851  
   852  	if s.WrapInfo.WrappedAccessor == "" {
   853  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   854  	} else if s.WrapInfo.Token == "" {
   855  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   856  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   857  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   858  	}
   859  }
   860  
   861  func TestVaultClient_CreateToken_Root_Target_Role(t *testing.T) {
   862  	t.Parallel()
   863  	v := testutil.NewTestVault(t)
   864  	defer v.Stop()
   865  
   866  	// Create the test role
   867  	defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   868  
   869  	// Target the test role
   870  	v.Config.Role = "test"
   871  
   872  	// Start the client
   873  	logger := testlog.Logger(t)
   874  	client, err := NewVaultClient(v.Config, logger, nil)
   875  	if err != nil {
   876  		t.Fatalf("failed to build vault client: %v", err)
   877  	}
   878  	client.SetActive(true)
   879  	defer client.Stop()
   880  
   881  	waitForConnection(client, t)
   882  
   883  	// Create an allocation that requires a Vault policy
   884  	a := mock.Alloc()
   885  	task := a.Job.TaskGroups[0].Tasks[0]
   886  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   887  
   888  	s, err := client.CreateToken(context.Background(), a, task.Name)
   889  	if err != nil {
   890  		t.Fatalf("CreateToken failed: %v", err)
   891  	}
   892  
   893  	// Ensure that created secret is a wrapped token
   894  	if s == nil || s.WrapInfo == nil {
   895  		t.Fatalf("Bad secret: %#v", s)
   896  	}
   897  
   898  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   899  	if err != nil {
   900  		t.Fatalf("bad: %v", err)
   901  	}
   902  
   903  	if s.WrapInfo.WrappedAccessor == "" {
   904  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   905  	} else if s.WrapInfo.Token == "" {
   906  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   907  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   908  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   909  	}
   910  }
   911  
   912  func TestVaultClient_CreateToken_Blacklist_Role(t *testing.T) {
   913  	t.Parallel()
   914  	// Need to skip if test is 0.6.4
   915  	version, err := testutil.VaultVersion()
   916  	if err != nil {
   917  		t.Fatalf("failed to determine version: %v", err)
   918  	}
   919  
   920  	if strings.Contains(version, "v0.6.4") {
   921  		t.Skipf("Vault has a regression in v0.6.4 that this test hits")
   922  	}
   923  
   924  	v := testutil.NewTestVault(t)
   925  	defer v.Stop()
   926  
   927  	// Set the configs token in a new test role
   928  	v.Config.Token = defaultTestVaultBlacklistRoleAndToken(v, t, 5)
   929  	v.Config.Role = "test"
   930  
   931  	// Start the client
   932  	logger := testlog.Logger(t)
   933  	client, err := NewVaultClient(v.Config, logger, nil)
   934  	if err != nil {
   935  		t.Fatalf("failed to build vault client: %v", err)
   936  	}
   937  	client.SetActive(true)
   938  	defer client.Stop()
   939  
   940  	waitForConnection(client, t)
   941  
   942  	// Create an allocation that requires a Vault policy
   943  	a := mock.Alloc()
   944  	task := a.Job.TaskGroups[0].Tasks[0]
   945  	task.Vault = &structs.Vault{Policies: []string{"secrets"}}
   946  
   947  	s, err := client.CreateToken(context.Background(), a, task.Name)
   948  	if err != nil {
   949  		t.Fatalf("CreateToken failed: %v", err)
   950  	}
   951  
   952  	// Ensure that created secret is a wrapped token
   953  	if s == nil || s.WrapInfo == nil {
   954  		t.Fatalf("Bad secret: %#v", s)
   955  	}
   956  
   957  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   958  	if err != nil {
   959  		t.Fatalf("bad: %v", err)
   960  	}
   961  
   962  	if s.WrapInfo.WrappedAccessor == "" {
   963  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   964  	} else if s.WrapInfo.Token == "" {
   965  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   966  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   967  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   968  	}
   969  }
   970  
   971  func TestVaultClient_CreateToken_Role_InvalidToken(t *testing.T) {
   972  	t.Parallel()
   973  	v := testutil.NewTestVault(t)
   974  	defer v.Stop()
   975  
   976  	// Set the configs token in a new test role
   977  	defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   978  	v.Config.Token = "foo-bar"
   979  
   980  	// Start the client
   981  	logger := testlog.Logger(t)
   982  	client, err := NewVaultClient(v.Config, logger, nil)
   983  	if err != nil {
   984  		t.Fatalf("failed to build vault client: %v", err)
   985  	}
   986  	client.SetActive(true)
   987  	defer client.Stop()
   988  
   989  	testutil.WaitForResult(func() (bool, error) {
   990  		established, err := client.ConnectionEstablished()
   991  		if !established {
   992  			return false, fmt.Errorf("Should establish")
   993  		}
   994  		return err != nil, nil
   995  	}, func(err error) {
   996  		t.Fatalf("Connection not established")
   997  	})
   998  
   999  	// Create an allocation that requires a Vault policy
  1000  	a := mock.Alloc()
  1001  	task := a.Job.TaskGroups[0].Tasks[0]
  1002  	task.Vault = &structs.Vault{Policies: []string{"default"}}
  1003  
  1004  	_, err = client.CreateToken(context.Background(), a, task.Name)
  1005  	if err == nil || !strings.Contains(err.Error(), "Nomad Server failed to establish connections to Vault") {
  1006  		t.Fatalf("CreateToken should have failed: %v", err)
  1007  	}
  1008  }
  1009  
  1010  func TestVaultClient_CreateToken_Role_Unrecoverable(t *testing.T) {
  1011  	t.Parallel()
  1012  	v := testutil.NewTestVault(t)
  1013  	defer v.Stop()
  1014  
  1015  	// Set the configs token in a new test role
  1016  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
  1017  
  1018  	// Start the client
  1019  	logger := testlog.Logger(t)
  1020  	client, err := NewVaultClient(v.Config, logger, nil)
  1021  	if err != nil {
  1022  		t.Fatalf("failed to build vault client: %v", err)
  1023  	}
  1024  	client.SetActive(true)
  1025  	defer client.Stop()
  1026  
  1027  	waitForConnection(client, t)
  1028  
  1029  	// Create an allocation that requires a Vault policy
  1030  	a := mock.Alloc()
  1031  	task := a.Job.TaskGroups[0].Tasks[0]
  1032  	task.Vault = &structs.Vault{Policies: []string{"unknown_policy"}}
  1033  
  1034  	_, err = client.CreateToken(context.Background(), a, task.Name)
  1035  	if err == nil {
  1036  		t.Fatalf("CreateToken should have failed: %v", err)
  1037  	}
  1038  
  1039  	_, ok := err.(structs.Recoverable)
  1040  	if ok {
  1041  		t.Fatalf("CreateToken should not be a recoverable error type: %v (%T)", err, err)
  1042  	}
  1043  }
  1044  
  1045  func TestVaultClient_CreateToken_Prestart(t *testing.T) {
  1046  	t.Parallel()
  1047  	vconfig := &config.VaultConfig{
  1048  		Enabled: helper.BoolToPtr(true),
  1049  		Token:   uuid.Generate(),
  1050  		Addr:    "http://127.0.0.1:0",
  1051  	}
  1052  
  1053  	logger := testlog.Logger(t)
  1054  	client, err := NewVaultClient(vconfig, logger, nil)
  1055  	if err != nil {
  1056  		t.Fatalf("failed to build vault client: %v", err)
  1057  	}
  1058  	client.SetActive(true)
  1059  	defer client.Stop()
  1060  
  1061  	// Create an allocation that requires a Vault policy
  1062  	a := mock.Alloc()
  1063  	task := a.Job.TaskGroups[0].Tasks[0]
  1064  	task.Vault = &structs.Vault{Policies: []string{"default"}}
  1065  
  1066  	_, err = client.CreateToken(context.Background(), a, task.Name)
  1067  	if err == nil {
  1068  		t.Fatalf("CreateToken should have failed: %v", err)
  1069  	}
  1070  
  1071  	if rerr, ok := err.(*structs.RecoverableError); !ok {
  1072  		t.Fatalf("Err should have been type recoverable error")
  1073  	} else if ok && !rerr.IsRecoverable() {
  1074  		t.Fatalf("Err should have been recoverable")
  1075  	}
  1076  }
  1077  
  1078  func TestVaultClient_RevokeTokens_PreEstablishs(t *testing.T) {
  1079  	t.Parallel()
  1080  	vconfig := &config.VaultConfig{
  1081  		Enabled: helper.BoolToPtr(true),
  1082  		Token:   uuid.Generate(),
  1083  		Addr:    "http://127.0.0.1:0",
  1084  	}
  1085  	logger := testlog.Logger(t)
  1086  	client, err := NewVaultClient(vconfig, logger, nil)
  1087  	if err != nil {
  1088  		t.Fatalf("failed to build vault client: %v", err)
  1089  	}
  1090  	client.SetActive(true)
  1091  	defer client.Stop()
  1092  
  1093  	// Create some VaultAccessors
  1094  	vas := []*structs.VaultAccessor{
  1095  		mock.VaultAccessor(),
  1096  		mock.VaultAccessor(),
  1097  	}
  1098  
  1099  	if err := client.RevokeTokens(context.Background(), vas, false); err != nil {
  1100  		t.Fatalf("RevokeTokens failed: %v", err)
  1101  	}
  1102  
  1103  	// Wasn't committed
  1104  	if len(client.revoking) != 0 {
  1105  		t.Fatalf("didn't add to revoke loop")
  1106  	}
  1107  
  1108  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1109  		t.Fatalf("RevokeTokens failed: %v", err)
  1110  	}
  1111  
  1112  	// Was committed
  1113  	if len(client.revoking) != 2 {
  1114  		t.Fatalf("didn't add to revoke loop")
  1115  	}
  1116  
  1117  	if client.Stats().TrackedForRevoke != 2 {
  1118  		t.Fatalf("didn't add to revoke loop")
  1119  	}
  1120  }
  1121  
  1122  func TestVaultClient_RevokeTokens_Root(t *testing.T) {
  1123  	t.Parallel()
  1124  	v := testutil.NewTestVault(t)
  1125  	defer v.Stop()
  1126  
  1127  	purged := 0
  1128  	purge := func(accessors []*structs.VaultAccessor) error {
  1129  		purged += len(accessors)
  1130  		return nil
  1131  	}
  1132  
  1133  	logger := testlog.Logger(t)
  1134  	client, err := NewVaultClient(v.Config, logger, purge)
  1135  	if err != nil {
  1136  		t.Fatalf("failed to build vault client: %v", err)
  1137  	}
  1138  	client.SetActive(true)
  1139  	defer client.Stop()
  1140  
  1141  	waitForConnection(client, t)
  1142  
  1143  	// Create some vault tokens
  1144  	auth := v.Client.Auth().Token()
  1145  	req := vapi.TokenCreateRequest{
  1146  		Policies: []string{"default"},
  1147  	}
  1148  	t1, err := auth.Create(&req)
  1149  	if err != nil {
  1150  		t.Fatalf("Failed to create vault token: %v", err)
  1151  	}
  1152  	if t1 == nil || t1.Auth == nil {
  1153  		t.Fatalf("bad secret response: %+v", t1)
  1154  	}
  1155  	t2, err := auth.Create(&req)
  1156  	if err != nil {
  1157  		t.Fatalf("Failed to create vault token: %v", err)
  1158  	}
  1159  	if t2 == nil || t2.Auth == nil {
  1160  		t.Fatalf("bad secret response: %+v", t2)
  1161  	}
  1162  
  1163  	// Create two VaultAccessors
  1164  	vas := []*structs.VaultAccessor{
  1165  		{Accessor: t1.Auth.Accessor},
  1166  		{Accessor: t2.Auth.Accessor},
  1167  	}
  1168  
  1169  	// Issue a token revocation
  1170  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1171  		t.Fatalf("RevokeTokens failed: %v", err)
  1172  	}
  1173  
  1174  	// Lookup the token and make sure we get an error
  1175  	if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
  1176  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1177  	}
  1178  	if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
  1179  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1180  	}
  1181  
  1182  	if purged != 2 {
  1183  		t.Fatalf("Expected purged 2; got %d", purged)
  1184  	}
  1185  }
  1186  
  1187  func TestVaultClient_RevokeTokens_Role(t *testing.T) {
  1188  	t.Parallel()
  1189  	v := testutil.NewTestVault(t)
  1190  	defer v.Stop()
  1191  
  1192  	// Set the configs token in a new test role
  1193  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
  1194  
  1195  	purged := 0
  1196  	purge := func(accessors []*structs.VaultAccessor) error {
  1197  		purged += len(accessors)
  1198  		return nil
  1199  	}
  1200  
  1201  	logger := testlog.Logger(t)
  1202  	client, err := NewVaultClient(v.Config, logger, purge)
  1203  	if err != nil {
  1204  		t.Fatalf("failed to build vault client: %v", err)
  1205  	}
  1206  	client.SetActive(true)
  1207  	defer client.Stop()
  1208  
  1209  	waitForConnection(client, t)
  1210  
  1211  	// Create some vault tokens
  1212  	auth := v.Client.Auth().Token()
  1213  	req := vapi.TokenCreateRequest{
  1214  		Policies: []string{"default"},
  1215  	}
  1216  	t1, err := auth.Create(&req)
  1217  	if err != nil {
  1218  		t.Fatalf("Failed to create vault token: %v", err)
  1219  	}
  1220  	if t1 == nil || t1.Auth == nil {
  1221  		t.Fatalf("bad secret response: %+v", t1)
  1222  	}
  1223  	t2, err := auth.Create(&req)
  1224  	if err != nil {
  1225  		t.Fatalf("Failed to create vault token: %v", err)
  1226  	}
  1227  	if t2 == nil || t2.Auth == nil {
  1228  		t.Fatalf("bad secret response: %+v", t2)
  1229  	}
  1230  
  1231  	// Create two VaultAccessors
  1232  	vas := []*structs.VaultAccessor{
  1233  		{Accessor: t1.Auth.Accessor},
  1234  		{Accessor: t2.Auth.Accessor},
  1235  	}
  1236  
  1237  	// Issue a token revocation
  1238  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1239  		t.Fatalf("RevokeTokens failed: %v", err)
  1240  	}
  1241  
  1242  	// Lookup the token and make sure we get an error
  1243  	if purged != 2 {
  1244  		t.Fatalf("Expected purged 2; got %d", purged)
  1245  	}
  1246  	if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
  1247  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1248  	}
  1249  	if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
  1250  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1251  	}
  1252  }
  1253  
  1254  func waitForConnection(v *vaultClient, t *testing.T) {
  1255  	testutil.WaitForResult(func() (bool, error) {
  1256  		return v.ConnectionEstablished()
  1257  	}, func(err error) {
  1258  		t.Fatalf("Connection not established")
  1259  	})
  1260  }