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