github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/auth_helpers_test.go (about) 1 package aws 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "net/http" 9 "net/http/httptest" 10 "os" 11 "testing" 12 13 "github.com/aws/aws-sdk-go/aws/awserr" 14 "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" 15 "github.com/aws/aws-sdk-go/service/iam" 16 "github.com/aws/aws-sdk-go/service/sts" 17 ) 18 19 func TestAWSGetAccountInfo_shouldBeValid_fromEC2Role(t *testing.T) { 20 resetEnv := unsetEnv(t) 21 defer resetEnv() 22 // capture the test server's close method, to call after the test returns 23 awsTs := awsEnv(t) 24 defer awsTs() 25 26 closeEmpty, emptySess, err := getMockedAwsApiSession("zero", []*awsMockEndpoint{}) 27 defer closeEmpty() 28 if err != nil { 29 t.Fatal(err) 30 } 31 32 iamConn := iam.New(emptySess) 33 stsConn := sts.New(emptySess) 34 35 part, id, err := GetAccountInfo(iamConn, stsConn, ec2rolecreds.ProviderName) 36 if err != nil { 37 t.Fatalf("Getting account ID from EC2 metadata API failed: %s", err) 38 } 39 40 expectedPart := "aws" 41 if part != expectedPart { 42 t.Fatalf("Expected partition: %s, given: %s", expectedPart, part) 43 } 44 45 expectedAccountId := "123456789013" 46 if id != expectedAccountId { 47 t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id) 48 } 49 } 50 51 func TestAWSGetAccountInfo_shouldBeValid_EC2RoleHasPriority(t *testing.T) { 52 resetEnv := unsetEnv(t) 53 defer resetEnv() 54 // capture the test server's close method, to call after the test returns 55 awsTs := awsEnv(t) 56 defer awsTs() 57 58 iamEndpoints := []*awsMockEndpoint{ 59 { 60 Request: &awsMockRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"}, 61 Response: &awsMockResponse{200, iamResponse_GetUser_valid, "text/xml"}, 62 }, 63 } 64 closeIam, iamSess, err := getMockedAwsApiSession("IAM", iamEndpoints) 65 defer closeIam() 66 if err != nil { 67 t.Fatal(err) 68 } 69 iamConn := iam.New(iamSess) 70 closeSts, stsSess, err := getMockedAwsApiSession("STS", []*awsMockEndpoint{}) 71 defer closeSts() 72 if err != nil { 73 t.Fatal(err) 74 } 75 stsConn := sts.New(stsSess) 76 77 part, id, err := GetAccountInfo(iamConn, stsConn, ec2rolecreds.ProviderName) 78 if err != nil { 79 t.Fatalf("Getting account ID from EC2 metadata API failed: %s", err) 80 } 81 82 expectedPart := "aws" 83 if part != expectedPart { 84 t.Fatalf("Expected partition: %s, given: %s", expectedPart, part) 85 } 86 87 expectedAccountId := "123456789013" 88 if id != expectedAccountId { 89 t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id) 90 } 91 } 92 93 func TestAWSGetAccountInfo_shouldBeValid_fromIamUser(t *testing.T) { 94 iamEndpoints := []*awsMockEndpoint{ 95 { 96 Request: &awsMockRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"}, 97 Response: &awsMockResponse{200, iamResponse_GetUser_valid, "text/xml"}, 98 }, 99 } 100 101 closeIam, iamSess, err := getMockedAwsApiSession("IAM", iamEndpoints) 102 defer closeIam() 103 if err != nil { 104 t.Fatal(err) 105 } 106 closeSts, stsSess, err := getMockedAwsApiSession("STS", []*awsMockEndpoint{}) 107 defer closeSts() 108 if err != nil { 109 t.Fatal(err) 110 } 111 112 iamConn := iam.New(iamSess) 113 stsConn := sts.New(stsSess) 114 115 part, id, err := GetAccountInfo(iamConn, stsConn, "") 116 if err != nil { 117 t.Fatalf("Getting account ID via GetUser failed: %s", err) 118 } 119 120 expectedPart := "aws" 121 if part != expectedPart { 122 t.Fatalf("Expected partition: %s, given: %s", expectedPart, part) 123 } 124 125 expectedAccountId := "123456789012" 126 if id != expectedAccountId { 127 t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id) 128 } 129 } 130 131 func TestAWSGetAccountInfo_shouldBeValid_fromGetCallerIdentity(t *testing.T) { 132 iamEndpoints := []*awsMockEndpoint{ 133 { 134 Request: &awsMockRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"}, 135 Response: &awsMockResponse{403, iamResponse_GetUser_unauthorized, "text/xml"}, 136 }, 137 } 138 closeIam, iamSess, err := getMockedAwsApiSession("IAM", iamEndpoints) 139 defer closeIam() 140 if err != nil { 141 t.Fatal(err) 142 } 143 144 stsEndpoints := []*awsMockEndpoint{ 145 { 146 Request: &awsMockRequest{"POST", "/", "Action=GetCallerIdentity&Version=2011-06-15"}, 147 Response: &awsMockResponse{200, stsResponse_GetCallerIdentity_valid, "text/xml"}, 148 }, 149 } 150 closeSts, stsSess, err := getMockedAwsApiSession("STS", stsEndpoints) 151 defer closeSts() 152 if err != nil { 153 t.Fatal(err) 154 } 155 156 iamConn := iam.New(iamSess) 157 stsConn := sts.New(stsSess) 158 159 part, id, err := GetAccountInfo(iamConn, stsConn, "") 160 if err != nil { 161 t.Fatalf("Getting account ID via GetUser failed: %s", err) 162 } 163 164 expectedPart := "aws" 165 if part != expectedPart { 166 t.Fatalf("Expected partition: %s, given: %s", expectedPart, part) 167 } 168 169 expectedAccountId := "123456789012" 170 if id != expectedAccountId { 171 t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id) 172 } 173 } 174 175 func TestAWSGetAccountInfo_shouldBeValid_fromIamListRoles(t *testing.T) { 176 iamEndpoints := []*awsMockEndpoint{ 177 { 178 Request: &awsMockRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"}, 179 Response: &awsMockResponse{403, iamResponse_GetUser_unauthorized, "text/xml"}, 180 }, 181 { 182 Request: &awsMockRequest{"POST", "/", "Action=ListRoles&MaxItems=1&Version=2010-05-08"}, 183 Response: &awsMockResponse{200, iamResponse_ListRoles_valid, "text/xml"}, 184 }, 185 } 186 closeIam, iamSess, err := getMockedAwsApiSession("IAM", iamEndpoints) 187 defer closeIam() 188 if err != nil { 189 t.Fatal(err) 190 } 191 192 stsEndpoints := []*awsMockEndpoint{ 193 { 194 Request: &awsMockRequest{"POST", "/", "Action=GetCallerIdentity&Version=2011-06-15"}, 195 Response: &awsMockResponse{403, stsResponse_GetCallerIdentity_unauthorized, "text/xml"}, 196 }, 197 } 198 closeSts, stsSess, err := getMockedAwsApiSession("STS", stsEndpoints) 199 defer closeSts() 200 if err != nil { 201 t.Fatal(err) 202 } 203 204 iamConn := iam.New(iamSess) 205 stsConn := sts.New(stsSess) 206 207 part, id, err := GetAccountInfo(iamConn, stsConn, "") 208 if err != nil { 209 t.Fatalf("Getting account ID via ListRoles failed: %s", err) 210 } 211 212 expectedPart := "aws" 213 if part != expectedPart { 214 t.Fatalf("Expected partition: %s, given: %s", expectedPart, part) 215 } 216 217 expectedAccountId := "123456789012" 218 if id != expectedAccountId { 219 t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id) 220 } 221 } 222 223 func TestAWSGetAccountInfo_shouldBeValid_federatedRole(t *testing.T) { 224 iamEndpoints := []*awsMockEndpoint{ 225 { 226 Request: &awsMockRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"}, 227 Response: &awsMockResponse{400, iamResponse_GetUser_federatedFailure, "text/xml"}, 228 }, 229 { 230 Request: &awsMockRequest{"POST", "/", "Action=ListRoles&MaxItems=1&Version=2010-05-08"}, 231 Response: &awsMockResponse{200, iamResponse_ListRoles_valid, "text/xml"}, 232 }, 233 } 234 closeIam, iamSess, err := getMockedAwsApiSession("IAM", iamEndpoints) 235 defer closeIam() 236 if err != nil { 237 t.Fatal(err) 238 } 239 240 closeSts, stsSess, err := getMockedAwsApiSession("STS", []*awsMockEndpoint{}) 241 defer closeSts() 242 if err != nil { 243 t.Fatal(err) 244 } 245 246 iamConn := iam.New(iamSess) 247 stsConn := sts.New(stsSess) 248 249 part, id, err := GetAccountInfo(iamConn, stsConn, "") 250 if err != nil { 251 t.Fatalf("Getting account ID via ListRoles failed: %s", err) 252 } 253 254 expectedPart := "aws" 255 if part != expectedPart { 256 t.Fatalf("Expected partition: %s, given: %s", expectedPart, part) 257 } 258 259 expectedAccountId := "123456789012" 260 if id != expectedAccountId { 261 t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id) 262 } 263 } 264 265 func TestAWSGetAccountInfo_shouldError_unauthorizedFromIam(t *testing.T) { 266 iamEndpoints := []*awsMockEndpoint{ 267 { 268 Request: &awsMockRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"}, 269 Response: &awsMockResponse{403, iamResponse_GetUser_unauthorized, "text/xml"}, 270 }, 271 { 272 Request: &awsMockRequest{"POST", "/", "Action=ListRoles&MaxItems=1&Version=2010-05-08"}, 273 Response: &awsMockResponse{403, iamResponse_ListRoles_unauthorized, "text/xml"}, 274 }, 275 } 276 closeIam, iamSess, err := getMockedAwsApiSession("IAM", iamEndpoints) 277 defer closeIam() 278 if err != nil { 279 t.Fatal(err) 280 } 281 282 closeSts, stsSess, err := getMockedAwsApiSession("STS", []*awsMockEndpoint{}) 283 defer closeSts() 284 if err != nil { 285 t.Fatal(err) 286 } 287 288 iamConn := iam.New(iamSess) 289 stsConn := sts.New(stsSess) 290 291 part, id, err := GetAccountInfo(iamConn, stsConn, "") 292 if err == nil { 293 t.Fatal("Expected error when getting account ID") 294 } 295 296 if part != "" { 297 t.Fatalf("Expected no partition, given: %s", part) 298 } 299 300 if id != "" { 301 t.Fatalf("Expected no account ID, given: %s", id) 302 } 303 } 304 305 func TestAWSParseAccountInfoFromArn(t *testing.T) { 306 validArn := "arn:aws:iam::101636750127:instance-profile/aws-elasticbeanstalk-ec2-role" 307 expectedPart := "aws" 308 expectedId := "101636750127" 309 part, id, err := parseAccountInfoFromArn(validArn) 310 if err != nil { 311 t.Fatalf("Expected no error when parsing valid ARN: %s", err) 312 } 313 if part != expectedPart { 314 t.Fatalf("Parsed part doesn't match with expected (%q != %q)", part, expectedPart) 315 } 316 if id != expectedId { 317 t.Fatalf("Parsed id doesn't match with expected (%q != %q)", id, expectedId) 318 } 319 320 invalidArn := "blablah" 321 part, id, err = parseAccountInfoFromArn(invalidArn) 322 if err == nil { 323 t.Fatalf("Expected error when parsing invalid ARN (%q)", invalidArn) 324 } 325 } 326 327 func TestAWSGetCredentials_shouldError(t *testing.T) { 328 resetEnv := unsetEnv(t) 329 defer resetEnv() 330 cfg := Config{} 331 332 c, err := GetCredentials(&cfg) 333 if awsErr, ok := err.(awserr.Error); ok { 334 if awsErr.Code() != "NoCredentialProviders" { 335 t.Fatal("Expected NoCredentialProviders error") 336 } 337 } 338 _, err = c.Get() 339 if awsErr, ok := err.(awserr.Error); ok { 340 if awsErr.Code() != "NoCredentialProviders" { 341 t.Fatal("Expected NoCredentialProviders error") 342 } 343 } 344 if err == nil { 345 t.Fatal("Expected an error with empty env, keys, and IAM in AWS Config") 346 } 347 } 348 349 func TestAWSGetCredentials_shouldBeStatic(t *testing.T) { 350 simple := []struct { 351 Key, Secret, Token string 352 }{ 353 { 354 Key: "test", 355 Secret: "secret", 356 }, { 357 Key: "test", 358 Secret: "test", 359 Token: "test", 360 }, 361 } 362 363 for _, c := range simple { 364 cfg := Config{ 365 AccessKey: c.Key, 366 SecretKey: c.Secret, 367 Token: c.Token, 368 } 369 370 creds, err := GetCredentials(&cfg) 371 if err != nil { 372 t.Fatalf("Error gettings creds: %s", err) 373 } 374 if creds == nil { 375 t.Fatal("Expected a static creds provider to be returned") 376 } 377 378 v, err := creds.Get() 379 if err != nil { 380 t.Fatalf("Error gettings creds: %s", err) 381 } 382 383 if v.AccessKeyID != c.Key { 384 t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID) 385 } 386 if v.SecretAccessKey != c.Secret { 387 t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey) 388 } 389 if v.SessionToken != c.Token { 390 t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken) 391 } 392 } 393 } 394 395 // TestAWSGetCredentials_shouldIAM is designed to test the scenario of running Terraform 396 // from an EC2 instance, without environment variables or manually supplied 397 // credentials. 398 func TestAWSGetCredentials_shouldIAM(t *testing.T) { 399 // clear AWS_* environment variables 400 resetEnv := unsetEnv(t) 401 defer resetEnv() 402 403 // capture the test server's close method, to call after the test returns 404 ts := awsEnv(t) 405 defer ts() 406 407 // An empty config, no key supplied 408 cfg := Config{} 409 410 creds, err := GetCredentials(&cfg) 411 if err != nil { 412 t.Fatalf("Error gettings creds: %s", err) 413 } 414 if creds == nil { 415 t.Fatal("Expected a static creds provider to be returned") 416 } 417 418 v, err := creds.Get() 419 if err != nil { 420 t.Fatalf("Error gettings creds: %s", err) 421 } 422 if v.AccessKeyID != "somekey" { 423 t.Fatalf("AccessKeyID mismatch, expected: (somekey), got (%s)", v.AccessKeyID) 424 } 425 if v.SecretAccessKey != "somesecret" { 426 t.Fatalf("SecretAccessKey mismatch, expected: (somesecret), got (%s)", v.SecretAccessKey) 427 } 428 if v.SessionToken != "sometoken" { 429 t.Fatalf("SessionToken mismatch, expected: (sometoken), got (%s)", v.SessionToken) 430 } 431 } 432 433 // TestAWSGetCredentials_shouldIAM is designed to test the scenario of running Terraform 434 // from an EC2 instance, without environment variables or manually supplied 435 // credentials. 436 func TestAWSGetCredentials_shouldIgnoreIAM(t *testing.T) { 437 resetEnv := unsetEnv(t) 438 defer resetEnv() 439 // capture the test server's close method, to call after the test returns 440 ts := awsEnv(t) 441 defer ts() 442 simple := []struct { 443 Key, Secret, Token string 444 }{ 445 { 446 Key: "test", 447 Secret: "secret", 448 }, { 449 Key: "test", 450 Secret: "test", 451 Token: "test", 452 }, 453 } 454 455 for _, c := range simple { 456 cfg := Config{ 457 AccessKey: c.Key, 458 SecretKey: c.Secret, 459 Token: c.Token, 460 } 461 462 creds, err := GetCredentials(&cfg) 463 if err != nil { 464 t.Fatalf("Error gettings creds: %s", err) 465 } 466 if creds == nil { 467 t.Fatal("Expected a static creds provider to be returned") 468 } 469 470 v, err := creds.Get() 471 if err != nil { 472 t.Fatalf("Error gettings creds: %s", err) 473 } 474 if v.AccessKeyID != c.Key { 475 t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID) 476 } 477 if v.SecretAccessKey != c.Secret { 478 t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey) 479 } 480 if v.SessionToken != c.Token { 481 t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken) 482 } 483 } 484 } 485 486 func TestAWSGetCredentials_shouldErrorWithInvalidEndpoint(t *testing.T) { 487 resetEnv := unsetEnv(t) 488 defer resetEnv() 489 // capture the test server's close method, to call after the test returns 490 ts := invalidAwsEnv(t) 491 defer ts() 492 493 creds, err := GetCredentials(&Config{}) 494 if err != nil { 495 t.Fatalf("Error gettings creds: %s", err) 496 } 497 if creds == nil { 498 t.Fatal("Expected a static creds provider to be returned") 499 } 500 501 v, err := creds.Get() 502 if err == nil { 503 t.Fatal("Expected error returned when getting creds w/ invalid EC2 endpoint") 504 } 505 506 if v.ProviderName != "" { 507 t.Fatalf("Expected provider name to be empty, %q given", v.ProviderName) 508 } 509 } 510 511 func TestAWSGetCredentials_shouldIgnoreInvalidEndpoint(t *testing.T) { 512 resetEnv := unsetEnv(t) 513 defer resetEnv() 514 // capture the test server's close method, to call after the test returns 515 ts := invalidAwsEnv(t) 516 defer ts() 517 518 creds, err := GetCredentials(&Config{AccessKey: "accessKey", SecretKey: "secretKey"}) 519 if err != nil { 520 t.Fatalf("Error gettings creds: %s", err) 521 } 522 v, err := creds.Get() 523 if err != nil { 524 t.Fatalf("Getting static credentials w/ invalid EC2 endpoint failed: %s", err) 525 } 526 if creds == nil { 527 t.Fatal("Expected a static creds provider to be returned") 528 } 529 530 if v.ProviderName != "StaticProvider" { 531 t.Fatalf("Expected provider name to be %q, %q given", "StaticProvider", v.ProviderName) 532 } 533 534 if v.AccessKeyID != "accessKey" { 535 t.Fatalf("Static Access Key %q doesn't match: %s", "accessKey", v.AccessKeyID) 536 } 537 538 if v.SecretAccessKey != "secretKey" { 539 t.Fatalf("Static Secret Key %q doesn't match: %s", "secretKey", v.SecretAccessKey) 540 } 541 } 542 543 func TestAWSGetCredentials_shouldCatchEC2RoleProvider(t *testing.T) { 544 resetEnv := unsetEnv(t) 545 defer resetEnv() 546 // capture the test server's close method, to call after the test returns 547 ts := awsEnv(t) 548 defer ts() 549 550 creds, err := GetCredentials(&Config{}) 551 if err != nil { 552 t.Fatalf("Error gettings creds: %s", err) 553 } 554 if creds == nil { 555 t.Fatal("Expected an EC2Role creds provider to be returned") 556 } 557 558 v, err := creds.Get() 559 if err != nil { 560 t.Fatalf("Expected no error when getting creds: %s", err) 561 } 562 expectedProvider := "EC2RoleProvider" 563 if v.ProviderName != expectedProvider { 564 t.Fatalf("Expected provider name to be %q, %q given", 565 expectedProvider, v.ProviderName) 566 } 567 } 568 569 var credentialsFileContents = `[myprofile] 570 aws_access_key_id = accesskey 571 aws_secret_access_key = secretkey 572 ` 573 574 func TestAWSGetCredentials_shouldBeShared(t *testing.T) { 575 file, err := ioutil.TempFile(os.TempDir(), "terraform_aws_cred") 576 if err != nil { 577 t.Fatalf("Error writing temporary credentials file: %s", err) 578 } 579 _, err = file.WriteString(credentialsFileContents) 580 if err != nil { 581 t.Fatalf("Error writing temporary credentials to file: %s", err) 582 } 583 err = file.Close() 584 if err != nil { 585 t.Fatalf("Error closing temporary credentials file: %s", err) 586 } 587 588 defer os.Remove(file.Name()) 589 590 resetEnv := unsetEnv(t) 591 defer resetEnv() 592 593 if err := os.Setenv("AWS_PROFILE", "myprofile"); err != nil { 594 t.Fatalf("Error resetting env var AWS_PROFILE: %s", err) 595 } 596 if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", file.Name()); err != nil { 597 t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err) 598 } 599 600 creds, err := GetCredentials(&Config{Profile: "myprofile", CredsFilename: file.Name()}) 601 if err != nil { 602 t.Fatalf("Error gettings creds: %s", err) 603 } 604 if creds == nil { 605 t.Fatal("Expected a provider chain to be returned") 606 } 607 608 v, err := creds.Get() 609 if err != nil { 610 t.Fatalf("Error gettings creds: %s", err) 611 } 612 613 if v.AccessKeyID != "accesskey" { 614 t.Fatalf("AccessKeyID mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID) 615 } 616 617 if v.SecretAccessKey != "secretkey" { 618 t.Fatalf("SecretAccessKey mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID) 619 } 620 } 621 622 func TestAWSGetCredentials_shouldBeENV(t *testing.T) { 623 // need to set the environment variables to a dummy string, as we don't know 624 // what they may be at runtime without hardcoding here 625 s := "some_env" 626 resetEnv := setEnv(s, t) 627 628 defer resetEnv() 629 630 cfg := Config{} 631 creds, err := GetCredentials(&cfg) 632 if err != nil { 633 t.Fatalf("Error gettings creds: %s", err) 634 } 635 if creds == nil { 636 t.Fatalf("Expected a static creds provider to be returned") 637 } 638 639 v, err := creds.Get() 640 if err != nil { 641 t.Fatalf("Error gettings creds: %s", err) 642 } 643 if v.AccessKeyID != s { 644 t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", s, v.AccessKeyID) 645 } 646 if v.SecretAccessKey != s { 647 t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", s, v.SecretAccessKey) 648 } 649 if v.SessionToken != s { 650 t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", s, v.SessionToken) 651 } 652 } 653 654 // unsetEnv unsets environment variables for testing a "clean slate" with no 655 // credentials in the environment 656 func unsetEnv(t *testing.T) func() { 657 // Grab any existing AWS keys and preserve. In some tests we'll unset these, so 658 // we need to have them and restore them after 659 e := getEnv() 660 if err := os.Unsetenv("AWS_ACCESS_KEY_ID"); err != nil { 661 t.Fatalf("Error unsetting env var AWS_ACCESS_KEY_ID: %s", err) 662 } 663 if err := os.Unsetenv("AWS_SECRET_ACCESS_KEY"); err != nil { 664 t.Fatalf("Error unsetting env var AWS_SECRET_ACCESS_KEY: %s", err) 665 } 666 if err := os.Unsetenv("AWS_SESSION_TOKEN"); err != nil { 667 t.Fatalf("Error unsetting env var AWS_SESSION_TOKEN: %s", err) 668 } 669 if err := os.Unsetenv("AWS_PROFILE"); err != nil { 670 t.Fatalf("Error unsetting env var AWS_PROFILE: %s", err) 671 } 672 if err := os.Unsetenv("AWS_SHARED_CREDENTIALS_FILE"); err != nil { 673 t.Fatalf("Error unsetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err) 674 } 675 676 return func() { 677 // re-set all the envs we unset above 678 if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil { 679 t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err) 680 } 681 if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil { 682 t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err) 683 } 684 if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil { 685 t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err) 686 } 687 if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil { 688 t.Fatalf("Error resetting env var AWS_PROFILE: %s", err) 689 } 690 if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", e.CredsFilename); err != nil { 691 t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err) 692 } 693 } 694 } 695 696 func setEnv(s string, t *testing.T) func() { 697 e := getEnv() 698 // Set all the envs to a dummy value 699 if err := os.Setenv("AWS_ACCESS_KEY_ID", s); err != nil { 700 t.Fatalf("Error setting env var AWS_ACCESS_KEY_ID: %s", err) 701 } 702 if err := os.Setenv("AWS_SECRET_ACCESS_KEY", s); err != nil { 703 t.Fatalf("Error setting env var AWS_SECRET_ACCESS_KEY: %s", err) 704 } 705 if err := os.Setenv("AWS_SESSION_TOKEN", s); err != nil { 706 t.Fatalf("Error setting env var AWS_SESSION_TOKEN: %s", err) 707 } 708 if err := os.Setenv("AWS_PROFILE", s); err != nil { 709 t.Fatalf("Error setting env var AWS_PROFILE: %s", err) 710 } 711 if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil { 712 t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err) 713 } 714 715 return func() { 716 // re-set all the envs we unset above 717 if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil { 718 t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err) 719 } 720 if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil { 721 t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err) 722 } 723 if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil { 724 t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err) 725 } 726 if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil { 727 t.Fatalf("Error setting env var AWS_PROFILE: %s", err) 728 } 729 if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil { 730 t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err) 731 } 732 } 733 } 734 735 // awsEnv establishes a httptest server to mock out the internal AWS Metadata 736 // service. IAM Credentials are retrieved by the EC2RoleProvider, which makes 737 // API calls to this internal URL. By replacing the server with a test server, 738 // we can simulate an AWS environment 739 func awsEnv(t *testing.T) func() { 740 routes := routes{} 741 if err := json.Unmarshal([]byte(metadataApiRoutes), &routes); err != nil { 742 t.Fatalf("Failed to unmarshal JSON in AWS ENV test: %s", err) 743 } 744 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 745 w.Header().Set("Content-Type", "text/plain") 746 w.Header().Add("Server", "MockEC2") 747 log.Printf("[DEBUG] Mocker server received request to %q", r.RequestURI) 748 for _, e := range routes.Endpoints { 749 if r.RequestURI == e.Uri { 750 fmt.Fprintln(w, e.Body) 751 w.WriteHeader(200) 752 return 753 } 754 } 755 w.WriteHeader(400) 756 })) 757 758 os.Setenv("AWS_METADATA_URL", ts.URL+"/latest") 759 return ts.Close 760 } 761 762 // invalidAwsEnv establishes a httptest server to simulate behaviour 763 // when endpoint doesn't respond as expected 764 func invalidAwsEnv(t *testing.T) func() { 765 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 766 w.WriteHeader(400) 767 })) 768 769 os.Setenv("AWS_METADATA_URL", ts.URL+"/latest") 770 return ts.Close 771 } 772 773 func getEnv() *currentEnv { 774 // Grab any existing AWS keys and preserve. In some tests we'll unset these, so 775 // we need to have them and restore them after 776 return ¤tEnv{ 777 Key: os.Getenv("AWS_ACCESS_KEY_ID"), 778 Secret: os.Getenv("AWS_SECRET_ACCESS_KEY"), 779 Token: os.Getenv("AWS_SESSION_TOKEN"), 780 Profile: os.Getenv("AWS_PROFILE"), 781 CredsFilename: os.Getenv("AWS_SHARED_CREDENTIALS_FILE"), 782 } 783 } 784 785 // struct to preserve the current environment 786 type currentEnv struct { 787 Key, Secret, Token, Profile, CredsFilename string 788 } 789 790 type routes struct { 791 Endpoints []*endpoint `json:"endpoints"` 792 } 793 type endpoint struct { 794 Uri string `json:"uri"` 795 Body string `json:"body"` 796 } 797 798 const metadataApiRoutes = ` 799 { 800 "endpoints": [ 801 { 802 "uri": "/latest/meta-data/instance-id", 803 "body": "mock-instance-id" 804 }, 805 { 806 "uri": "/latest/meta-data/iam/info", 807 "body": "{\"Code\": \"Success\",\"LastUpdated\": \"2016-03-17T12:27:32Z\",\"InstanceProfileArn\": \"arn:aws:iam::123456789013:instance-profile/my-instance-profile\",\"InstanceProfileId\": \"AIPAABCDEFGHIJKLMN123\"}" 808 }, 809 { 810 "uri": "/latest/meta-data/iam/security-credentials", 811 "body": "test_role" 812 }, 813 { 814 "uri": "/latest/meta-data/iam/security-credentials/test_role", 815 "body": "{\"Code\":\"Success\",\"LastUpdated\":\"2015-12-11T17:17:25Z\",\"Type\":\"AWS-HMAC\",\"AccessKeyId\":\"somekey\",\"SecretAccessKey\":\"somesecret\",\"Token\":\"sometoken\"}" 816 } 817 ] 818 } 819 ` 820 821 const iamResponse_GetUser_valid = `<GetUserResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> 822 <GetUserResult> 823 <User> 824 <UserId>AIDACKCEVSQ6C2EXAMPLE</UserId> 825 <Path>/division_abc/subdivision_xyz/</Path> 826 <UserName>Bob</UserName> 827 <Arn>arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob</Arn> 828 <CreateDate>2013-10-02T17:01:44Z</CreateDate> 829 <PasswordLastUsed>2014-10-10T14:37:51Z</PasswordLastUsed> 830 </User> 831 </GetUserResult> 832 <ResponseMetadata> 833 <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId> 834 </ResponseMetadata> 835 </GetUserResponse>` 836 837 const iamResponse_GetUser_unauthorized = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> 838 <Error> 839 <Type>Sender</Type> 840 <Code>AccessDenied</Code> 841 <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: iam:GetUser on resource: arn:aws:iam::123456789012:user/Bob</Message> 842 </Error> 843 <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId> 844 </ErrorResponse>` 845 846 const stsResponse_GetCallerIdentity_valid = `<GetCallerIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/"> 847 <GetCallerIdentityResult> 848 <Arn>arn:aws:iam::123456789012:user/Alice</Arn> 849 <UserId>AKIAI44QH8DHBEXAMPLE</UserId> 850 <Account>123456789012</Account> 851 </GetCallerIdentityResult> 852 <ResponseMetadata> 853 <RequestId>01234567-89ab-cdef-0123-456789abcdef</RequestId> 854 </ResponseMetadata> 855 </GetCallerIdentityResponse>` 856 857 const stsResponse_GetCallerIdentity_unauthorized = `<ErrorResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/"> 858 <Error> 859 <Type>Sender</Type> 860 <Code>AccessDenied</Code> 861 <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: sts:GetCallerIdentity</Message> 862 </Error> 863 <RequestId>01234567-89ab-cdef-0123-456789abcdef</RequestId> 864 </ErrorResponse>` 865 866 const iamResponse_GetUser_federatedFailure = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> 867 <Error> 868 <Type>Sender</Type> 869 <Code>ValidationError</Code> 870 <Message>Must specify userName when calling with non-User credentials</Message> 871 </Error> 872 <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId> 873 </ErrorResponse>` 874 875 const iamResponse_ListRoles_valid = `<ListRolesResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> 876 <ListRolesResult> 877 <IsTruncated>true</IsTruncated> 878 <Marker>AWceSSsKsazQ4IEplT9o4hURCzBs00iavlEvEXAMPLE</Marker> 879 <Roles> 880 <member> 881 <Path>/</Path> 882 <AssumeRolePolicyDocument>%7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D</AssumeRolePolicyDocument> 883 <RoleId>AROACKCEVSQ6C2EXAMPLE</RoleId> 884 <RoleName>elasticbeanstalk-role</RoleName> 885 <Arn>arn:aws:iam::123456789012:role/elasticbeanstalk-role</Arn> 886 <CreateDate>2013-10-02T17:01:44Z</CreateDate> 887 </member> 888 </Roles> 889 </ListRolesResult> 890 <ResponseMetadata> 891 <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId> 892 </ResponseMetadata> 893 </ListRolesResponse>` 894 895 const iamResponse_ListRoles_unauthorized = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> 896 <Error> 897 <Type>Sender</Type> 898 <Code>AccessDenied</Code> 899 <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: iam:ListRoles on resource: arn:aws:iam::123456789012:role/</Message> 900 </Error> 901 <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId> 902 </ErrorResponse>`