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 }