github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/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  		&iamEndpoint{
    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  		&iamEndpoint{
    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  		&iamEndpoint{
    98  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
    99  			Response: &iamResponse{403, iamResponse_GetUser_unauthorized, "text/xml"},
   100  		},
   101  		&iamEndpoint{
   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  		&iamEndpoint{
   123  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
   124  			Response: &iamResponse{403, iamResponse_GetUser_unauthorized, "text/xml"},
   125  		},
   126  		&iamEndpoint{
   127  			Request:  &iamRequest{"POST", "/", "Action=GetCallerIdentity&Version=2011-06-15"},
   128  			Response: &iamResponse{403, stsResponse_GetCallerIdentity_unauthorized, "text/xml"},
   129  		},
   130  		&iamEndpoint{
   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  		&iamEndpoint{
   152  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
   153  			Response: &iamResponse{400, iamResponse_GetUser_federatedFailure, "text/xml"},
   154  		},
   155  		&iamEndpoint{
   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  		&iamEndpoint{
   177  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
   178  			Response: &iamResponse{403, iamResponse_GetUser_unauthorized, "text/xml"},
   179  		},
   180  		&iamEndpoint{
   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 := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
   222  	_, err := c.Get()
   223  	if awsErr, ok := err.(awserr.Error); ok {
   224  		if awsErr.Code() != "NoCredentialProviders" {
   225  			t.Fatalf("Expected NoCredentialProviders error")
   226  		}
   227  	}
   228  	if err == nil {
   229  		t.Fatalf("Expected an error with empty env, keys, and IAM in AWS Config")
   230  	}
   231  }
   232  
   233  func TestAWSGetCredentials_shouldBeStatic(t *testing.T) {
   234  	simple := []struct {
   235  		Key, Secret, Token string
   236  	}{
   237  		{
   238  			Key:    "test",
   239  			Secret: "secret",
   240  		}, {
   241  			Key:    "test",
   242  			Secret: "test",
   243  			Token:  "test",
   244  		},
   245  	}
   246  
   247  	for _, c := range simple {
   248  		cfg := Config{
   249  			AccessKey: c.Key,
   250  			SecretKey: c.Secret,
   251  			Token:     c.Token,
   252  		}
   253  
   254  		creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
   255  		if creds == nil {
   256  			t.Fatalf("Expected a static creds provider to be returned")
   257  		}
   258  		v, err := creds.Get()
   259  		if err != nil {
   260  			t.Fatalf("Error gettings creds: %s", err)
   261  		}
   262  		if v.AccessKeyID != c.Key {
   263  			t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID)
   264  		}
   265  		if v.SecretAccessKey != c.Secret {
   266  			t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey)
   267  		}
   268  		if v.SessionToken != c.Token {
   269  			t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken)
   270  		}
   271  	}
   272  }
   273  
   274  // TestAWSGetCredentials_shouldIAM is designed to test the scenario of running Terraform
   275  // from an EC2 instance, without environment variables or manually supplied
   276  // credentials.
   277  func TestAWSGetCredentials_shouldIAM(t *testing.T) {
   278  	// clear AWS_* environment variables
   279  	resetEnv := unsetEnv(t)
   280  	defer resetEnv()
   281  
   282  	// capture the test server's close method, to call after the test returns
   283  	ts := awsEnv(t)
   284  	defer ts()
   285  
   286  	// An empty config, no key supplied
   287  	cfg := Config{}
   288  
   289  	creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
   290  	if creds == nil {
   291  		t.Fatalf("Expected a static creds provider to be returned")
   292  	}
   293  
   294  	v, err := creds.Get()
   295  	if err != nil {
   296  		t.Fatalf("Error gettings creds: %s", err)
   297  	}
   298  	if v.AccessKeyID != "somekey" {
   299  		t.Fatalf("AccessKeyID mismatch, expected: (somekey), got (%s)", v.AccessKeyID)
   300  	}
   301  	if v.SecretAccessKey != "somesecret" {
   302  		t.Fatalf("SecretAccessKey mismatch, expected: (somesecret), got (%s)", v.SecretAccessKey)
   303  	}
   304  	if v.SessionToken != "sometoken" {
   305  		t.Fatalf("SessionToken mismatch, expected: (sometoken), got (%s)", v.SessionToken)
   306  	}
   307  }
   308  
   309  // TestAWSGetCredentials_shouldIAM is designed to test the scenario of running Terraform
   310  // from an EC2 instance, without environment variables or manually supplied
   311  // credentials.
   312  func TestAWSGetCredentials_shouldIgnoreIAM(t *testing.T) {
   313  	resetEnv := unsetEnv(t)
   314  	defer resetEnv()
   315  	// capture the test server's close method, to call after the test returns
   316  	ts := awsEnv(t)
   317  	defer ts()
   318  	simple := []struct {
   319  		Key, Secret, Token string
   320  	}{
   321  		{
   322  			Key:    "test",
   323  			Secret: "secret",
   324  		}, {
   325  			Key:    "test",
   326  			Secret: "test",
   327  			Token:  "test",
   328  		},
   329  	}
   330  
   331  	for _, c := range simple {
   332  		cfg := Config{
   333  			AccessKey: c.Key,
   334  			SecretKey: c.Secret,
   335  			Token:     c.Token,
   336  		}
   337  
   338  		creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
   339  		if creds == nil {
   340  			t.Fatalf("Expected a static creds provider to be returned")
   341  		}
   342  		v, err := creds.Get()
   343  		if err != nil {
   344  			t.Fatalf("Error gettings creds: %s", err)
   345  		}
   346  		if v.AccessKeyID != c.Key {
   347  			t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID)
   348  		}
   349  		if v.SecretAccessKey != c.Secret {
   350  			t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey)
   351  		}
   352  		if v.SessionToken != c.Token {
   353  			t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken)
   354  		}
   355  	}
   356  }
   357  
   358  func TestAWSGetCredentials_shouldErrorWithInvalidEndpoint(t *testing.T) {
   359  	resetEnv := unsetEnv(t)
   360  	defer resetEnv()
   361  	// capture the test server's close method, to call after the test returns
   362  	ts := invalidAwsEnv(t)
   363  	defer ts()
   364  
   365  	creds := GetCredentials("", "", "", "", "")
   366  	v, err := creds.Get()
   367  	if err == nil {
   368  		t.Fatal("Expected error returned when getting creds w/ invalid EC2 endpoint")
   369  	}
   370  
   371  	if v.ProviderName != "" {
   372  		t.Fatalf("Expected provider name to be empty, %q given", v.ProviderName)
   373  	}
   374  }
   375  
   376  func TestAWSGetCredentials_shouldIgnoreInvalidEndpoint(t *testing.T) {
   377  	resetEnv := unsetEnv(t)
   378  	defer resetEnv()
   379  	// capture the test server's close method, to call after the test returns
   380  	ts := invalidAwsEnv(t)
   381  	defer ts()
   382  
   383  	creds := GetCredentials("accessKey", "secretKey", "", "", "")
   384  	v, err := creds.Get()
   385  	if err != nil {
   386  		t.Fatalf("Getting static credentials w/ invalid EC2 endpoint failed: %s", err)
   387  	}
   388  
   389  	if v.ProviderName != "StaticProvider" {
   390  		t.Fatalf("Expected provider name to be %q, %q given", "StaticProvider", v.ProviderName)
   391  	}
   392  
   393  	if v.AccessKeyID != "accessKey" {
   394  		t.Fatalf("Static Access Key %q doesn't match: %s", "accessKey", v.AccessKeyID)
   395  	}
   396  
   397  	if v.SecretAccessKey != "secretKey" {
   398  		t.Fatalf("Static Secret Key %q doesn't match: %s", "secretKey", v.SecretAccessKey)
   399  	}
   400  }
   401  
   402  func TestAWSGetCredentials_shouldCatchEC2RoleProvider(t *testing.T) {
   403  	resetEnv := unsetEnv(t)
   404  	defer resetEnv()
   405  	// capture the test server's close method, to call after the test returns
   406  	ts := awsEnv(t)
   407  	defer ts()
   408  
   409  	creds := GetCredentials("", "", "", "", "")
   410  	if creds == nil {
   411  		t.Fatalf("Expected an EC2Role creds provider to be returned")
   412  	}
   413  	v, err := creds.Get()
   414  	if err != nil {
   415  		t.Fatalf("Expected no error when getting creds: %s", err)
   416  	}
   417  	expectedProvider := "EC2RoleProvider"
   418  	if v.ProviderName != expectedProvider {
   419  		t.Fatalf("Expected provider name to be %q, %q given",
   420  			expectedProvider, v.ProviderName)
   421  	}
   422  }
   423  
   424  var credentialsFileContents = `[myprofile]
   425  aws_access_key_id = accesskey
   426  aws_secret_access_key = secretkey
   427  `
   428  
   429  func TestAWSGetCredentials_shouldBeShared(t *testing.T) {
   430  	file, err := ioutil.TempFile(os.TempDir(), "terraform_aws_cred")
   431  	if err != nil {
   432  		t.Fatalf("Error writing temporary credentials file: %s", err)
   433  	}
   434  	_, err = file.WriteString(credentialsFileContents)
   435  	if err != nil {
   436  		t.Fatalf("Error writing temporary credentials to file: %s", err)
   437  	}
   438  	err = file.Close()
   439  	if err != nil {
   440  		t.Fatalf("Error closing temporary credentials file: %s", err)
   441  	}
   442  
   443  	defer os.Remove(file.Name())
   444  
   445  	resetEnv := unsetEnv(t)
   446  	defer resetEnv()
   447  
   448  	if err := os.Setenv("AWS_PROFILE", "myprofile"); err != nil {
   449  		t.Fatalf("Error resetting env var AWS_PROFILE: %s", err)
   450  	}
   451  	if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", file.Name()); err != nil {
   452  		t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
   453  	}
   454  
   455  	creds := GetCredentials("", "", "", "myprofile", file.Name())
   456  	if creds == nil {
   457  		t.Fatalf("Expected a provider chain to be returned")
   458  	}
   459  	v, err := creds.Get()
   460  	if err != nil {
   461  		t.Fatalf("Error gettings creds: %s", err)
   462  	}
   463  
   464  	if v.AccessKeyID != "accesskey" {
   465  		t.Fatalf("AccessKeyID mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID)
   466  	}
   467  
   468  	if v.SecretAccessKey != "secretkey" {
   469  		t.Fatalf("SecretAccessKey mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID)
   470  	}
   471  }
   472  
   473  func TestAWSGetCredentials_shouldBeENV(t *testing.T) {
   474  	// need to set the environment variables to a dummy string, as we don't know
   475  	// what they may be at runtime without hardcoding here
   476  	s := "some_env"
   477  	resetEnv := setEnv(s, t)
   478  
   479  	defer resetEnv()
   480  
   481  	cfg := Config{}
   482  	creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
   483  	if creds == nil {
   484  		t.Fatalf("Expected a static creds provider to be returned")
   485  	}
   486  	v, err := creds.Get()
   487  	if err != nil {
   488  		t.Fatalf("Error gettings creds: %s", err)
   489  	}
   490  	if v.AccessKeyID != s {
   491  		t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", s, v.AccessKeyID)
   492  	}
   493  	if v.SecretAccessKey != s {
   494  		t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", s, v.SecretAccessKey)
   495  	}
   496  	if v.SessionToken != s {
   497  		t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", s, v.SessionToken)
   498  	}
   499  }
   500  
   501  // unsetEnv unsets enviornment variables for testing a "clean slate" with no
   502  // credentials in the environment
   503  func unsetEnv(t *testing.T) func() {
   504  	// Grab any existing AWS keys and preserve. In some tests we'll unset these, so
   505  	// we need to have them and restore them after
   506  	e := getEnv()
   507  	if err := os.Unsetenv("AWS_ACCESS_KEY_ID"); err != nil {
   508  		t.Fatalf("Error unsetting env var AWS_ACCESS_KEY_ID: %s", err)
   509  	}
   510  	if err := os.Unsetenv("AWS_SECRET_ACCESS_KEY"); err != nil {
   511  		t.Fatalf("Error unsetting env var AWS_SECRET_ACCESS_KEY: %s", err)
   512  	}
   513  	if err := os.Unsetenv("AWS_SESSION_TOKEN"); err != nil {
   514  		t.Fatalf("Error unsetting env var AWS_SESSION_TOKEN: %s", err)
   515  	}
   516  	if err := os.Unsetenv("AWS_PROFILE"); err != nil {
   517  		t.Fatalf("Error unsetting env var AWS_PROFILE: %s", err)
   518  	}
   519  	if err := os.Unsetenv("AWS_SHARED_CREDENTIALS_FILE"); err != nil {
   520  		t.Fatalf("Error unsetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
   521  	}
   522  
   523  	return func() {
   524  		// re-set all the envs we unset above
   525  		if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil {
   526  			t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err)
   527  		}
   528  		if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil {
   529  			t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err)
   530  		}
   531  		if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil {
   532  			t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err)
   533  		}
   534  		if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil {
   535  			t.Fatalf("Error resetting env var AWS_PROFILE: %s", err)
   536  		}
   537  		if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", e.CredsFilename); err != nil {
   538  			t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
   539  		}
   540  	}
   541  }
   542  
   543  func setEnv(s string, t *testing.T) func() {
   544  	e := getEnv()
   545  	// Set all the envs to a dummy value
   546  	if err := os.Setenv("AWS_ACCESS_KEY_ID", s); err != nil {
   547  		t.Fatalf("Error setting env var AWS_ACCESS_KEY_ID: %s", err)
   548  	}
   549  	if err := os.Setenv("AWS_SECRET_ACCESS_KEY", s); err != nil {
   550  		t.Fatalf("Error setting env var AWS_SECRET_ACCESS_KEY: %s", err)
   551  	}
   552  	if err := os.Setenv("AWS_SESSION_TOKEN", s); err != nil {
   553  		t.Fatalf("Error setting env var AWS_SESSION_TOKEN: %s", err)
   554  	}
   555  	if err := os.Setenv("AWS_PROFILE", s); err != nil {
   556  		t.Fatalf("Error setting env var AWS_PROFILE: %s", err)
   557  	}
   558  	if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil {
   559  		t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err)
   560  	}
   561  
   562  	return func() {
   563  		// re-set all the envs we unset above
   564  		if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil {
   565  			t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err)
   566  		}
   567  		if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil {
   568  			t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err)
   569  		}
   570  		if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil {
   571  			t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err)
   572  		}
   573  		if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil {
   574  			t.Fatalf("Error setting env var AWS_PROFILE: %s", err)
   575  		}
   576  		if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil {
   577  			t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err)
   578  		}
   579  	}
   580  }
   581  
   582  // awsEnv establishes a httptest server to mock out the internal AWS Metadata
   583  // service. IAM Credentials are retrieved by the EC2RoleProvider, which makes
   584  // API calls to this internal URL. By replacing the server with a test server,
   585  // we can simulate an AWS environment
   586  func awsEnv(t *testing.T) func() {
   587  	routes := routes{}
   588  	if err := json.Unmarshal([]byte(metadataApiRoutes), &routes); err != nil {
   589  		t.Fatalf("Failed to unmarshal JSON in AWS ENV test: %s", err)
   590  	}
   591  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   592  		w.Header().Set("Content-Type", "text/plain")
   593  		w.Header().Add("Server", "MockEC2")
   594  		log.Printf("[DEBUG] Mocker server received request to %q", r.RequestURI)
   595  		for _, e := range routes.Endpoints {
   596  			if r.RequestURI == e.Uri {
   597  				fmt.Fprintln(w, e.Body)
   598  				w.WriteHeader(200)
   599  				return
   600  			}
   601  		}
   602  		w.WriteHeader(400)
   603  	}))
   604  
   605  	os.Setenv("AWS_METADATA_URL", ts.URL+"/latest")
   606  	return ts.Close
   607  }
   608  
   609  // invalidAwsEnv establishes a httptest server to simulate behaviour
   610  // when endpoint doesn't respond as expected
   611  func invalidAwsEnv(t *testing.T) func() {
   612  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   613  		w.WriteHeader(400)
   614  	}))
   615  
   616  	os.Setenv("AWS_METADATA_URL", ts.URL+"/latest")
   617  	return ts.Close
   618  }
   619  
   620  // getMockedAwsIamStsApi establishes a httptest server to simulate behaviour
   621  // of a real AWS' IAM & STS server
   622  func getMockedAwsIamStsApi(endpoints []*iamEndpoint) (func(), *iam.IAM, *sts.STS) {
   623  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   624  		buf := new(bytes.Buffer)
   625  		buf.ReadFrom(r.Body)
   626  		requestBody := buf.String()
   627  
   628  		log.Printf("[DEBUG] Received API %q request to %q: %s",
   629  			r.Method, r.RequestURI, requestBody)
   630  
   631  		for _, e := range endpoints {
   632  			if r.Method == e.Request.Method && r.RequestURI == e.Request.Uri && requestBody == e.Request.Body {
   633  				log.Printf("[DEBUG] Mock API responding with %d: %s", e.Response.StatusCode, e.Response.Body)
   634  
   635  				w.WriteHeader(e.Response.StatusCode)
   636  				w.Header().Set("Content-Type", e.Response.ContentType)
   637  				w.Header().Set("X-Amzn-Requestid", "1b206dd1-f9a8-11e5-becf-051c60f11c4a")
   638  				w.Header().Set("Date", time.Now().Format(time.RFC1123))
   639  
   640  				fmt.Fprintln(w, e.Response.Body)
   641  				return
   642  			}
   643  		}
   644  
   645  		w.WriteHeader(400)
   646  		return
   647  	}))
   648  
   649  	sc := awsCredentials.NewStaticCredentials("accessKey", "secretKey", "")
   650  
   651  	sess := session.New(&aws.Config{
   652  		Credentials:                   sc,
   653  		Region:                        aws.String("us-east-1"),
   654  		Endpoint:                      aws.String(ts.URL),
   655  		CredentialsChainVerboseErrors: aws.Bool(true),
   656  	})
   657  	iamConn := iam.New(sess)
   658  	stsConn := sts.New(sess)
   659  	return ts.Close, iamConn, stsConn
   660  }
   661  
   662  func getEnv() *currentEnv {
   663  	// Grab any existing AWS keys and preserve. In some tests we'll unset these, so
   664  	// we need to have them and restore them after
   665  	return &currentEnv{
   666  		Key:           os.Getenv("AWS_ACCESS_KEY_ID"),
   667  		Secret:        os.Getenv("AWS_SECRET_ACCESS_KEY"),
   668  		Token:         os.Getenv("AWS_SESSION_TOKEN"),
   669  		Profile:       os.Getenv("AWS_PROFILE"),
   670  		CredsFilename: os.Getenv("AWS_SHARED_CREDENTIALS_FILE"),
   671  	}
   672  }
   673  
   674  // struct to preserve the current environment
   675  type currentEnv struct {
   676  	Key, Secret, Token, Profile, CredsFilename string
   677  }
   678  
   679  type routes struct {
   680  	Endpoints []*endpoint `json:"endpoints"`
   681  }
   682  type endpoint struct {
   683  	Uri  string `json:"uri"`
   684  	Body string `json:"body"`
   685  }
   686  
   687  const metadataApiRoutes = `
   688  {
   689    "endpoints": [
   690      {
   691        "uri": "/latest/meta-data/instance-id",
   692        "body": "mock-instance-id"
   693      },
   694      {
   695        "uri": "/latest/meta-data/iam/info",
   696        "body": "{\"Code\": \"Success\",\"LastUpdated\": \"2016-03-17T12:27:32Z\",\"InstanceProfileArn\": \"arn:aws:iam::123456789013:instance-profile/my-instance-profile\",\"InstanceProfileId\": \"AIPAABCDEFGHIJKLMN123\"}"
   697      },
   698      {
   699        "uri": "/latest/meta-data/iam/security-credentials",
   700        "body": "test_role"
   701      },
   702      {
   703        "uri": "/latest/meta-data/iam/security-credentials/test_role",
   704        "body": "{\"Code\":\"Success\",\"LastUpdated\":\"2015-12-11T17:17:25Z\",\"Type\":\"AWS-HMAC\",\"AccessKeyId\":\"somekey\",\"SecretAccessKey\":\"somesecret\",\"Token\":\"sometoken\"}"
   705      }
   706    ]
   707  }
   708  `
   709  
   710  type iamEndpoint struct {
   711  	Request  *iamRequest
   712  	Response *iamResponse
   713  }
   714  
   715  type iamRequest struct {
   716  	Method string
   717  	Uri    string
   718  	Body   string
   719  }
   720  
   721  type iamResponse struct {
   722  	StatusCode  int
   723  	Body        string
   724  	ContentType string
   725  }
   726  
   727  const iamResponse_GetUser_valid = `<GetUserResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   728    <GetUserResult>
   729      <User>
   730        <UserId>AIDACKCEVSQ6C2EXAMPLE</UserId>
   731        <Path>/division_abc/subdivision_xyz/</Path>
   732        <UserName>Bob</UserName>
   733        <Arn>arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob</Arn>
   734        <CreateDate>2013-10-02T17:01:44Z</CreateDate>
   735        <PasswordLastUsed>2014-10-10T14:37:51Z</PasswordLastUsed>
   736      </User>
   737    </GetUserResult>
   738    <ResponseMetadata>
   739      <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   740    </ResponseMetadata>
   741  </GetUserResponse>`
   742  
   743  const iamResponse_GetUser_unauthorized = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   744    <Error>
   745      <Type>Sender</Type>
   746      <Code>AccessDenied</Code>
   747      <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: iam:GetUser on resource: arn:aws:iam::123456789012:user/Bob</Message>
   748    </Error>
   749    <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   750  </ErrorResponse>`
   751  
   752  const stsResponse_GetCallerIdentity_valid = `<GetCallerIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
   753    <GetCallerIdentityResult>
   754     <Arn>arn:aws:iam::123456789012:user/Alice</Arn>
   755      <UserId>AKIAI44QH8DHBEXAMPLE</UserId>
   756      <Account>123456789012</Account>
   757    </GetCallerIdentityResult>
   758    <ResponseMetadata>
   759      <RequestId>01234567-89ab-cdef-0123-456789abcdef</RequestId>
   760    </ResponseMetadata>
   761  </GetCallerIdentityResponse>`
   762  
   763  const stsResponse_GetCallerIdentity_unauthorized = `<ErrorResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
   764    <Error>
   765      <Type>Sender</Type>
   766      <Code>AccessDenied</Code>
   767      <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: sts:GetCallerIdentity</Message>
   768    </Error>
   769    <RequestId>01234567-89ab-cdef-0123-456789abcdef</RequestId>
   770  </ErrorResponse>`
   771  
   772  const iamResponse_GetUser_federatedFailure = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   773    <Error>
   774      <Type>Sender</Type>
   775      <Code>ValidationError</Code>
   776      <Message>Must specify userName when calling with non-User credentials</Message>
   777    </Error>
   778    <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   779  </ErrorResponse>`
   780  
   781  const iamResponse_ListRoles_valid = `<ListRolesResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   782    <ListRolesResult>
   783      <IsTruncated>true</IsTruncated>
   784      <Marker>AWceSSsKsazQ4IEplT9o4hURCzBs00iavlEvEXAMPLE</Marker>
   785      <Roles>
   786        <member>
   787          <Path>/</Path>
   788          <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>
   789          <RoleId>AROACKCEVSQ6C2EXAMPLE</RoleId>
   790          <RoleName>elasticbeanstalk-role</RoleName>
   791          <Arn>arn:aws:iam::123456789012:role/elasticbeanstalk-role</Arn>
   792          <CreateDate>2013-10-02T17:01:44Z</CreateDate>
   793        </member>
   794      </Roles>
   795    </ListRolesResult>
   796    <ResponseMetadata>
   797      <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   798    </ResponseMetadata>
   799  </ListRolesResponse>`
   800  
   801  const iamResponse_ListRoles_unauthorized = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   802    <Error>
   803      <Type>Sender</Type>
   804      <Code>AccessDenied</Code>
   805      <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: iam:ListRoles on resource: arn:aws:iam::123456789012:role/</Message>
   806    </Error>
   807    <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   808  </ErrorResponse>`