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