github.com/taylorchu/nomad@v0.5.3-rc1.0.20170407200202-db11e7dd7b55/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_ValidateToken(t *testing.T) {
   251  	v := testutil.NewTestVault(t).Start()
   252  	defer v.Stop()
   253  
   254  	// Set the configs token in a new test role
   255  	vaultPolicies := map[string]string{
   256  		"nomad-role-create": nomadRoleCreatePolicy,
   257  		"token-lookup":      tokenLookupPolicy,
   258  	}
   259  	data := map[string]interface{}{
   260  		"allowed_policies": "token-lookup,nomad-role-create",
   261  		"period":           10,
   262  	}
   263  	v.Config.Token = testVaultRoleAndToken(v, t, vaultPolicies, data, []string{"token-lookup", "nomad-role-create"})
   264  
   265  	logger := log.New(os.Stderr, "", log.LstdFlags)
   266  	v.Config.ConnectionRetryIntv = 100 * time.Millisecond
   267  	client, err := NewVaultClient(v.Config, logger, nil)
   268  	if err != nil {
   269  		t.Fatalf("failed to build vault client: %v", err)
   270  	}
   271  	defer client.Stop()
   272  
   273  	// Wait for an error
   274  	var conn bool
   275  	var connErr error
   276  	testutil.WaitForResult(func() (bool, error) {
   277  		conn, connErr = client.ConnectionEstablished()
   278  		if conn {
   279  			return false, fmt.Errorf("Should not connect")
   280  		}
   281  
   282  		if connErr == nil {
   283  			return false, fmt.Errorf("expect an error")
   284  		}
   285  
   286  		return true, nil
   287  	}, func(err error) {
   288  		t.Fatalf("bad: %v", err)
   289  	})
   290  
   291  	errStr := connErr.Error()
   292  	if !strings.Contains(errStr, vaultTokenRevokePath) {
   293  		t.Fatalf("Expect orphan error")
   294  	}
   295  	if !strings.Contains(errStr, fmt.Sprintf(vaultRoleLookupPath, "test")) {
   296  		t.Fatalf("Expect explicit max ttl error")
   297  	}
   298  	if !strings.Contains(errStr, "token must have one of the following") {
   299  		t.Fatalf("Expect explicit max ttl error")
   300  	}
   301  }
   302  
   303  func TestVaultClient_SetActive(t *testing.T) {
   304  	v := testutil.NewTestVault(t).Start()
   305  	defer v.Stop()
   306  
   307  	logger := log.New(os.Stderr, "", log.LstdFlags)
   308  	client, err := NewVaultClient(v.Config, logger, nil)
   309  	if err != nil {
   310  		t.Fatalf("failed to build vault client: %v", err)
   311  	}
   312  	defer client.Stop()
   313  
   314  	waitForConnection(client, t)
   315  
   316  	// Do a lookup and expect an error about not being active
   317  	_, err = client.LookupToken(context.Background(), "123")
   318  	if err == nil || !strings.Contains(err.Error(), "not active") {
   319  		t.Fatalf("Expected not-active error: %v", err)
   320  	}
   321  
   322  	client.SetActive(true)
   323  
   324  	// Do a lookup of ourselves
   325  	_, err = client.LookupToken(context.Background(), v.RootToken)
   326  	if err != nil {
   327  		t.Fatalf("Unexpected error: %v", err)
   328  	}
   329  }
   330  
   331  // Test that we can update the config and things keep working
   332  func TestVaultClient_SetConfig(t *testing.T) {
   333  	v := testutil.NewTestVault(t).Start()
   334  	defer v.Stop()
   335  
   336  	v2 := testutil.NewTestVault(t).Start()
   337  	defer v2.Stop()
   338  
   339  	// Set the configs token in a new test role
   340  	v2.Config.Token = defaultTestVaultWhitelistRoleAndToken(v2, t, 20)
   341  
   342  	logger := log.New(os.Stderr, "", log.LstdFlags)
   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  	waitForConnection(client, t)
   350  
   351  	if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
   352  		t.Fatalf("unexpected token: %v", client.tokenData)
   353  	}
   354  
   355  	// Update the config
   356  	if err := client.SetConfig(v2.Config); err != nil {
   357  		t.Fatalf("SetConfig failed: %v", err)
   358  	}
   359  
   360  	waitForConnection(client, t)
   361  
   362  	if client.tokenData == nil || len(client.tokenData.Policies) != 3 {
   363  		t.Fatalf("unexpected token: %v", client.tokenData)
   364  	}
   365  }
   366  
   367  // Test that we can disable vault
   368  func TestVaultClient_SetConfig_Disable(t *testing.T) {
   369  	v := testutil.NewTestVault(t).Start()
   370  	defer v.Stop()
   371  
   372  	logger := log.New(os.Stderr, "", log.LstdFlags)
   373  	client, err := NewVaultClient(v.Config, logger, nil)
   374  	if err != nil {
   375  		t.Fatalf("failed to build vault client: %v", err)
   376  	}
   377  	defer client.Stop()
   378  
   379  	waitForConnection(client, t)
   380  
   381  	if client.tokenData == nil || len(client.tokenData.Policies) != 1 {
   382  		t.Fatalf("unexpected token: %v", client.tokenData)
   383  	}
   384  
   385  	// Disable vault
   386  	f := false
   387  	config := config.VaultConfig{
   388  		Enabled: &f,
   389  	}
   390  
   391  	// Update the config
   392  	if err := client.SetConfig(&config); err != nil {
   393  		t.Fatalf("SetConfig failed: %v", err)
   394  	}
   395  
   396  	if client.Enabled() || client.Running() {
   397  		t.Fatalf("SetConfig should have stopped client")
   398  	}
   399  }
   400  
   401  func TestVaultClient_RenewalLoop(t *testing.T) {
   402  	v := testutil.NewTestVault(t).Start()
   403  	defer v.Stop()
   404  
   405  	// Set the configs token in a new test role
   406  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   407  
   408  	// Start the client
   409  	logger := log.New(os.Stderr, "", log.LstdFlags)
   410  	client, err := NewVaultClient(v.Config, logger, nil)
   411  	if err != nil {
   412  		t.Fatalf("failed to build vault client: %v", err)
   413  	}
   414  	defer client.Stop()
   415  
   416  	// Sleep 8 seconds and ensure we have a non-zero TTL
   417  	time.Sleep(8 * time.Second)
   418  
   419  	// Get the current TTL
   420  	a := v.Client.Auth().Token()
   421  	s2, err := a.Lookup(v.Config.Token)
   422  	if err != nil {
   423  		t.Fatalf("failed to lookup token: %v", err)
   424  	}
   425  
   426  	ttl := parseTTLFromLookup(s2, t)
   427  	if ttl == 0 {
   428  		t.Fatalf("token renewal failed; ttl %v", ttl)
   429  	}
   430  }
   431  
   432  func parseTTLFromLookup(s *vapi.Secret, t *testing.T) int64 {
   433  	if s == nil {
   434  		t.Fatalf("nil secret")
   435  	} else if s.Data == nil {
   436  		t.Fatalf("nil data block in secret")
   437  	}
   438  
   439  	ttlRaw, ok := s.Data["ttl"]
   440  	if !ok {
   441  		t.Fatalf("no ttl")
   442  	}
   443  
   444  	ttlNumber, ok := ttlRaw.(json.Number)
   445  	if !ok {
   446  		t.Fatalf("failed to convert ttl %q to json Number", ttlRaw)
   447  	}
   448  
   449  	ttl, err := ttlNumber.Int64()
   450  	if err != nil {
   451  		t.Fatalf("Failed to get ttl from json.Number: %v", err)
   452  	}
   453  
   454  	return ttl
   455  }
   456  
   457  func TestVaultClient_LookupToken_Invalid(t *testing.T) {
   458  	tr := true
   459  	conf := &config.VaultConfig{
   460  		Enabled: &tr,
   461  		Addr:    "http://foobar:12345",
   462  		Token:   structs.GenerateUUID(),
   463  	}
   464  
   465  	// Enable vault but use a bad address so it never establishes a conn
   466  	logger := log.New(os.Stderr, "", log.LstdFlags)
   467  	client, err := NewVaultClient(conf, logger, nil)
   468  	if err != nil {
   469  		t.Fatalf("failed to build vault client: %v", err)
   470  	}
   471  	client.SetActive(true)
   472  	defer client.Stop()
   473  
   474  	_, err = client.LookupToken(context.Background(), "foo")
   475  	if err == nil || !strings.Contains(err.Error(), "established") {
   476  		t.Fatalf("Expected error because connection to Vault hasn't been made: %v", err)
   477  	}
   478  }
   479  
   480  func TestVaultClient_LookupToken_Root(t *testing.T) {
   481  	v := testutil.NewTestVault(t).Start()
   482  	defer v.Stop()
   483  
   484  	logger := log.New(os.Stderr, "", log.LstdFlags)
   485  	client, err := NewVaultClient(v.Config, logger, nil)
   486  	if err != nil {
   487  		t.Fatalf("failed to build vault client: %v", err)
   488  	}
   489  	client.SetActive(true)
   490  	defer client.Stop()
   491  
   492  	waitForConnection(client, t)
   493  
   494  	// Lookup ourselves
   495  	s, err := client.LookupToken(context.Background(), v.Config.Token)
   496  	if err != nil {
   497  		t.Fatalf("self lookup failed: %v", err)
   498  	}
   499  
   500  	policies, err := PoliciesFrom(s)
   501  	if err != nil {
   502  		t.Fatalf("failed to parse policies: %v", err)
   503  	}
   504  
   505  	expected := []string{"root"}
   506  	if !reflect.DeepEqual(policies, expected) {
   507  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   508  	}
   509  
   510  	// Create a token with a different set of policies
   511  	expected = []string{"default"}
   512  	req := vapi.TokenCreateRequest{
   513  		Policies: expected,
   514  	}
   515  	s, err = v.Client.Auth().Token().Create(&req)
   516  	if err != nil {
   517  		t.Fatalf("failed to create child token: %v", err)
   518  	}
   519  
   520  	// Get the client token
   521  	if s == nil || s.Auth == nil {
   522  		t.Fatalf("bad secret response: %+v", s)
   523  	}
   524  
   525  	// Lookup new child
   526  	s, err = client.LookupToken(context.Background(), s.Auth.ClientToken)
   527  	if err != nil {
   528  		t.Fatalf("self lookup failed: %v", err)
   529  	}
   530  
   531  	policies, err = PoliciesFrom(s)
   532  	if err != nil {
   533  		t.Fatalf("failed to parse policies: %v", err)
   534  	}
   535  
   536  	if !reflect.DeepEqual(policies, expected) {
   537  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   538  	}
   539  }
   540  
   541  func TestVaultClient_LookupToken_Role(t *testing.T) {
   542  	v := testutil.NewTestVault(t).Start()
   543  	defer v.Stop()
   544  
   545  	// Set the configs token in a new test role
   546  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   547  
   548  	logger := log.New(os.Stderr, "", log.LstdFlags)
   549  	client, err := NewVaultClient(v.Config, logger, nil)
   550  	if err != nil {
   551  		t.Fatalf("failed to build vault client: %v", err)
   552  	}
   553  	client.SetActive(true)
   554  	defer client.Stop()
   555  
   556  	waitForConnection(client, t)
   557  
   558  	// Lookup ourselves
   559  	s, err := client.LookupToken(context.Background(), v.Config.Token)
   560  	if err != nil {
   561  		t.Fatalf("self lookup failed: %v", err)
   562  	}
   563  
   564  	policies, err := PoliciesFrom(s)
   565  	if err != nil {
   566  		t.Fatalf("failed to parse policies: %v", err)
   567  	}
   568  
   569  	expected := []string{"default", "nomad-role-create", "nomad-role-management"}
   570  	if !reflect.DeepEqual(policies, expected) {
   571  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   572  	}
   573  
   574  	// Create a token with a different set of policies
   575  	expected = []string{"default"}
   576  	req := vapi.TokenCreateRequest{
   577  		Policies: expected,
   578  	}
   579  	s, err = v.Client.Auth().Token().Create(&req)
   580  	if err != nil {
   581  		t.Fatalf("failed to create child token: %v", err)
   582  	}
   583  
   584  	// Get the client token
   585  	if s == nil || s.Auth == nil {
   586  		t.Fatalf("bad secret response: %+v", s)
   587  	}
   588  
   589  	// Lookup new child
   590  	s, err = client.LookupToken(context.Background(), s.Auth.ClientToken)
   591  	if err != nil {
   592  		t.Fatalf("self lookup failed: %v", err)
   593  	}
   594  
   595  	policies, err = PoliciesFrom(s)
   596  	if err != nil {
   597  		t.Fatalf("failed to parse policies: %v", err)
   598  	}
   599  
   600  	if !reflect.DeepEqual(policies, expected) {
   601  		t.Fatalf("Unexpected policies; got %v; want %v", policies, expected)
   602  	}
   603  }
   604  
   605  func TestVaultClient_LookupToken_RateLimit(t *testing.T) {
   606  	v := testutil.NewTestVault(t).Start()
   607  	defer v.Stop()
   608  
   609  	logger := log.New(os.Stderr, "", log.LstdFlags)
   610  	client, err := NewVaultClient(v.Config, logger, nil)
   611  	if err != nil {
   612  		t.Fatalf("failed to build vault client: %v", err)
   613  	}
   614  	client.SetActive(true)
   615  	defer client.Stop()
   616  	client.setLimit(rate.Limit(1.0))
   617  
   618  	waitForConnection(client, t)
   619  
   620  	// Spin up many requests. These should block
   621  	ctx, cancel := context.WithCancel(context.Background())
   622  
   623  	cancels := 0
   624  	numRequests := 10
   625  	unblock := make(chan struct{})
   626  	for i := 0; i < numRequests; i++ {
   627  		go func() {
   628  			// Lookup ourselves
   629  			_, err := client.LookupToken(ctx, v.Config.Token)
   630  			if err != nil {
   631  				if err == context.Canceled {
   632  					cancels += 1
   633  					return
   634  				}
   635  				t.Fatalf("self lookup failed: %v", err)
   636  				return
   637  			}
   638  
   639  			// Cancel the context
   640  			close(unblock)
   641  		}()
   642  	}
   643  
   644  	select {
   645  	case <-time.After(5 * time.Second):
   646  		t.Fatalf("timeout")
   647  	case <-unblock:
   648  		cancel()
   649  	}
   650  
   651  	desired := numRequests - 1
   652  	testutil.WaitForResult(func() (bool, error) {
   653  		if cancels != desired {
   654  			return false, fmt.Errorf("Incorrect number of cancels; got %d; want %d", cancels, desired)
   655  		}
   656  
   657  		return true, nil
   658  	}, func(err error) {
   659  		t.Fatalf("Connection not established")
   660  	})
   661  }
   662  
   663  func TestVaultClient_CreateToken_Root(t *testing.T) {
   664  	v := testutil.NewTestVault(t).Start()
   665  	defer v.Stop()
   666  
   667  	logger := log.New(os.Stderr, "", log.LstdFlags)
   668  	client, err := NewVaultClient(v.Config, logger, nil)
   669  	if err != nil {
   670  		t.Fatalf("failed to build vault client: %v", err)
   671  	}
   672  	client.SetActive(true)
   673  	defer client.Stop()
   674  
   675  	waitForConnection(client, t)
   676  
   677  	// Create an allocation that requires a Vault policy
   678  	a := mock.Alloc()
   679  	task := a.Job.TaskGroups[0].Tasks[0]
   680  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   681  
   682  	s, err := client.CreateToken(context.Background(), a, task.Name)
   683  	if err != nil {
   684  		t.Fatalf("CreateToken failed: %v", err)
   685  	}
   686  
   687  	// Ensure that created secret is a wrapped token
   688  	if s == nil || s.WrapInfo == nil {
   689  		t.Fatalf("Bad secret: %#v", s)
   690  	}
   691  
   692  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   693  	if err != nil {
   694  		t.Fatalf("bad: %v", err)
   695  	}
   696  
   697  	if s.WrapInfo.WrappedAccessor == "" {
   698  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   699  	} else if s.WrapInfo.Token == "" {
   700  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   701  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   702  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   703  	}
   704  }
   705  
   706  func TestVaultClient_CreateToken_Whitelist_Role(t *testing.T) {
   707  	v := testutil.NewTestVault(t).Start()
   708  	defer v.Stop()
   709  
   710  	// Set the configs token in a new test role
   711  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   712  
   713  	// Start the client
   714  	logger := log.New(os.Stderr, "", log.LstdFlags)
   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  	// Create an allocation that requires a Vault policy
   725  	a := mock.Alloc()
   726  	task := a.Job.TaskGroups[0].Tasks[0]
   727  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   728  
   729  	s, err := client.CreateToken(context.Background(), a, task.Name)
   730  	if err != nil {
   731  		t.Fatalf("CreateToken failed: %v", err)
   732  	}
   733  
   734  	// Ensure that created secret is a wrapped token
   735  	if s == nil || s.WrapInfo == nil {
   736  		t.Fatalf("Bad secret: %#v", s)
   737  	}
   738  
   739  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   740  	if err != nil {
   741  		t.Fatalf("bad: %v", err)
   742  	}
   743  
   744  	if s.WrapInfo.WrappedAccessor == "" {
   745  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   746  	} else if s.WrapInfo.Token == "" {
   747  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   748  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   749  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   750  	}
   751  }
   752  
   753  func TestVaultClient_CreateToken_Root_Target_Role(t *testing.T) {
   754  	v := testutil.NewTestVault(t).Start()
   755  	defer v.Stop()
   756  
   757  	// Create the test role
   758  	defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   759  
   760  	// Target the test role
   761  	v.Config.Role = "test"
   762  
   763  	// Start the client
   764  	logger := log.New(os.Stderr, "", log.LstdFlags)
   765  	client, err := NewVaultClient(v.Config, logger, nil)
   766  	if err != nil {
   767  		t.Fatalf("failed to build vault client: %v", err)
   768  	}
   769  	client.SetActive(true)
   770  	defer client.Stop()
   771  
   772  	waitForConnection(client, t)
   773  
   774  	// Create an allocation that requires a Vault policy
   775  	a := mock.Alloc()
   776  	task := a.Job.TaskGroups[0].Tasks[0]
   777  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   778  
   779  	s, err := client.CreateToken(context.Background(), a, task.Name)
   780  	if err != nil {
   781  		t.Fatalf("CreateToken failed: %v", err)
   782  	}
   783  
   784  	// Ensure that created secret is a wrapped token
   785  	if s == nil || s.WrapInfo == nil {
   786  		t.Fatalf("Bad secret: %#v", s)
   787  	}
   788  
   789  	d, err := time.ParseDuration(vaultTokenCreateTTL)
   790  	if err != nil {
   791  		t.Fatalf("bad: %v", err)
   792  	}
   793  
   794  	if s.WrapInfo.WrappedAccessor == "" {
   795  		t.Fatalf("Bad accessor: %v", s.WrapInfo.WrappedAccessor)
   796  	} else if s.WrapInfo.Token == "" {
   797  		t.Fatalf("Bad token: %v", s.WrapInfo.WrappedAccessor)
   798  	} else if s.WrapInfo.TTL != int(d.Seconds()) {
   799  		t.Fatalf("Bad ttl: %v", s.WrapInfo.WrappedAccessor)
   800  	}
   801  }
   802  
   803  func TestVaultClient_CreateToken_Blacklist_Role(t *testing.T) {
   804  	// Need to skip if test is 0.6.4
   805  	version, err := testutil.VaultVersion()
   806  	if err != nil {
   807  		t.Fatalf("failed to determine version: %v", err)
   808  	}
   809  
   810  	if strings.Contains(version, "v0.6.4") {
   811  		t.Skipf("Vault has a regression in v0.6.4 that this test hits")
   812  	}
   813  
   814  	v := testutil.NewTestVault(t).Start()
   815  	defer v.Stop()
   816  
   817  	// Set the configs token in a new test role
   818  	v.Config.Token = defaultTestVaultBlacklistRoleAndToken(v, t, 5)
   819  	v.Config.Role = "test"
   820  
   821  	// Start the client
   822  	logger := log.New(os.Stderr, "", log.LstdFlags)
   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{"secrets"}}
   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_Role_InvalidToken(t *testing.T) {
   862  	v := testutil.NewTestVault(t).Start()
   863  	defer v.Stop()
   864  
   865  	// Set the configs token in a new test role
   866  	defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   867  	v.Config.Token = "foo-bar"
   868  
   869  	// Start the client
   870  	logger := log.New(os.Stderr, "", log.LstdFlags)
   871  	client, err := NewVaultClient(v.Config, logger, nil)
   872  	if err != nil {
   873  		t.Fatalf("failed to build vault client: %v", err)
   874  	}
   875  	client.SetActive(true)
   876  	defer client.Stop()
   877  
   878  	testutil.WaitForResult(func() (bool, error) {
   879  		established, err := client.ConnectionEstablished()
   880  		if established {
   881  			return false, fmt.Errorf("Shouldn't establish")
   882  		}
   883  
   884  		return err != nil, nil
   885  	}, func(err error) {
   886  		t.Fatalf("Connection not established")
   887  	})
   888  
   889  	// Create an allocation that requires a Vault policy
   890  	a := mock.Alloc()
   891  	task := a.Job.TaskGroups[0].Tasks[0]
   892  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   893  
   894  	_, err = client.CreateToken(context.Background(), a, task.Name)
   895  	if err == nil || !strings.Contains(err.Error(), "Connection to Vault failed") {
   896  		t.Fatalf("CreateToken should have failed: %v", err)
   897  	}
   898  }
   899  
   900  func TestVaultClient_CreateToken_Role_Unrecoverable(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  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
   906  
   907  	// Start the client
   908  	logger := log.New(os.Stderr, "", log.LstdFlags)
   909  	client, err := NewVaultClient(v.Config, logger, nil)
   910  	if err != nil {
   911  		t.Fatalf("failed to build vault client: %v", err)
   912  	}
   913  	client.SetActive(true)
   914  	defer client.Stop()
   915  
   916  	waitForConnection(client, t)
   917  
   918  	// Create an allocation that requires a Vault policy
   919  	a := mock.Alloc()
   920  	task := a.Job.TaskGroups[0].Tasks[0]
   921  	task.Vault = &structs.Vault{Policies: []string{"unknown_policy"}}
   922  
   923  	_, err = client.CreateToken(context.Background(), a, task.Name)
   924  	if err == nil {
   925  		t.Fatalf("CreateToken should have failed: %v", err)
   926  	}
   927  
   928  	_, ok := err.(structs.Recoverable)
   929  	if ok {
   930  		t.Fatalf("CreateToken should not be a recoverable error type: %v (%T)", err, err)
   931  	}
   932  }
   933  
   934  func TestVaultClient_CreateToken_Prestart(t *testing.T) {
   935  	v := testutil.NewTestVault(t)
   936  	defer v.Stop()
   937  
   938  	logger := log.New(os.Stderr, "", log.LstdFlags)
   939  	client, err := NewVaultClient(v.Config, logger, nil)
   940  	if err != nil {
   941  		t.Fatalf("failed to build vault client: %v", err)
   942  	}
   943  	client.SetActive(true)
   944  	defer client.Stop()
   945  
   946  	// Create an allocation that requires a Vault policy
   947  	a := mock.Alloc()
   948  	task := a.Job.TaskGroups[0].Tasks[0]
   949  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   950  
   951  	_, err = client.CreateToken(context.Background(), a, task.Name)
   952  	if err == nil {
   953  		t.Fatalf("CreateToken should have failed: %v", err)
   954  	}
   955  
   956  	if rerr, ok := err.(*structs.RecoverableError); !ok {
   957  		t.Fatalf("Err should have been type recoverable error")
   958  	} else if ok && !rerr.IsRecoverable() {
   959  		t.Fatalf("Err should have been recoverable")
   960  	}
   961  }
   962  
   963  func TestVaultClient_RevokeTokens_PreEstablishs(t *testing.T) {
   964  	v := testutil.NewTestVault(t)
   965  	logger := log.New(os.Stderr, "", log.LstdFlags)
   966  	client, err := NewVaultClient(v.Config, logger, nil)
   967  	if err != nil {
   968  		t.Fatalf("failed to build vault client: %v", err)
   969  	}
   970  	client.SetActive(true)
   971  	defer client.Stop()
   972  
   973  	// Create some VaultAccessors
   974  	vas := []*structs.VaultAccessor{
   975  		mock.VaultAccessor(),
   976  		mock.VaultAccessor(),
   977  	}
   978  
   979  	if err := client.RevokeTokens(context.Background(), vas, false); err != nil {
   980  		t.Fatalf("RevokeTokens failed: %v", err)
   981  	}
   982  
   983  	// Wasn't committed
   984  	if len(client.revoking) != 0 {
   985  		t.Fatalf("didn't add to revoke loop")
   986  	}
   987  
   988  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
   989  		t.Fatalf("RevokeTokens failed: %v", err)
   990  	}
   991  
   992  	// Was committed
   993  	if len(client.revoking) != 2 {
   994  		t.Fatalf("didn't add to revoke loop")
   995  	}
   996  
   997  	if client.Stats().TrackedForRevoke != 2 {
   998  		t.Fatalf("didn't add to revoke loop")
   999  	}
  1000  }
  1001  
  1002  func TestVaultClient_RevokeTokens_Root(t *testing.T) {
  1003  	v := testutil.NewTestVault(t).Start()
  1004  	defer v.Stop()
  1005  
  1006  	purged := 0
  1007  	purge := func(accessors []*structs.VaultAccessor) error {
  1008  		purged += len(accessors)
  1009  		return nil
  1010  	}
  1011  
  1012  	logger := log.New(os.Stderr, "", log.LstdFlags)
  1013  	client, err := NewVaultClient(v.Config, logger, purge)
  1014  	if err != nil {
  1015  		t.Fatalf("failed to build vault client: %v", err)
  1016  	}
  1017  	client.SetActive(true)
  1018  	defer client.Stop()
  1019  
  1020  	waitForConnection(client, t)
  1021  
  1022  	// Create some vault tokens
  1023  	auth := v.Client.Auth().Token()
  1024  	req := vapi.TokenCreateRequest{
  1025  		Policies: []string{"default"},
  1026  	}
  1027  	t1, err := auth.Create(&req)
  1028  	if err != nil {
  1029  		t.Fatalf("Failed to create vault token: %v", err)
  1030  	}
  1031  	if t1 == nil || t1.Auth == nil {
  1032  		t.Fatalf("bad secret response: %+v", t1)
  1033  	}
  1034  	t2, err := auth.Create(&req)
  1035  	if err != nil {
  1036  		t.Fatalf("Failed to create vault token: %v", err)
  1037  	}
  1038  	if t2 == nil || t2.Auth == nil {
  1039  		t.Fatalf("bad secret response: %+v", t2)
  1040  	}
  1041  
  1042  	// Create two VaultAccessors
  1043  	vas := []*structs.VaultAccessor{
  1044  		&structs.VaultAccessor{Accessor: t1.Auth.Accessor},
  1045  		&structs.VaultAccessor{Accessor: t2.Auth.Accessor},
  1046  	}
  1047  
  1048  	// Issue a token revocation
  1049  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1050  		t.Fatalf("RevokeTokens failed: %v", err)
  1051  	}
  1052  
  1053  	// Lookup the token and make sure we get an error
  1054  	if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
  1055  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1056  	}
  1057  	if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
  1058  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1059  	}
  1060  
  1061  	if purged != 2 {
  1062  		t.Fatalf("Expected purged 2; got %d", purged)
  1063  	}
  1064  }
  1065  
  1066  func TestVaultClient_RevokeTokens_Role(t *testing.T) {
  1067  	v := testutil.NewTestVault(t).Start()
  1068  	defer v.Stop()
  1069  
  1070  	// Set the configs token in a new test role
  1071  	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
  1072  
  1073  	purged := 0
  1074  	purge := func(accessors []*structs.VaultAccessor) error {
  1075  		purged += len(accessors)
  1076  		return nil
  1077  	}
  1078  
  1079  	logger := log.New(os.Stderr, "", log.LstdFlags)
  1080  	client, err := NewVaultClient(v.Config, logger, purge)
  1081  	if err != nil {
  1082  		t.Fatalf("failed to build vault client: %v", err)
  1083  	}
  1084  	client.SetActive(true)
  1085  	defer client.Stop()
  1086  
  1087  	waitForConnection(client, t)
  1088  
  1089  	// Create some vault tokens
  1090  	auth := v.Client.Auth().Token()
  1091  	req := vapi.TokenCreateRequest{
  1092  		Policies: []string{"default"},
  1093  	}
  1094  	t1, err := auth.Create(&req)
  1095  	if err != nil {
  1096  		t.Fatalf("Failed to create vault token: %v", err)
  1097  	}
  1098  	if t1 == nil || t1.Auth == nil {
  1099  		t.Fatalf("bad secret response: %+v", t1)
  1100  	}
  1101  	t2, err := auth.Create(&req)
  1102  	if err != nil {
  1103  		t.Fatalf("Failed to create vault token: %v", err)
  1104  	}
  1105  	if t2 == nil || t2.Auth == nil {
  1106  		t.Fatalf("bad secret response: %+v", t2)
  1107  	}
  1108  
  1109  	// Create two VaultAccessors
  1110  	vas := []*structs.VaultAccessor{
  1111  		&structs.VaultAccessor{Accessor: t1.Auth.Accessor},
  1112  		&structs.VaultAccessor{Accessor: t2.Auth.Accessor},
  1113  	}
  1114  
  1115  	// Issue a token revocation
  1116  	if err := client.RevokeTokens(context.Background(), vas, true); err != nil {
  1117  		t.Fatalf("RevokeTokens failed: %v", err)
  1118  	}
  1119  
  1120  	// Lookup the token and make sure we get an error
  1121  	if purged != 2 {
  1122  		t.Fatalf("Expected purged 2; got %d", purged)
  1123  	}
  1124  	if s, err := auth.Lookup(t1.Auth.ClientToken); err == nil {
  1125  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1126  	}
  1127  	if s, err := auth.Lookup(t2.Auth.ClientToken); err == nil {
  1128  		t.Fatalf("Revoked token lookup didn't fail: %+v", s)
  1129  	}
  1130  }
  1131  
  1132  func waitForConnection(v *vaultClient, t *testing.T) {
  1133  	testutil.WaitForResult(func() (bool, error) {
  1134  		return v.ConnectionEstablished()
  1135  	}, func(err error) {
  1136  		t.Fatalf("Connection not established")
  1137  	})
  1138  }