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 }