1package awsauth 2 3import ( 4 "context" 5 "encoding/base64" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "os" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/aws/aws-sdk-go/aws/session" 16 "github.com/aws/aws-sdk-go/service/sts" 17 "github.com/hashicorp/vault/helper/policyutil" 18 "github.com/hashicorp/vault/logical" 19 "github.com/hashicorp/vault/logical/framework" 20 logicaltest "github.com/hashicorp/vault/logical/testing" 21) 22 23const testVaultHeaderValue = "VaultAcceptanceTesting" 24const testValidRoleName = "valid-role" 25const testInvalidRoleName = "invalid-role" 26 27func TestBackend_CreateParseVerifyRoleTag(t *testing.T) { 28 // create a backend 29 config := logical.TestBackendConfig() 30 storage := &logical.InmemStorage{} 31 config.StorageView = storage 32 33 b, err := Backend(config) 34 if err != nil { 35 t.Fatal(err) 36 } 37 38 err = b.Setup(context.Background(), config) 39 if err != nil { 40 t.Fatal(err) 41 } 42 43 // create a role entry 44 data := map[string]interface{}{ 45 "auth_type": "ec2", 46 "policies": "p,q,r,s", 47 "bound_ami_id": "abcd-123", 48 } 49 resp, err := b.HandleRequest(context.Background(), &logical.Request{ 50 Operation: logical.CreateOperation, 51 Path: "role/abcd-123", 52 Storage: storage, 53 Data: data, 54 }) 55 if resp != nil && resp.IsError() { 56 t.Fatalf("failed to create role") 57 } 58 if err != nil { 59 t.Fatal(err) 60 } 61 62 // read the created role entry 63 roleEntry, err := b.lockedAWSRole(context.Background(), storage, "abcd-123") 64 if err != nil { 65 t.Fatal(err) 66 } 67 68 // create a nonce for the role tag 69 nonce, err := createRoleTagNonce() 70 if err != nil { 71 t.Fatal(err) 72 } 73 rTag1 := &roleTag{ 74 Version: "v1", 75 Role: "abcd-123", 76 Nonce: nonce, 77 Policies: []string{"p", "q", "r"}, 78 MaxTTL: 200000000000, // 200s 79 } 80 81 // create a role tag against the role entry 82 val, err := createRoleTagValue(rTag1, roleEntry) 83 if err != nil { 84 t.Fatal(err) 85 } 86 if val == "" { 87 t.Fatalf("failed to create role tag") 88 } 89 90 // parse the created role tag 91 rTag2, err := b.parseAndVerifyRoleTagValue(context.Background(), storage, val) 92 if err != nil { 93 t.Fatal(err) 94 } 95 96 // check the values in parsed role tag 97 if rTag2.Version != "v1" || 98 rTag2.Nonce != nonce || 99 rTag2.Role != "abcd-123" || 100 rTag2.MaxTTL != 200000000000 || // 200s 101 !policyutil.EquivalentPolicies(rTag2.Policies, []string{"p", "q", "r"}) || 102 len(rTag2.HMAC) == 0 { 103 t.Fatalf("parsed role tag is invalid") 104 } 105 106 // verify the tag contents using role specific HMAC key 107 verified, err := verifyRoleTagValue(rTag2, roleEntry) 108 if err != nil { 109 t.Fatal(err) 110 } 111 if !verified { 112 t.Fatalf("failed to verify the role tag") 113 } 114 115 // register a different role 116 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 117 Operation: logical.CreateOperation, 118 Path: "role/ami-6789", 119 Storage: storage, 120 Data: data, 121 }) 122 if resp != nil && resp.IsError() { 123 t.Fatalf("failed to create role") 124 } 125 if err != nil { 126 t.Fatal(err) 127 } 128 129 // get the entry of the newly created role entry 130 roleEntry2, err := b.lockedAWSRole(context.Background(), storage, "ami-6789") 131 if err != nil { 132 t.Fatal(err) 133 } 134 135 // try to verify the tag created with previous role's HMAC key 136 // with the newly registered entry's HMAC key 137 verified, err = verifyRoleTagValue(rTag2, roleEntry2) 138 if err != nil { 139 t.Fatal(err) 140 } 141 if verified { 142 t.Fatalf("verification of role tag should have failed") 143 } 144 145 // modify any value in role tag and try to verify it 146 rTag2.Version = "v2" 147 verified, err = verifyRoleTagValue(rTag2, roleEntry) 148 if err != nil { 149 t.Fatal(err) 150 } 151 if verified { 152 t.Fatalf("verification of role tag should have failed: invalid Version") 153 } 154} 155 156func TestBackend_prepareRoleTagPlaintextValue(t *testing.T) { 157 // create a nonce for the role tag 158 nonce, err := createRoleTagNonce() 159 if err != nil { 160 t.Fatal(err) 161 } 162 rTag := &roleTag{ 163 Version: "v1", 164 Nonce: nonce, 165 Role: "abcd-123", 166 } 167 168 rTag.Version = "" 169 // try to create plaintext part of role tag 170 // without specifying version 171 val, err := prepareRoleTagPlaintextValue(rTag) 172 if err == nil { 173 t.Fatalf("expected error for missing version") 174 } 175 rTag.Version = "v1" 176 177 rTag.Nonce = "" 178 // try to create plaintext part of role tag 179 // without specifying nonce 180 val, err = prepareRoleTagPlaintextValue(rTag) 181 if err == nil { 182 t.Fatalf("expected error for missing nonce") 183 } 184 rTag.Nonce = nonce 185 186 rTag.Role = "" 187 // try to create plaintext part of role tag 188 // without specifying role 189 val, err = prepareRoleTagPlaintextValue(rTag) 190 if err == nil { 191 t.Fatalf("expected error for missing role") 192 } 193 rTag.Role = "abcd-123" 194 195 // create the plaintext part of the tag 196 val, err = prepareRoleTagPlaintextValue(rTag) 197 if err != nil { 198 t.Fatal(err) 199 } 200 201 // verify if it contains known fields 202 if !strings.Contains(val, "r=") || 203 !strings.Contains(val, "d=") || 204 !strings.Contains(val, "m=") || 205 !strings.HasPrefix(val, "v1") { 206 t.Fatalf("incorrect information in role tag plaintext value") 207 } 208 209 rTag.InstanceID = "instance-123" 210 // create the role tag with instance_id specified 211 val, err = prepareRoleTagPlaintextValue(rTag) 212 if err != nil { 213 t.Fatal(err) 214 } 215 // verify it 216 if !strings.Contains(val, "i=") { 217 t.Fatalf("missing instance ID in role tag plaintext value") 218 } 219 220 rTag.MaxTTL = 200000000000 221 // create the role tag with max_ttl specified 222 val, err = prepareRoleTagPlaintextValue(rTag) 223 if err != nil { 224 t.Fatal(err) 225 } 226 // verify it 227 if !strings.Contains(val, "t=") { 228 t.Fatalf("missing max_ttl field in role tag plaintext value") 229 } 230} 231 232func TestBackend_CreateRoleTagNonce(t *testing.T) { 233 // create a nonce for the role tag 234 nonce, err := createRoleTagNonce() 235 if err != nil { 236 t.Fatal(err) 237 } 238 if nonce == "" { 239 t.Fatalf("failed to create role tag nonce") 240 } 241 242 // verify that the value returned is base64 encoded 243 nonceBytes, err := base64.StdEncoding.DecodeString(nonce) 244 if err != nil { 245 t.Fatal(err) 246 } 247 if len(nonceBytes) == 0 { 248 t.Fatalf("length of role tag nonce is zero") 249 } 250} 251 252func TestBackend_ConfigTidyIdentities(t *testing.T) { 253 // create a backend 254 config := logical.TestBackendConfig() 255 storage := &logical.InmemStorage{} 256 config.StorageView = storage 257 258 b, err := Backend(config) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 err = b.Setup(context.Background(), config) 264 if err != nil { 265 t.Fatal(err) 266 } 267 268 // test update operation 269 tidyRequest := &logical.Request{ 270 Operation: logical.UpdateOperation, 271 Path: "config/tidy/identity-whitelist", 272 Storage: storage, 273 } 274 data := map[string]interface{}{ 275 "safety_buffer": "60", 276 "disable_periodic_tidy": true, 277 } 278 tidyRequest.Data = data 279 _, err = b.HandleRequest(context.Background(), tidyRequest) 280 if err != nil { 281 t.Fatal(err) 282 } 283 284 // test read operation 285 tidyRequest.Operation = logical.ReadOperation 286 resp, err := b.HandleRequest(context.Background(), tidyRequest) 287 if err != nil { 288 t.Fatal(err) 289 } 290 if resp == nil || resp.IsError() { 291 t.Fatalf("failed to read config/tidy/identity-whitelist endpoint") 292 } 293 if resp.Data["safety_buffer"].(int) != 60 || !resp.Data["disable_periodic_tidy"].(bool) { 294 t.Fatalf("bad: expected: safety_buffer:60 disable_periodic_tidy:true actual: safety_buffer:%d disable_periodic_tidy:%t\n", resp.Data["safety_buffer"].(int), resp.Data["disable_periodic_tidy"].(bool)) 295 } 296 297 // test delete operation 298 tidyRequest.Operation = logical.DeleteOperation 299 resp, err = b.HandleRequest(context.Background(), tidyRequest) 300 if err != nil { 301 t.Fatal(err) 302 } 303 if resp != nil { 304 t.Fatalf("failed to delete config/tidy/identity-whitelist") 305 } 306} 307 308func TestBackend_ConfigTidyRoleTags(t *testing.T) { 309 config := logical.TestBackendConfig() 310 storage := &logical.InmemStorage{} 311 config.StorageView = storage 312 313 b, err := Backend(config) 314 if err != nil { 315 t.Fatal(err) 316 } 317 318 err = b.Setup(context.Background(), config) 319 if err != nil { 320 t.Fatal(err) 321 } 322 323 // test update operation 324 tidyRequest := &logical.Request{ 325 Operation: logical.UpdateOperation, 326 Path: "config/tidy/roletag-blacklist", 327 Storage: storage, 328 } 329 data := map[string]interface{}{ 330 "safety_buffer": "60", 331 "disable_periodic_tidy": true, 332 } 333 tidyRequest.Data = data 334 _, err = b.HandleRequest(context.Background(), tidyRequest) 335 if err != nil { 336 t.Fatal(err) 337 } 338 339 // test read operation 340 tidyRequest.Operation = logical.ReadOperation 341 resp, err := b.HandleRequest(context.Background(), tidyRequest) 342 if err != nil { 343 t.Fatal(err) 344 } 345 if resp == nil || resp.IsError() { 346 t.Fatalf("failed to read config/tidy/roletag-blacklist endpoint") 347 } 348 if resp.Data["safety_buffer"].(int) != 60 || !resp.Data["disable_periodic_tidy"].(bool) { 349 t.Fatalf("bad: expected: safety_buffer:60 disable_periodic_tidy:true actual: safety_buffer:%d disable_periodic_tidy:%t\n", resp.Data["safety_buffer"].(int), resp.Data["disable_periodic_tidy"].(bool)) 350 } 351 352 // test delete operation 353 tidyRequest.Operation = logical.DeleteOperation 354 resp, err = b.HandleRequest(context.Background(), tidyRequest) 355 if err != nil { 356 t.Fatal(err) 357 } 358 if resp != nil { 359 t.Fatalf("failed to delete config/tidy/roletag-blacklist") 360 } 361} 362 363func TestBackend_TidyIdentities(t *testing.T) { 364 config := logical.TestBackendConfig() 365 storage := &logical.InmemStorage{} 366 config.StorageView = storage 367 368 b, err := Backend(config) 369 if err != nil { 370 t.Fatal(err) 371 } 372 373 err = b.Setup(context.Background(), config) 374 if err != nil { 375 t.Fatal(err) 376 } 377 378 expiredIdentityWhitelist := &whitelistIdentity{ 379 ExpirationTime: time.Now().Add(-1 * 24 * 365 * time.Hour), 380 } 381 entry, err := logical.StorageEntryJSON("whitelist/identity/id1", expiredIdentityWhitelist) 382 if err != nil { 383 t.Fatal(err) 384 } 385 if err := storage.Put(context.Background(), entry); err != nil { 386 t.Fatal(err) 387 } 388 389 // test update operation 390 _, err = b.HandleRequest(context.Background(), &logical.Request{ 391 Operation: logical.UpdateOperation, 392 Path: "tidy/identity-whitelist", 393 Storage: storage, 394 }) 395 if err != nil { 396 t.Fatal(err) 397 } 398 399 // let tidy finish in the background 400 time.Sleep(1 * time.Second) 401 402 entry, err = storage.Get(context.Background(), "whitelist/identity/id1") 403 if err != nil { 404 t.Fatal(err) 405 } 406 if entry != nil { 407 t.Fatal("wl tidy did not remove expired entry") 408 } 409} 410 411func TestBackend_TidyRoleTags(t *testing.T) { 412 config := logical.TestBackendConfig() 413 storage := &logical.InmemStorage{} 414 config.StorageView = storage 415 416 b, err := Backend(config) 417 if err != nil { 418 t.Fatal(err) 419 } 420 421 err = b.Setup(context.Background(), config) 422 if err != nil { 423 t.Fatal(err) 424 } 425 426 expiredIdentityWhitelist := &roleTagBlacklistEntry{ 427 ExpirationTime: time.Now().Add(-1 * 24 * 365 * time.Hour), 428 } 429 entry, err := logical.StorageEntryJSON("blacklist/roletag/id1", expiredIdentityWhitelist) 430 if err != nil { 431 t.Fatal(err) 432 } 433 if err := storage.Put(context.Background(), entry); err != nil { 434 t.Fatal(err) 435 } 436 437 // test update operation 438 _, err = b.HandleRequest(context.Background(), &logical.Request{ 439 Operation: logical.UpdateOperation, 440 Path: "tidy/roletag-blacklist", 441 Storage: storage, 442 }) 443 if err != nil { 444 t.Fatal(err) 445 } 446 447 // let tidy finish in the background 448 time.Sleep(1 * time.Second) 449 450 entry, err = storage.Get(context.Background(), "blacklist/roletag/id1") 451 if err != nil { 452 t.Fatal(err) 453 } 454 if entry != nil { 455 t.Fatal("bl tidy did not remove expired entry") 456 } 457} 458 459func TestBackend_ConfigClient(t *testing.T) { 460 config := logical.TestBackendConfig() 461 storage := &logical.InmemStorage{} 462 config.StorageView = storage 463 464 b, err := Backend(config) 465 if err != nil { 466 t.Fatal(err) 467 } 468 469 err = b.Setup(context.Background(), config) 470 if err != nil { 471 t.Fatal(err) 472 } 473 474 data := map[string]interface{}{"access_key": "AKIAJBRHKV6EVTTNXDHA", 475 "secret_key": "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", 476 } 477 478 stepCreate := logicaltest.TestStep{ 479 Operation: logical.CreateOperation, 480 Path: "config/client", 481 Data: data, 482 } 483 484 stepUpdate := logicaltest.TestStep{ 485 Operation: logical.UpdateOperation, 486 Path: "config/client", 487 Data: data, 488 } 489 490 data3 := map[string]interface{}{"access_key": "", 491 "secret_key": "mCtSM8ZUEQ3mOFVZYPBQkf2sO6F/W7a5TVzrl3Oj", 492 } 493 stepInvalidAccessKey := logicaltest.TestStep{ 494 Operation: logical.UpdateOperation, 495 Path: "config/client", 496 Data: data3, 497 ErrorOk: true, 498 } 499 500 data4 := map[string]interface{}{"access_key": "accesskey", 501 "secret_key": "", 502 } 503 stepInvalidSecretKey := logicaltest.TestStep{ 504 Operation: logical.UpdateOperation, 505 Path: "config/client", 506 Data: data4, 507 ErrorOk: true, 508 } 509 510 logicaltest.Test(t, logicaltest.TestCase{ 511 AcceptanceTest: false, 512 CredentialBackend: b, 513 Steps: []logicaltest.TestStep{ 514 stepCreate, 515 stepInvalidAccessKey, 516 stepInvalidSecretKey, 517 stepUpdate, 518 }, 519 }) 520 521 // test existence check returning false 522 checkFound, exists, err := b.HandleExistenceCheck(context.Background(), &logical.Request{ 523 Operation: logical.CreateOperation, 524 Path: "config/client", 525 Storage: storage, 526 }) 527 if err != nil { 528 t.Fatal(err) 529 } 530 if !checkFound { 531 t.Fatal("existence check not found for path 'config/client'") 532 } 533 if exists { 534 t.Fatal("existence check should have returned 'false' for 'config/client'") 535 } 536 537 // create an entry 538 configClientCreateRequest := &logical.Request{ 539 Operation: logical.UpdateOperation, 540 Path: "config/client", 541 Data: data, 542 Storage: storage, 543 } 544 _, err = b.HandleRequest(context.Background(), configClientCreateRequest) 545 if err != nil { 546 t.Fatal(err) 547 } 548 549 //test existence check returning true 550 checkFound, exists, err = b.HandleExistenceCheck(context.Background(), &logical.Request{ 551 Operation: logical.CreateOperation, 552 Path: "config/client", 553 Storage: storage, 554 }) 555 if err != nil { 556 t.Fatal(err) 557 } 558 if !checkFound { 559 t.Fatal("existence check not found for path 'config/client'") 560 } 561 if !exists { 562 t.Fatal("existence check should have returned 'true' for 'config/client'") 563 } 564 565 endpointData := map[string]interface{}{ 566 "secret_key": "secretkey", 567 "access_key": "accesskey", 568 "endpoint": "endpointvalue", 569 } 570 571 endpointReq := &logical.Request{ 572 Operation: logical.UpdateOperation, 573 Path: "config/client", 574 Storage: storage, 575 Data: endpointData, 576 } 577 _, err = b.HandleRequest(context.Background(), endpointReq) 578 if err != nil { 579 t.Fatal(err) 580 } 581 582 endpointReq.Operation = logical.ReadOperation 583 resp, err := b.HandleRequest(context.Background(), endpointReq) 584 if err != nil { 585 t.Fatal(err) 586 } 587 if resp == nil || 588 resp.IsError() { 589 t.Fatalf("") 590 } 591 actual := resp.Data["endpoint"].(string) 592 if actual != "endpointvalue" { 593 t.Fatalf("bad: endpoint: expected:endpointvalue actual:%s\n", actual) 594 } 595} 596 597func TestBackend_pathConfigCertificate(t *testing.T) { 598 config := logical.TestBackendConfig() 599 storage := &logical.InmemStorage{} 600 config.StorageView = storage 601 602 b, err := Backend(config) 603 if err != nil { 604 t.Fatal(err) 605 } 606 607 err = b.Setup(context.Background(), config) 608 if err != nil { 609 t.Fatal(err) 610 } 611 612 certReq := &logical.Request{ 613 Operation: logical.CreateOperation, 614 Storage: storage, 615 Path: "config/certificate/cert1", 616 } 617 checkFound, exists, err := b.HandleExistenceCheck(context.Background(), certReq) 618 if err != nil { 619 t.Fatal(err) 620 } 621 if !checkFound { 622 t.Fatal("existence check not found for path 'config/certificate/cert1'") 623 } 624 if exists { 625 t.Fatal("existence check should have returned 'false' for 'config/certificate/cert1'") 626 } 627 628 data := map[string]interface{}{ 629 "type": "pkcs7", 630 "aws_public_cert": `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM3VENDQXEwQ0NRQ1d1a2paNVY0YVp6QUpC 631Z2NxaGtqT09BUURNRnd4Q3pBSkJnTlZCQVlUQWxWVE1Sa3cKRndZRFZRUUlFeEJYWVhOb2FXNW5k 632Rzl1SUZOMFlYUmxNUkF3RGdZRFZRUUhFd2RUWldGMGRHeGxNU0F3SGdZRApWUVFLRXhkQmJXRjZi 633MjRnVjJWaUlGTmxjblpwWTJWeklFeE1RekFlRncweE1qQXhNRFV4TWpVMk1USmFGdzB6Ck9EQXhN 634RFV4TWpVMk1USmFNRnd4Q3pBSkJnTlZCQVlUQWxWVE1Sa3dGd1lEVlFRSUV4QlhZWE5vYVc1bmRH 635OXUKSUZOMFlYUmxNUkF3RGdZRFZRUUhFd2RUWldGMGRHeGxNU0F3SGdZRFZRUUtFeGRCYldGNmIy 636NGdWMlZpSUZObApjblpwWTJWeklFeE1RekNDQWJjd2dnRXNCZ2NxaGtqT09BUUJNSUlCSHdLQmdR 637Q2prdmNTMmJiMVZRNHl0LzVlCmloNU9PNmtLL24xTHpsbHI3RDhad3RRUDhmT0VwcDVFMm5nK0Q2 638VWQxWjFnWWlwcjU4S2ozbnNzU05wSTZiWDMKVnlJUXpLN3dMY2xuZC9Zb3pxTk5tZ0l5WmVjTjdF 639Z2xLOUlUSEpMUCt4OEZ0VXB0M1FieVlYSmRtVk1lZ042UApodmlZdDVKSC9uWWw0aGgzUGExSEpk 640c2tnUUlWQUxWSjNFUjExK0tvNHRQNm53dkh3aDYrRVJZUkFvR0JBSTFqCmsrdGtxTVZIdUFGY3ZB 641R0tvY1Rnc2pKZW02LzVxb216SnVLRG1iSk51OVF4dzNyQW90WGF1OFFlK01CY0psL1UKaGh5MUtI 642VnBDR2w5ZnVlUTJzNklMMENhTy9idXljVTFDaVlRazQwS05IQ2NIZk5pWmJkbHgxRTlycFVwN2Ju 643RgpsUmEydjFudE1YM2NhUlZEZGJ0UEVXbWR4U0NZc1lGRGs0bVpyT0xCQTRHRUFBS0JnRWJtZXZl 644NWY4TElFL0dmCk1ObVA5Q001ZW92UU9HeDVobzhXcUQrYVRlYnMrazJ0bjkyQkJQcWVacXBXUmE1 645UC8ranJkS21sMXF4NGxsSFcKTVhyczNJZ0liNitoVUlCK1M4ZHo4L21tTzBicHI3NlJvWlZDWFlh 646YjJDWmVkRnV0N3FjM1dVSDkrRVVBSDVtdwp2U2VEQ09VTVlRUjdSOUxJTll3b3VISXppcVFZTUFr 647R0J5cUdTTTQ0QkFNREx3QXdMQUlVV1hCbGs0MHhUd1N3CjdIWDMyTXhYWXJ1c2U5QUNGQk5HbWRY 648MlpCclZOR3JOOU4yZjZST2swazlLCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 649`, 650 } 651 652 certReq.Data = data 653 // test create operation 654 resp, err := b.HandleRequest(context.Background(), certReq) 655 if err != nil || (resp != nil && resp.IsError()) { 656 t.Fatalf("resp: %#v, err: %v", resp, err) 657 } 658 659 certReq.Data = nil 660 // test existence check 661 checkFound, exists, err = b.HandleExistenceCheck(context.Background(), certReq) 662 if err != nil { 663 t.Fatal(err) 664 } 665 if !checkFound { 666 t.Fatal("existence check not found for path 'config/certificate/cert1'") 667 } 668 if !exists { 669 t.Fatal("existence check should have returned 'true' for 'config/certificate/cert1'") 670 } 671 672 certReq.Operation = logical.ReadOperation 673 // test read operation 674 resp, err = b.HandleRequest(context.Background(), certReq) 675 if err != nil { 676 t.Fatal(err) 677 } 678 expectedCert := `-----BEGIN CERTIFICATE----- 679MIIC7TCCAq0CCQCWukjZ5V4aZzAJBgcqhkjOOAQDMFwxCzAJBgNVBAYTAlVTMRkw 680FwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYD 681VQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0xMjAxMDUxMjU2MTJaFw0z 682ODAxMDUxMjU2MTJaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9u 683IFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNl 684cnZpY2VzIExMQzCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCjkvcS2bb1VQ4yt/5e 685ih5OO6kK/n1Lzllr7D8ZwtQP8fOEpp5E2ng+D6Ud1Z1gYipr58Kj3nssSNpI6bX3 686VyIQzK7wLclnd/YozqNNmgIyZecN7EglK9ITHJLP+x8FtUpt3QbyYXJdmVMegN6P 687hviYt5JH/nYl4hh3Pa1HJdskgQIVALVJ3ER11+Ko4tP6nwvHwh6+ERYRAoGBAI1j 688k+tkqMVHuAFcvAGKocTgsjJem6/5qomzJuKDmbJNu9Qxw3rAotXau8Qe+MBcJl/U 689hhy1KHVpCGl9fueQ2s6IL0CaO/buycU1CiYQk40KNHCcHfNiZbdlx1E9rpUp7bnF 690lRa2v1ntMX3caRVDdbtPEWmdxSCYsYFDk4mZrOLBA4GEAAKBgEbmeve5f8LIE/Gf 691MNmP9CM5eovQOGx5ho8WqD+aTebs+k2tn92BBPqeZqpWRa5P/+jrdKml1qx4llHW 692MXrs3IgIb6+hUIB+S8dz8/mmO0bpr76RoZVCXYab2CZedFut7qc3WUH9+EUAH5mw 693vSeDCOUMYQR7R9LINYwouHIziqQYMAkGByqGSM44BAMDLwAwLAIUWXBlk40xTwSw 6947HX32MxXYruse9ACFBNGmdX2ZBrVNGrN9N2f6ROk0k9K 695-----END CERTIFICATE----- 696` 697 if resp.Data["aws_public_cert"].(string) != expectedCert { 698 t.Fatalf("bad: expected:%s\n got:%s\n", expectedCert, resp.Data["aws_public_cert"].(string)) 699 } 700 701 certReq.Operation = logical.CreateOperation 702 certReq.Path = "config/certificate/cert2" 703 certReq.Data = data 704 // create another entry to test the list operation 705 _, err = b.HandleRequest(context.Background(), certReq) 706 if err != nil { 707 t.Fatal(err) 708 } 709 710 certReq.Operation = logical.ListOperation 711 certReq.Path = "config/certificates" 712 // test list operation 713 resp, err = b.HandleRequest(context.Background(), certReq) 714 if err != nil { 715 t.Fatal(err) 716 } 717 if resp == nil || resp.IsError() { 718 t.Fatalf("failed to list config/certificates") 719 } 720 keys := resp.Data["keys"].([]string) 721 if len(keys) != 2 { 722 t.Fatalf("invalid keys listed: %#v\n", keys) 723 } 724 725 certReq.Operation = logical.DeleteOperation 726 certReq.Path = "config/certificate/cert1" 727 _, err = b.HandleRequest(context.Background(), certReq) 728 if err != nil { 729 t.Fatal(err) 730 } 731 732 certReq.Path = "config/certificate/cert2" 733 _, err = b.HandleRequest(context.Background(), certReq) 734 if err != nil { 735 t.Fatal(err) 736 } 737 738 certReq.Operation = logical.ListOperation 739 certReq.Path = "config/certificates" 740 // test list operation 741 resp, err = b.HandleRequest(context.Background(), certReq) 742 if err != nil { 743 t.Fatal(err) 744 } 745 if resp == nil || resp.IsError() { 746 t.Fatalf("failed to list config/certificates") 747 } 748 if resp.Data["keys"] != nil { 749 t.Fatalf("no entries should be present") 750 } 751} 752 753func TestBackend_parseAndVerifyRoleTagValue(t *testing.T) { 754 // create a backend 755 config := logical.TestBackendConfig() 756 storage := &logical.InmemStorage{} 757 config.StorageView = storage 758 b, err := Backend(config) 759 if err != nil { 760 t.Fatal(err) 761 } 762 763 err = b.Setup(context.Background(), config) 764 if err != nil { 765 t.Fatal(err) 766 } 767 768 // create a role 769 data := map[string]interface{}{ 770 "auth_type": "ec2", 771 "policies": "p,q,r,s", 772 "max_ttl": "120s", 773 "role_tag": "VaultRole", 774 "bound_ami_id": "abcd-123", 775 } 776 resp, err := b.HandleRequest(context.Background(), &logical.Request{ 777 Operation: logical.CreateOperation, 778 Path: "role/abcd-123", 779 Storage: storage, 780 Data: data, 781 }) 782 if resp != nil && resp.IsError() { 783 t.Fatalf("failed to create role") 784 } 785 if err != nil { 786 t.Fatal(err) 787 } 788 789 // verify that the entry is created 790 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 791 Operation: logical.ReadOperation, 792 Path: "role/abcd-123", 793 Storage: storage, 794 }) 795 if err != nil { 796 t.Fatal(err) 797 } 798 if resp == nil { 799 t.Fatalf("expected an role entry for abcd-123") 800 } 801 802 // create a role tag 803 data2 := map[string]interface{}{ 804 "policies": "p,q,r,s", 805 } 806 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 807 Operation: logical.UpdateOperation, 808 Path: "role/abcd-123/tag", 809 Storage: storage, 810 Data: data2, 811 }) 812 if err != nil { 813 t.Fatal(err) 814 } 815 if resp.Data["tag_key"].(string) == "" || 816 resp.Data["tag_value"].(string) == "" { 817 t.Fatalf("invalid tag response: %#v\n", resp) 818 } 819 tagValue := resp.Data["tag_value"].(string) 820 821 // parse the value and check if the verifiable values match 822 rTag, err := b.parseAndVerifyRoleTagValue(context.Background(), storage, tagValue) 823 if err != nil { 824 t.Fatalf("err: %s", err) 825 } 826 if rTag == nil { 827 t.Fatalf("failed to parse role tag") 828 } 829 if rTag.Version != "v1" || 830 !policyutil.EquivalentPolicies(rTag.Policies, []string{"p", "q", "r", "s"}) || 831 rTag.Role != "abcd-123" { 832 t.Fatalf("bad: parsed role tag contains incorrect values. Got: %#v\n", rTag) 833 } 834} 835 836func TestBackend_PathRoleTag(t *testing.T) { 837 config := logical.TestBackendConfig() 838 storage := &logical.InmemStorage{} 839 config.StorageView = storage 840 b, err := Backend(config) 841 if err != nil { 842 t.Fatal(err) 843 } 844 845 err = b.Setup(context.Background(), config) 846 if err != nil { 847 t.Fatal(err) 848 } 849 850 data := map[string]interface{}{ 851 "auth_type": "ec2", 852 "policies": "p,q,r,s", 853 "max_ttl": "120s", 854 "role_tag": "VaultRole", 855 "bound_ami_id": "abcd-123", 856 } 857 resp, err := b.HandleRequest(context.Background(), &logical.Request{ 858 Operation: logical.CreateOperation, 859 Path: "role/abcd-123", 860 Storage: storage, 861 Data: data, 862 }) 863 if resp != nil && resp.IsError() { 864 t.Fatalf("failed to create role") 865 } 866 if err != nil { 867 t.Fatal(err) 868 } 869 870 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 871 Operation: logical.ReadOperation, 872 Path: "role/abcd-123", 873 Storage: storage, 874 }) 875 if err != nil { 876 t.Fatal(err) 877 } 878 if resp == nil { 879 t.Fatalf("failed to find a role entry for abcd-123") 880 } 881 882 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 883 Operation: logical.UpdateOperation, 884 Path: "role/abcd-123/tag", 885 Storage: storage, 886 }) 887 if err != nil { 888 t.Fatal(err) 889 } 890 if resp == nil || resp.Data == nil { 891 t.Fatalf("failed to create a tag on role: abcd-123") 892 } 893 if resp.IsError() { 894 t.Fatalf("failed to create a tag on role: abcd-123: %s\n", resp.Data["error"]) 895 } 896 if resp.Data["tag_value"].(string) == "" { 897 t.Fatalf("role tag not present in the response data: %#v\n", resp.Data) 898 } 899} 900 901func TestBackend_PathBlacklistRoleTag(t *testing.T) { 902 // create the backend 903 storage := &logical.InmemStorage{} 904 config := logical.TestBackendConfig() 905 config.StorageView = storage 906 b, err := Backend(config) 907 if err != nil { 908 t.Fatal(err) 909 } 910 911 err = b.Setup(context.Background(), config) 912 if err != nil { 913 t.Fatal(err) 914 } 915 916 // create an role entry 917 data := map[string]interface{}{ 918 "auth_type": "ec2", 919 "policies": "p,q,r,s", 920 "role_tag": "VaultRole", 921 "bound_ami_id": "abcd-123", 922 } 923 resp, err := b.HandleRequest(context.Background(), &logical.Request{ 924 Operation: logical.CreateOperation, 925 Path: "role/abcd-123", 926 Storage: storage, 927 Data: data, 928 }) 929 if resp != nil && resp.IsError() { 930 t.Fatalf("failed to create role") 931 } 932 if err != nil { 933 t.Fatal(err) 934 } 935 936 // create a role tag against an role registered before 937 data2 := map[string]interface{}{ 938 "policies": "p,q,r,s", 939 } 940 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 941 Operation: logical.UpdateOperation, 942 Path: "role/abcd-123/tag", 943 Storage: storage, 944 Data: data2, 945 }) 946 if err != nil { 947 t.Fatal(err) 948 } 949 if resp == nil || resp.Data == nil { 950 t.Fatalf("failed to create a tag on role: abcd-123") 951 } 952 if resp.IsError() { 953 t.Fatalf("failed to create a tag on role: abcd-123: %s\n", resp.Data["error"]) 954 } 955 tag := resp.Data["tag_value"].(string) 956 if tag == "" { 957 t.Fatalf("role tag not present in the response data: %#v\n", resp.Data) 958 } 959 960 // blacklist that role tag 961 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 962 Operation: logical.UpdateOperation, 963 Path: "roletag-blacklist/" + tag, 964 Storage: storage, 965 }) 966 if err != nil { 967 t.Fatal(err) 968 } 969 if resp != nil { 970 t.Fatalf("failed to blacklist the roletag: %s\n", tag) 971 } 972 973 // read the blacklist entry 974 resp, err = b.HandleRequest(context.Background(), &logical.Request{ 975 Operation: logical.ReadOperation, 976 Path: "roletag-blacklist/" + tag, 977 Storage: storage, 978 }) 979 if err != nil { 980 t.Fatal(err) 981 } 982 if resp == nil || resp.Data == nil { 983 t.Fatalf("failed to read the blacklisted role tag: %s\n", tag) 984 } 985 if resp.IsError() { 986 t.Fatalf("failed to read the blacklisted role tag:%s. Err: %s\n", tag, resp.Data["error"]) 987 } 988 989 // delete the blacklisted entry 990 _, err = b.HandleRequest(context.Background(), &logical.Request{ 991 Operation: logical.DeleteOperation, 992 Path: "roletag-blacklist/" + tag, 993 Storage: storage, 994 }) 995 if err != nil { 996 t.Fatal(err) 997 } 998 999 // try to read the deleted entry 1000 tagEntry, err := b.lockedBlacklistRoleTagEntry(context.Background(), storage, tag) 1001 if err != nil { 1002 t.Fatal(err) 1003 } 1004 if tagEntry != nil { 1005 t.Fatalf("role tag should not have been present: %s\n", tag) 1006 } 1007} 1008 1009/* This is an acceptance test. 1010 Requires the following env vars: 1011 TEST_AWS_EC2_PKCS7 1012 TEST_AWS_EC2_IDENTITY_DOCUMENT 1013 TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG 1014 TEST_AWS_EC2_AMI_ID 1015 TEST_AWS_EC2_ACCOUNT_ID 1016 TEST_AWS_EC2_IAM_ROLE_ARN 1017 1018 If this is being run on an EC2 instance, you can set the environment vars using this bash snippet: 1019 1020 export TEST_AWS_EC2_PKCS7=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/pkcs7) 1021 export TEST_AWS_EC2_IDENTITY_DOCUMENT=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | base64 -w 0) 1022 export TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/signature | tr -d '\n') 1023 export TEST_AWS_EC2_AMI_ID=$(curl -s http://169.254.169.254/latest/meta-data/ami-id) 1024 export TEST_AWS_EC2_IAM_ROLE_ARN=$(aws iam get-role --role-name $(curl -q http://169.254.169.254/latest/meta-data/iam/security-credentials/ -S -s) --query Role.Arn --output text) 1025 export TEST_AWS_EC2_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) 1026 1027 If the test is not being run on an EC2 instance that has access to 1028 credentials using EC2RoleProvider, on top of the above vars, following 1029 needs to be set: 1030 TEST_AWS_SECRET_KEY 1031 TEST_AWS_ACCESS_KEY 1032*/ 1033func TestBackendAcc_LoginWithInstanceIdentityDocAndWhitelistIdentity(t *testing.T) { 1034 // This test case should be run only when certain env vars are set and 1035 // executed as an acceptance test. 1036 if os.Getenv(logicaltest.TestEnvVar) == "" { 1037 t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar)) 1038 return 1039 } 1040 1041 pkcs7 := os.Getenv("TEST_AWS_EC2_PKCS7") 1042 if pkcs7 == "" { 1043 t.Skipf("env var TEST_AWS_EC2_PKCS7 not set, skipping test") 1044 } 1045 1046 identityDoc := os.Getenv("TEST_AWS_EC2_IDENTITY_DOCUMENT") 1047 if identityDoc == "" { 1048 t.Skipf("env var TEST_AWS_EC2_IDENTITY_DOCUMENT not set, skipping test") 1049 } 1050 1051 identityDocSig := os.Getenv("TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG") 1052 if identityDocSig == "" { 1053 t.Skipf("env var TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG not set, skipping test") 1054 } 1055 1056 amiID := os.Getenv("TEST_AWS_EC2_AMI_ID") 1057 if amiID == "" { 1058 t.Skipf("env var TEST_AWS_EC2_AMI_ID not set, skipping test") 1059 } 1060 1061 iamARN := os.Getenv("TEST_AWS_EC2_IAM_ROLE_ARN") 1062 if iamARN == "" { 1063 t.Skipf("env var TEST_AWS_EC2_IAM_ROLE_ARN not set, skipping test") 1064 } 1065 1066 accountID := os.Getenv("TEST_AWS_EC2_ACCOUNT_ID") 1067 if accountID == "" { 1068 t.Skipf("env var TEST_AWS_EC2_ACCOUNT_ID not set, skipping test") 1069 } 1070 1071 roleName := amiID 1072 1073 // create the backend 1074 storage := &logical.InmemStorage{} 1075 config := logical.TestBackendConfig() 1076 config.StorageView = storage 1077 b, err := Backend(config) 1078 if err != nil { 1079 t.Fatal(err) 1080 } 1081 1082 err = b.Setup(context.Background(), config) 1083 if err != nil { 1084 t.Fatal(err) 1085 } 1086 1087 accessKey := os.Getenv("TEST_AWS_ACCESS_KEY") 1088 secretKey := os.Getenv("TEST_AWS_SECRET_KEY") 1089 1090 // In case of problems with making API calls using the credentials (2FA enabled, 1091 // for instance), the keys need not be set if the test is running on an EC2 1092 // instance with permissions to get the credentials using EC2RoleProvider. 1093 if accessKey != "" && secretKey != "" { 1094 // get the API credentials from env vars 1095 clientConfig := map[string]interface{}{ 1096 "access_key": accessKey, 1097 "secret_key": secretKey, 1098 } 1099 if clientConfig["access_key"] == "" || 1100 clientConfig["secret_key"] == "" { 1101 t.Fatalf("credentials not configured") 1102 } 1103 1104 // store the credentials 1105 _, err = b.HandleRequest(context.Background(), &logical.Request{ 1106 Operation: logical.UpdateOperation, 1107 Storage: storage, 1108 Path: "config/client", 1109 Data: clientConfig, 1110 }) 1111 if err != nil { 1112 t.Fatal(err) 1113 } 1114 } 1115 1116 loginInput := map[string]interface{}{ 1117 "pkcs7": pkcs7, 1118 "nonce": "vault-client-nonce", 1119 } 1120 1121 parsedIdentityDoc, err := b.parseIdentityDocument(context.Background(), storage, pkcs7) 1122 if err != nil { 1123 t.Fatal(err) 1124 } 1125 1126 // Perform the login operation with a AMI ID that is not matching 1127 // the bound on the role. 1128 loginRequest := &logical.Request{ 1129 Operation: logical.UpdateOperation, 1130 Path: "login", 1131 Storage: storage, 1132 Data: loginInput, 1133 } 1134 1135 // Baseline role data that should succeed permit login 1136 data := map[string]interface{}{ 1137 "auth_type": "ec2", 1138 "policies": "root", 1139 "max_ttl": "120s", 1140 "bound_ami_id": []string{"wrong_ami_id", amiID, "wrong_ami_id2"}, 1141 "bound_account_id": accountID, 1142 "bound_iam_role_arn": iamARN, 1143 "bound_ec2_instance_id": []string{parsedIdentityDoc.InstanceID, "i-1234567"}, 1144 } 1145 1146 roleReq := &logical.Request{ 1147 Operation: logical.CreateOperation, 1148 Path: "role/" + roleName, 1149 Storage: storage, 1150 Data: data, 1151 } 1152 1153 updateRoleExpectLoginFail := func(roleRequest, loginRequest *logical.Request) error { 1154 resp, err := b.HandleRequest(context.Background(), roleRequest) 1155 if err != nil || (resp != nil && resp.IsError()) { 1156 return fmt.Errorf("bad: failed to create role: resp:%#v\nerr:%v", resp, err) 1157 } 1158 resp, err = b.HandleRequest(context.Background(), loginRequest) 1159 if err != nil || resp == nil || (resp != nil && !resp.IsError()) { 1160 return fmt.Errorf("bad: expected login failure: resp:%#v\nerr:%v", resp, err) 1161 } 1162 return nil 1163 } 1164 1165 // Test a role with the wrong AMI ID 1166 data["bound_ami_id"] = []string{"ami-1234567", "ami-7654321"} 1167 if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil { 1168 t.Fatal(err) 1169 } 1170 1171 roleReq.Operation = logical.UpdateOperation 1172 // Place the correct AMI ID in one of the values, but make the AccountID wrong 1173 data["bound_ami_id"] = []string{"wrong_ami_id_1", amiID, "wrong_ami_id_2"} 1174 data["bound_account_id"] = []string{"wrong-account-id", "wrong-account-id-2"} 1175 if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil { 1176 t.Fatal(err) 1177 } 1178 1179 // Place the correct AccountID in one of the values, but make the wrong IAMRoleARN 1180 data["bound_account_id"] = []string{"wrong-account-id-1", accountID, "wrong-account-id-2"} 1181 data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn", "wrong_iam_role_arn_2"} 1182 if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil { 1183 t.Fatal(err) 1184 } 1185 1186 // Place correct IAM role ARN, but incorrect instance ID 1187 data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn_1", iamARN, "wrong_iam_role_arn_2"} 1188 data["bound_ec2_instance_id"] = "i-1234567" 1189 if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil { 1190 t.Fatal(err) 1191 } 1192 1193 // Place correct instance ID, but substring of the IAM role ARN 1194 data["bound_ec2_instance_id"] = []string{parsedIdentityDoc.InstanceID, "i-1234567"} 1195 data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn", iamARN[:len(iamARN)-2], "wrong_iam_role_arn_2"} 1196 if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil { 1197 t.Fatal(err) 1198 } 1199 1200 // place a wildcard in the middle of the role ARN 1201 // The :31 gets arn:aws:iam::123456789012:role/ 1202 // This test relies on the role name having at least two characters 1203 data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn", fmt.Sprintf("%s*%s", iamARN[:31], iamARN[32:])} 1204 if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil { 1205 t.Fatal(err) 1206 } 1207 1208 // globbed IAM role ARN 1209 data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn_1", fmt.Sprintf("%s*", iamARN[:len(iamARN)-2]), "wrong_iam_role_arn_2"} 1210 resp, err := b.HandleRequest(context.Background(), roleReq) 1211 if err != nil || (resp != nil && resp.IsError()) { 1212 t.Fatalf("bad: failed to create role: resp:%#v\nerr:%v", resp, err) 1213 } 1214 1215 // Now, the login attempt should succeed 1216 resp, err = b.HandleRequest(context.Background(), loginRequest) 1217 if err != nil { 1218 t.Fatal(err) 1219 } 1220 if resp == nil || resp.Auth == nil || resp.IsError() { 1221 t.Fatalf("bad: failed to login: resp:%#v\nerr:%v", resp, err) 1222 } 1223 1224 // Attempt to re-login with the identity signature 1225 delete(loginInput, "pkcs7") 1226 loginInput["identity"] = identityDoc 1227 loginInput["signature"] = identityDocSig 1228 resp, err = b.HandleRequest(context.Background(), loginRequest) 1229 if err != nil { 1230 t.Fatal(err) 1231 } 1232 if resp == nil || resp.Auth == nil || resp.IsError() { 1233 t.Fatalf("bad: failed to login: resp:%#v\nerr:%v", resp, err) 1234 } 1235 1236 // verify the presence of instance_id in the response object. 1237 instanceID := resp.Auth.Metadata["instance_id"] 1238 if instanceID == "" { 1239 t.Fatalf("instance ID not present in the response object") 1240 } 1241 if instanceID != parsedIdentityDoc.InstanceID { 1242 t.Fatalf("instance ID in response (%q) did not match instance ID from identity document (%q)", instanceID, parsedIdentityDoc.InstanceID) 1243 } 1244 1245 _, ok := resp.Auth.Metadata["nonce"] 1246 if ok { 1247 t.Fatalf("client nonce should not have been returned") 1248 } 1249 1250 loginInput["nonce"] = "changed-vault-client-nonce" 1251 // try to login again with changed nonce 1252 resp, err = b.HandleRequest(context.Background(), loginRequest) 1253 if err != nil { 1254 t.Fatal(err) 1255 } 1256 if resp == nil || !resp.IsError() { 1257 t.Fatalf("login attempt should have failed due to client nonce mismatch") 1258 } 1259 1260 // Check if a whitelist identity entry is created after the login. 1261 wlRequest := &logical.Request{ 1262 Operation: logical.ReadOperation, 1263 Path: "identity-whitelist/" + instanceID, 1264 Storage: storage, 1265 } 1266 resp, err = b.HandleRequest(context.Background(), wlRequest) 1267 if err != nil { 1268 t.Fatal(err) 1269 } 1270 if resp == nil || resp.Data == nil || resp.Data["role"] != roleName { 1271 t.Fatalf("failed to read whitelist identity") 1272 } 1273 1274 // Delete the whitelist identity entry. 1275 wlRequest.Operation = logical.DeleteOperation 1276 resp, err = b.HandleRequest(context.Background(), wlRequest) 1277 if err != nil { 1278 t.Fatal(err) 1279 } 1280 if resp.IsError() { 1281 t.Fatalf("failed to delete whitelist identity") 1282 } 1283 1284 // Allow a fresh login without supplying the nonce 1285 delete(loginInput, "nonce") 1286 1287 resp, err = b.HandleRequest(context.Background(), loginRequest) 1288 if err != nil { 1289 t.Fatal(err) 1290 } 1291 if resp == nil || resp.Auth == nil || resp.IsError() { 1292 t.Fatalf("login attempt failed") 1293 } 1294 1295 _, ok = resp.Auth.Metadata["nonce"] 1296 if !ok { 1297 t.Fatalf("expected nonce to be returned") 1298 } 1299} 1300 1301func TestBackend_pathStsConfig(t *testing.T) { 1302 config := logical.TestBackendConfig() 1303 storage := &logical.InmemStorage{} 1304 config.StorageView = storage 1305 b, err := Backend(config) 1306 if err != nil { 1307 t.Fatal(err) 1308 } 1309 1310 err = b.Setup(context.Background(), config) 1311 if err != nil { 1312 t.Fatal(err) 1313 } 1314 stsReq := &logical.Request{ 1315 Operation: logical.CreateOperation, 1316 Storage: storage, 1317 Path: "config/sts/account1", 1318 } 1319 checkFound, exists, err := b.HandleExistenceCheck(context.Background(), stsReq) 1320 if err != nil { 1321 t.Fatal(err) 1322 } 1323 if !checkFound { 1324 t.Fatal("existence check not found for path 'config/sts/account1'") 1325 } 1326 if exists { 1327 t.Fatal("existence check should have returned 'false' for 'config/sts/account1'") 1328 } 1329 1330 data := map[string]interface{}{ 1331 "sts_role": "arn:aws:iam:account1:role/myRole", 1332 } 1333 1334 stsReq.Data = data 1335 // test create operation 1336 resp, err := b.HandleRequest(context.Background(), stsReq) 1337 if err != nil || (resp != nil && resp.IsError()) { 1338 t.Fatalf("resp: %#v, err: %v", resp, err) 1339 } 1340 1341 stsReq.Data = nil 1342 // test existence check 1343 checkFound, exists, err = b.HandleExistenceCheck(context.Background(), stsReq) 1344 if err != nil { 1345 t.Fatal(err) 1346 } 1347 if !checkFound { 1348 t.Fatal("existence check not found for path 'config/sts/account1'") 1349 } 1350 if !exists { 1351 t.Fatal("existence check should have returned 'true' for 'config/sts/account1'") 1352 } 1353 1354 stsReq.Operation = logical.ReadOperation 1355 // test read operation 1356 resp, err = b.HandleRequest(context.Background(), stsReq) 1357 if err != nil { 1358 t.Fatal(err) 1359 } 1360 expectedStsRole := "arn:aws:iam:account1:role/myRole" 1361 if resp.Data["sts_role"].(string) != expectedStsRole { 1362 t.Fatalf("bad: expected:%s\n got:%s\n", expectedStsRole, resp.Data["sts_role"].(string)) 1363 } 1364 1365 stsReq.Operation = logical.CreateOperation 1366 stsReq.Path = "config/sts/account2" 1367 stsReq.Data = data 1368 // create another entry to test the list operation 1369 resp, err = b.HandleRequest(context.Background(), stsReq) 1370 if err != nil || (resp != nil && resp.IsError()) { 1371 t.Fatal(err) 1372 } 1373 1374 stsReq.Operation = logical.ListOperation 1375 stsReq.Path = "config/sts" 1376 // test list operation 1377 resp, err = b.HandleRequest(context.Background(), stsReq) 1378 if err != nil { 1379 t.Fatal(err) 1380 } 1381 if resp == nil || resp.IsError() { 1382 t.Fatalf("failed to list config/sts") 1383 } 1384 keys := resp.Data["keys"].([]string) 1385 if len(keys) != 2 { 1386 t.Fatalf("invalid keys listed: %#v\n", keys) 1387 } 1388 1389 stsReq.Operation = logical.DeleteOperation 1390 stsReq.Path = "config/sts/account1" 1391 resp, err = b.HandleRequest(context.Background(), stsReq) 1392 if err != nil || (resp != nil && resp.IsError()) { 1393 t.Fatal(err) 1394 } 1395 1396 stsReq.Path = "config/sts/account2" 1397 resp, err = b.HandleRequest(context.Background(), stsReq) 1398 if err != nil || (resp != nil && resp.IsError()) { 1399 t.Fatal(err) 1400 } 1401 1402 stsReq.Operation = logical.ListOperation 1403 stsReq.Path = "config/sts" 1404 // test list operation 1405 resp, err = b.HandleRequest(context.Background(), stsReq) 1406 if err != nil { 1407 t.Fatal(err) 1408 } 1409 if resp == nil || resp.IsError() { 1410 t.Fatalf("failed to list config/sts") 1411 } 1412 if resp.Data["keys"] != nil { 1413 t.Fatalf("no entries should be present") 1414 } 1415} 1416 1417func buildCallerIdentityLoginData(request *http.Request, roleName string) (map[string]interface{}, error) { 1418 headersJson, err := json.Marshal(request.Header) 1419 if err != nil { 1420 return nil, err 1421 } 1422 requestBody, err := ioutil.ReadAll(request.Body) 1423 if err != nil { 1424 return nil, err 1425 } 1426 return map[string]interface{}{ 1427 "iam_http_request_method": request.Method, 1428 "iam_request_url": base64.StdEncoding.EncodeToString([]byte(request.URL.String())), 1429 "iam_request_headers": base64.StdEncoding.EncodeToString(headersJson), 1430 "iam_request_body": base64.StdEncoding.EncodeToString(requestBody), 1431 "request_role": roleName, 1432 }, nil 1433} 1434 1435// This is an acceptance test. 1436// If the test is NOT being run on an AWS EC2 instance in an instance profile, 1437// it requires the following environment variables to be set: 1438// TEST_AWS_ACCESS_KEY_ID 1439// TEST_AWS_SECRET_ACCESS_KEY 1440// TEST_AWS_SECURITY_TOKEN or TEST_AWS_SESSION_TOKEN (optional, if you are using short-lived creds) 1441// These are intentionally NOT the "standard" variables to prevent accidentally 1442// using prod creds in acceptance tests 1443func TestBackendAcc_LoginWithCallerIdentity(t *testing.T) { 1444 // This test case should be run only when certain env vars are set and 1445 // executed as an acceptance test. 1446 if os.Getenv(logicaltest.TestEnvVar) == "" { 1447 t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar)) 1448 return 1449 } 1450 1451 storage := &logical.InmemStorage{} 1452 config := logical.TestBackendConfig() 1453 config.StorageView = storage 1454 b, err := Backend(config) 1455 if err != nil { 1456 t.Fatal(err) 1457 } 1458 1459 err = b.Setup(context.Background(), config) 1460 if err != nil { 1461 t.Fatal(err) 1462 } 1463 1464 // Override the default AWS env vars (if set) with our test creds 1465 // so that the credential provider chain will pick them up 1466 // NOTE that I'm not bothing to override the shared config file location, 1467 // so if creds are specified there, they will be used before IAM 1468 // instance profile creds 1469 // This doesn't provide perfect leakage protection (e.g., it will still 1470 // potentially pick up credentials from the ~/.config files), but probably 1471 // good enough rather than having to muck around in the low-level details 1472 for _, envvar := range []string{ 1473 "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SECURITY_TOKEN", "AWS_SESSION_TOKEN"} { 1474 // Skip test if any of the required env vars are missing 1475 testEnvVar := os.Getenv("TEST_" + envvar) 1476 if testEnvVar == "" { 1477 t.Skipf("env var %s not set, skipping test", "TEST_"+envvar) 1478 } 1479 1480 // restore existing environment variables (in case future tests need them) 1481 defer os.Setenv(envvar, os.Getenv(envvar)) 1482 1483 os.Setenv(envvar, testEnvVar) 1484 } 1485 awsSession, err := session.NewSession() 1486 if err != nil { 1487 fmt.Println("failed to create session,", err) 1488 return 1489 } 1490 1491 stsService := sts.New(awsSession) 1492 stsInputParams := &sts.GetCallerIdentityInput{} 1493 1494 testIdentity, err := stsService.GetCallerIdentity(stsInputParams) 1495 if err != nil { 1496 t.Fatalf("Received error retrieving identity: %s", err) 1497 } 1498 entity, err := parseIamArn(*testIdentity.Arn) 1499 if err != nil { 1500 t.Fatal(err) 1501 } 1502 1503 // Test setup largely done 1504 // At this point, we're going to: 1505 // 1. Configure the client to require our test header value 1506 // 2. Configure identity to use the ARN for the alias 1507 // 3. Configure two different roles: 1508 // a. One bound to our test user 1509 // b. One bound to a garbage ARN 1510 // 4. Pass in a request that doesn't have the signed header, ensure 1511 // we're not allowed to login 1512 // 5. Passin a request that has a validly signed header, but the wrong 1513 // value, ensure it doesn't allow login 1514 // 6. Pass in a request that has a validly signed request, ensure 1515 // it allows us to login to our role 1516 // 7. Pass in a request that has a validly signed request, asking for 1517 // the other role, ensure it fails 1518 1519 clientConfigData := map[string]interface{}{ 1520 "iam_server_id_header_value": testVaultHeaderValue, 1521 } 1522 clientRequest := &logical.Request{ 1523 Operation: logical.UpdateOperation, 1524 Path: "config/client", 1525 Storage: storage, 1526 Data: clientConfigData, 1527 } 1528 _, err = b.HandleRequest(context.Background(), clientRequest) 1529 if err != nil { 1530 t.Fatal(err) 1531 } 1532 1533 configIdentityData := map[string]interface{}{ 1534 "iam_alias": identityAliasIAMFullArn, 1535 } 1536 configIdentityRequest := &logical.Request{ 1537 Operation: logical.UpdateOperation, 1538 Path: "config/identity", 1539 Storage: storage, 1540 Data: configIdentityData, 1541 } 1542 resp, err := b.HandleRequest(context.Background(), configIdentityRequest) 1543 if err != nil { 1544 t.Fatal(err) 1545 } 1546 if resp != nil && resp.IsError() { 1547 t.Fatalf("received error response when configuring identity: %#v", resp) 1548 } 1549 1550 // configuring the valid role we'll be able to login to 1551 roleData := map[string]interface{}{ 1552 "bound_iam_principal_arn": []string{entity.canonicalArn(), "arn:aws:iam::123456789012:role/FakeRoleArn1*"}, // Fake ARN MUST be wildcard terminated because we're resolving unique IDs, and the wildcard termination prevents unique ID resolution 1553 "policies": "root", 1554 "auth_type": iamAuthType, 1555 } 1556 roleRequest := &logical.Request{ 1557 Operation: logical.CreateOperation, 1558 Path: "role/" + testValidRoleName, 1559 Storage: storage, 1560 Data: roleData, 1561 } 1562 resp, err = b.HandleRequest(context.Background(), roleRequest) 1563 if err != nil || (resp != nil && resp.IsError()) { 1564 t.Fatalf("bad: failed to create role: resp:%#v\nerr:%v", resp, err) 1565 } 1566 1567 // configuring a valid role we won't be able to login to 1568 roleDataEc2 := map[string]interface{}{ 1569 "auth_type": "ec2", 1570 "policies": "root", 1571 "bound_ami_id": "ami-1234567", 1572 } 1573 roleRequestEc2 := &logical.Request{ 1574 Operation: logical.CreateOperation, 1575 Path: "role/ec2only", 1576 Storage: storage, 1577 Data: roleDataEc2, 1578 } 1579 resp, err = b.HandleRequest(context.Background(), roleRequestEc2) 1580 if err != nil || (resp != nil && resp.IsError()) { 1581 t.Fatalf("bad: failed to create role; resp:%#v\nerr:%v", resp, err) 1582 } 1583 1584 fakeArn := "arn:aws:iam::123456789012:role/somePath/FakeRole" 1585 fakeArn2 := "arn:aws:iam::123456789012:role/somePath/FakeRole2" 1586 fakeArnResolverCount := 0 1587 fakeArnResolver := func(ctx context.Context, s logical.Storage, arn string) (string, error) { 1588 if strings.HasPrefix(arn, fakeArn) { 1589 fakeArnResolverCount++ 1590 return fmt.Sprintf("FakeUniqueIdFor%s%d", arn, fakeArnResolverCount), nil 1591 } 1592 return b.resolveArnToRealUniqueId(context.Background(), s, arn) 1593 } 1594 b.resolveArnToUniqueIDFunc = fakeArnResolver 1595 1596 // now we're creating the invalid role we won't be able to login to 1597 roleData["bound_iam_principal_arn"] = []string{fakeArn, fakeArn2} 1598 roleRequest.Path = "role/" + testInvalidRoleName 1599 resp, err = b.HandleRequest(context.Background(), roleRequest) 1600 if err != nil || (resp != nil && resp.IsError()) { 1601 t.Fatalf("bad: didn't fail to create role: resp:%#v\nerr:%v", resp, err) 1602 } 1603 1604 // now, create the request without the signed header 1605 stsRequestNoHeader, _ := stsService.GetCallerIdentityRequest(stsInputParams) 1606 stsRequestNoHeader.Sign() 1607 loginData, err := buildCallerIdentityLoginData(stsRequestNoHeader.HTTPRequest, testValidRoleName) 1608 if err != nil { 1609 t.Fatal(err) 1610 } 1611 loginRequest := &logical.Request{ 1612 Operation: logical.UpdateOperation, 1613 Path: "login", 1614 Storage: storage, 1615 Data: loginData, 1616 } 1617 resp, err = b.HandleRequest(context.Background(), loginRequest) 1618 if err != nil || resp == nil || !resp.IsError() { 1619 t.Errorf("bad: expected failed login due to missing header: resp:%#v\nerr:%v", resp, err) 1620 } 1621 1622 // create the request with the invalid header value 1623 1624 // Not reusing stsRequestNoHeader because the process of signing the request 1625 // and reading the body modifies the underlying request, so it's just cleaner 1626 // to get new requests. 1627 stsRequestInvalidHeader, _ := stsService.GetCallerIdentityRequest(stsInputParams) 1628 stsRequestInvalidHeader.HTTPRequest.Header.Add(iamServerIdHeader, "InvalidValue") 1629 stsRequestInvalidHeader.Sign() 1630 loginData, err = buildCallerIdentityLoginData(stsRequestInvalidHeader.HTTPRequest, testValidRoleName) 1631 if err != nil { 1632 t.Fatal(err) 1633 } 1634 loginRequest = &logical.Request{ 1635 Operation: logical.UpdateOperation, 1636 Path: "login", 1637 Storage: storage, 1638 Data: loginData, 1639 } 1640 resp, err = b.HandleRequest(context.Background(), loginRequest) 1641 if err != nil || resp == nil || !resp.IsError() { 1642 t.Errorf("bad: expected failed login due to invalid header: resp:%#v\nerr:%v", resp, err) 1643 } 1644 1645 // Now, valid request against invalid role 1646 stsRequestValid, _ := stsService.GetCallerIdentityRequest(stsInputParams) 1647 stsRequestValid.HTTPRequest.Header.Add(iamServerIdHeader, testVaultHeaderValue) 1648 stsRequestValid.Sign() 1649 loginData, err = buildCallerIdentityLoginData(stsRequestValid.HTTPRequest, testInvalidRoleName) 1650 if err != nil { 1651 t.Fatal(err) 1652 } 1653 loginRequest = &logical.Request{ 1654 Operation: logical.UpdateOperation, 1655 Path: "login", 1656 Storage: storage, 1657 Data: loginData, 1658 } 1659 resp, err = b.HandleRequest(context.Background(), loginRequest) 1660 if err != nil || resp == nil || !resp.IsError() { 1661 t.Errorf("bad: expected failed login due to invalid role: resp:%#v\nerr:%v", resp, err) 1662 } 1663 1664 loginData["role"] = "ec2only" 1665 resp, err = b.HandleRequest(context.Background(), loginRequest) 1666 if err != nil || resp == nil || !resp.IsError() { 1667 t.Errorf("bad: expected failed login due to bad auth type: resp:%#v\nerr:%v", resp, err) 1668 } 1669 1670 // finally, the happy path test :) 1671 1672 loginData["role"] = testValidRoleName 1673 resp, err = b.HandleRequest(context.Background(), loginRequest) 1674 if err != nil { 1675 t.Fatal(err) 1676 } 1677 if resp == nil || resp.Auth == nil || resp.IsError() { 1678 t.Fatalf("bad: expected valid login: resp:%#v", resp) 1679 } 1680 if resp.Auth.Alias == nil { 1681 t.Fatalf("bad: nil auth Alias") 1682 } 1683 if resp.Auth.Alias.Name != *testIdentity.Arn { 1684 t.Fatalf("bad: expected identity alias of %q, got %q instead", *testIdentity.Arn, resp.Auth.Alias.Name) 1685 } 1686 1687 renewReq := generateRenewRequest(storage, resp.Auth) 1688 // dump a fake ARN into the metadata to ensure that we ONLY look 1689 // at the unique ID that has been generated 1690 renewReq.Auth.Metadata["canonical_arn"] = "fake_arn" 1691 empty_login_fd := &framework.FieldData{ 1692 Raw: map[string]interface{}{}, 1693 Schema: pathLogin(b).Fields, 1694 } 1695 // ensure we can renew 1696 resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd) 1697 if err != nil { 1698 t.Fatal(err) 1699 } 1700 if resp == nil { 1701 t.Fatal("got nil response from renew") 1702 } 1703 if resp.IsError() { 1704 t.Fatalf("got error when renewing: %#v", *resp) 1705 } 1706 1707 // Now, fake out the unique ID resolver to ensure we fail login if the unique ID 1708 // changes from under us 1709 b.resolveArnToUniqueIDFunc = resolveArnToFakeUniqueId 1710 // First, we need to update the role to force Vault to use our fake resolver to 1711 // pick up the fake user ID 1712 roleData["bound_iam_principal_arn"] = entity.canonicalArn() 1713 roleRequest.Path = "role/" + testValidRoleName 1714 resp, err = b.HandleRequest(context.Background(), roleRequest) 1715 if err != nil || (resp != nil && resp.IsError()) { 1716 t.Fatalf("bad: failed to recreate role: resp:%#v\nerr:%v", resp, err) 1717 } 1718 resp, err = b.HandleRequest(context.Background(), loginRequest) 1719 if err != nil || resp == nil || !resp.IsError() { 1720 t.Errorf("bad: expected failed login due to changed AWS role ID: resp: %#v\nerr:%v", resp, err) 1721 } 1722 1723 // and ensure a renew no longer works 1724 resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd) 1725 if err == nil || (resp != nil && !resp.IsError()) { 1726 t.Errorf("bad: expected failed renew due to changed AWS role ID: resp: %#v", resp) 1727 } 1728 // Undo the fake resolver... 1729 b.resolveArnToUniqueIDFunc = b.resolveArnToRealUniqueId 1730 1731 // Now test that wildcard matching works 1732 wildcardRoleName := "valid_wildcard" 1733 wildcardEntity := *entity 1734 wildcardEntity.FriendlyName = "*" 1735 roleData["bound_iam_principal_arn"] = []string{wildcardEntity.canonicalArn(), "arn:aws:iam::123456789012:role/DoesNotExist/Vault_Fake_Role*"} 1736 roleRequest.Path = "role/" + wildcardRoleName 1737 resp, err = b.HandleRequest(context.Background(), roleRequest) 1738 if err != nil || (resp != nil && resp.IsError()) { 1739 t.Fatalf("bad: failed to create wildcard roles: resp:%#v\nerr:%v", resp, err) 1740 } 1741 1742 loginData["role"] = wildcardRoleName 1743 resp, err = b.HandleRequest(context.Background(), loginRequest) 1744 if err != nil { 1745 t.Fatal(err) 1746 } 1747 if resp == nil || resp.Auth == nil || resp.IsError() { 1748 t.Fatalf("bad: expected valid login: resp:%#v", resp) 1749 } 1750 // and ensure we can renew 1751 renewReq = generateRenewRequest(storage, resp.Auth) 1752 resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd) 1753 if err != nil { 1754 t.Fatal(err) 1755 } 1756 if resp == nil { 1757 t.Fatal("got nil response from renew") 1758 } 1759 if resp.IsError() { 1760 t.Fatalf("got error when renewing: %#v", *resp) 1761 } 1762 // ensure the cache is populated 1763 cachedArn := b.getCachedUserId(resp.Auth.Metadata["client_user_id"]) 1764 if cachedArn == "" { 1765 t.Errorf("got empty ARN back from user ID cache; expected full arn") 1766 } 1767 1768 // Test for renewal with period 1769 period := 600 * time.Second 1770 roleData["period"] = period.String() 1771 roleRequest.Path = "role/" + testValidRoleName 1772 resp, err = b.HandleRequest(context.Background(), roleRequest) 1773 if err != nil || (resp != nil && resp.IsError()) { 1774 t.Fatalf("bad: failed to create wildcard role: resp:%#v\nerr:%v", resp, err) 1775 } 1776 1777 loginData["role"] = testValidRoleName 1778 resp, err = b.HandleRequest(context.Background(), loginRequest) 1779 if err != nil { 1780 t.Fatal(err) 1781 } 1782 if resp == nil || resp.Auth == nil || resp.IsError() { 1783 t.Fatalf("bad: expected valid login: resp:%#v", resp) 1784 } 1785 1786 renewReq = generateRenewRequest(storage, resp.Auth) 1787 resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd) 1788 if err != nil { 1789 t.Fatal(err) 1790 } 1791 if resp == nil { 1792 t.Fatal("got nil response from renew") 1793 } 1794 if resp.IsError() { 1795 t.Fatalf("got error when renewing: %#v", *resp) 1796 } 1797 1798 if resp.Auth.Period != period { 1799 t.Fatalf("expected a period value of %s in the response, got: %s", period, resp.Auth.Period) 1800 } 1801} 1802 1803func generateRenewRequest(s logical.Storage, auth *logical.Auth) *logical.Request { 1804 renewReq := &logical.Request{ 1805 Storage: s, 1806 Auth: &logical.Auth{}, 1807 } 1808 renewReq.Auth.InternalData = auth.InternalData 1809 renewReq.Auth.Metadata = auth.Metadata 1810 renewReq.Auth.LeaseOptions = auth.LeaseOptions 1811 renewReq.Auth.Policies = auth.Policies 1812 renewReq.Auth.Period = auth.Period 1813 1814 return renewReq 1815} 1816