@@ -33,15 +33,51 @@ func swapECSContainerURI(path string) func() {
33
33
}
34
34
}
35
35
36
- func setupCredentialsEndpoints (t * testing.T ) (aws.EndpointResolverWithOptions , func ()) {
36
+ const ecsFullPathResponse = `{
37
+ "Code": "Success",
38
+ "Type": "AWS-HMAC",
39
+ "AccessKeyId": "ecs-full-path-access-key",
40
+ "SecretAccessKey": "ecs-full-path-ecs-secret-key",
41
+ "Token": "ecs-full-path-token",
42
+ "Expiration": "2100-01-01T00:00:00Z",
43
+ "LastUpdated": "2009-11-23T00:00:00Z"
44
+ }`
45
+
46
+ const assumeRoleRespEcsFullPathMsg = `
47
+ <AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
48
+ <AssumeRoleResult>
49
+ <AssumedRoleUser>
50
+ <Arn>arn:aws:sts::account_id:assumed-role/role/session_name</Arn>
51
+ <AssumedRoleId>AKID:session_name</AssumedRoleId>
52
+ </AssumedRoleUser>
53
+ <Credentials>
54
+ <AccessKeyId>AKID-Full-Path</AccessKeyId>
55
+ <SecretAccessKey>SECRET-Full-Path</SecretAccessKey>
56
+ <SessionToken>SESSION_TOKEN-Full-Path</SessionToken>
57
+ <Expiration>%s</Expiration>
58
+ </Credentials>
59
+ </AssumeRoleResult>
60
+ <ResponseMetadata>
61
+ <RequestId>request-id</RequestId>
62
+ </ResponseMetadata>
63
+ </AssumeRoleResponse>
64
+ `
65
+
66
+ var ecsMetadataServerURL string
67
+
68
+ func setupCredentialsEndpoints () (aws.EndpointResolverWithOptions , func ()) {
37
69
ecsMetadataServer := httptest .NewServer (http .HandlerFunc (
38
70
func (w http.ResponseWriter , r * http.Request ) {
39
71
if r .URL .Path == "/ECS" {
40
72
w .Write ([]byte (ecsResponse ))
73
+ // Used when we specify a full path instead of relative path
74
+ } else if r .URL .Path == "/ECSFullPath" {
75
+ w .Write ([]byte (ecsFullPathResponse ))
41
76
} else {
42
77
w .Write ([]byte ("" ))
43
78
}
44
79
}))
80
+ ecsMetadataServerURL = ecsMetadataServer .URL
45
81
resetECSEndpoint := swapECSContainerURI (ecsMetadataServer .URL )
46
82
47
83
ec2MetadataServer := httptest .NewServer (http .HandlerFunc (
@@ -74,6 +110,15 @@ func setupCredentialsEndpoints(t *testing.T) (aws.EndpointResolverWithOptions, f
74
110
75
111
switch form .Get ("Action" ) {
76
112
case "AssumeRole" :
113
+ if val , ok := r .Header ["X-Amz-Security-Token" ]; ok {
114
+ if val [0 ] == "ecs-full-path-token" {
115
+ w .Write ([]byte (fmt .Sprintf (
116
+ assumeRoleRespEcsFullPathMsg ,
117
+ smithytime .FormatDateTime (time .Now ().
118
+ Add (15 * time .Minute )))))
119
+ return
120
+ }
121
+ }
77
122
w .Write ([]byte (fmt .Sprintf (
78
123
assumeRoleRespMsg ,
79
124
smithytime .FormatDateTime (time .Now ().
@@ -394,7 +439,7 @@ func TestSharedConfigCredentialSource(t *testing.T) {
394
439
os .Setenv ("AWS_PROFILE" , c .envProfile )
395
440
}
396
441
397
- endpointResolver , cleanupFn := setupCredentialsEndpoints (t )
442
+ endpointResolver , cleanupFn := setupCredentialsEndpoints ()
398
443
defer cleanupFn ()
399
444
400
445
var cleanup func ()
@@ -604,6 +649,107 @@ func TestResolveCredentialsIMDSClient(t *testing.T) {
604
649
}
605
650
}
606
651
652
+ func TestResolveCredentialsEcsContainer (t * testing.T ) {
653
+ testCases := map [string ]struct {
654
+ expectedAccessKey string
655
+ expectedSecretKey string
656
+ envVar map [string ]string
657
+ configFile string
658
+ }{
659
+ "only relative ECS URI set" : {
660
+ expectedAccessKey : "ecs-access-key" ,
661
+ expectedSecretKey : "ecs-secret-key" ,
662
+ envVar : map [string ]string {
663
+ "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" : "/ECS" ,
664
+ },
665
+ },
666
+ "only full ECS URI set" : {
667
+ expectedAccessKey : "ecs-full-path-access-key" ,
668
+ expectedSecretKey : "ecs-full-path-ecs-secret-key" ,
669
+ envVar : map [string ]string {
670
+ "AWS_CONTAINER_CREDENTIALS_FULL_URI" : "placeholder-replaced-at-runtime" ,
671
+ },
672
+ },
673
+ "relative ECS URI has precedence over full" : {
674
+ expectedAccessKey : "ecs-access-key" ,
675
+ expectedSecretKey : "ecs-secret-key" ,
676
+ envVar : map [string ]string {
677
+ "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" : "/ECS" ,
678
+ "AWS_CONTAINER_CREDENTIALS_FULL_URI" : "placeholder-replaced-at-runtime" ,
679
+ },
680
+ },
681
+ "credential source only relative ECS URI set" : {
682
+ expectedAccessKey : "AKID" ,
683
+ expectedSecretKey : "SECRET" ,
684
+ envVar : map [string ]string {
685
+ "AWS_PROFILE" : "ecscontainer" ,
686
+ "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" : "/ECS" ,
687
+ },
688
+ configFile : filepath .Join ("testdata" , "config_source_shared" ),
689
+ },
690
+ "credential source only full ECS URI set" : {
691
+ expectedAccessKey : "AKID-Full-Path" ,
692
+ expectedSecretKey : "SECRET-Full-Path" ,
693
+ envVar : map [string ]string {
694
+ "AWS_CONTAINER_CREDENTIALS_FULL_URI" : "placeholder-replaced-at-runtime" ,
695
+ "AWS_PROFILE" : "ecscontainer" ,
696
+ },
697
+ configFile : filepath .Join ("testdata" , "config_source_shared" ),
698
+ },
699
+ "credential source relative ECS URI has precedence over full" : {
700
+ expectedAccessKey : "AKID" ,
701
+ expectedSecretKey : "SECRET" ,
702
+ envVar : map [string ]string {
703
+ "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" : "/ECS" ,
704
+ "AWS_CONTAINER_CREDENTIALS_FULL_URI" : "placeholder-replaced-at-runtime" ,
705
+ "AWS_PROFILE" : "ecscontainer" ,
706
+ },
707
+ configFile : filepath .Join ("testdata" , "config_source_shared" ),
708
+ },
709
+ }
710
+
711
+ for name , tc := range testCases {
712
+ t .Run (name , func (t * testing.T ) {
713
+ endpointResolver , cleanupFn := setupCredentialsEndpoints ()
714
+ defer cleanupFn ()
715
+ restoreEnv := awstesting .StashEnv ()
716
+ defer awstesting .PopEnv (restoreEnv )
717
+ var sharedConfigFiles []string
718
+ if tc .configFile != "" {
719
+ sharedConfigFiles = append (sharedConfigFiles , tc .configFile )
720
+ }
721
+ opts := []func (* LoadOptions ) error {
722
+ WithEndpointResolverWithOptions (endpointResolver ),
723
+ WithRetryer (func () aws.Retryer { return aws.NopRetryer {} }),
724
+ WithSharedConfigFiles (sharedConfigFiles ),
725
+ WithSharedCredentialsFiles ([]string {}),
726
+ }
727
+ for k , v := range tc .envVar {
728
+ // since we don't know the value of this until the server starts
729
+ if k == "AWS_CONTAINER_CREDENTIALS_FULL_URI" {
730
+ v = ecsMetadataServerURL + "/ECSFullPath"
731
+ }
732
+ os .Setenv (k , v )
733
+ }
734
+ cfg , err := LoadDefaultConfig (context .TODO (), opts ... )
735
+ if err != nil {
736
+ t .Fatalf ("could not load config: %s" , err )
737
+ }
738
+ actual , err := cfg .Credentials .Retrieve (context .TODO ())
739
+ if err != nil {
740
+ t .Fatalf ("could not retrieve credentials: %s" , err )
741
+ }
742
+ if actual .AccessKeyID != tc .expectedAccessKey {
743
+ t .Errorf ("expected access key to be %s, got %s" , tc .expectedAccessKey , actual .AccessKeyID )
744
+ }
745
+ if actual .SecretAccessKey != tc .expectedSecretKey {
746
+ t .Errorf ("expected secret key to be %s, got %s" , tc .expectedSecretKey , actual .SecretAccessKey )
747
+ }
748
+ })
749
+ }
750
+
751
+ }
752
+
607
753
type stubErrorClient struct {
608
754
err error
609
755
}
0 commit comments