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