Skip to content

Commit c2ec655

Browse files
committed
use the same provider precedence in linux/windows, make ECS-A prefer SSM over EC2 Creds
1 parent a94a6db commit c2ec655

File tree

7 files changed

+216
-316
lines changed

7 files changed

+216
-316
lines changed

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/credentials/providers/instance_credentials_provider.go

Lines changed: 91 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/credentials/providers/instance_credentials_provider_linux.go

Lines changed: 0 additions & 49 deletions
This file was deleted.

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/credentials/providers/instance_credentials_provider_windows.go

Lines changed: 0 additions & 107 deletions
This file was deleted.

ecs-agent/credentials/providers/instance_credentials_provider.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,71 @@ func (p *InstanceCredentialsProvider) Retrieve(ctx context.Context) (aws.Credent
3232
return aws.Credentials{}, err
3333
}
3434

35+
// NewInstanceCredentialsCache returns a chain of instance credentials providers wrapped in a credentials cache.
36+
// The instance credentials chain is the default credentials chain plus the "rotating shared credentials provider",
37+
// so credentials will be checked in this order:
38+
//
39+
// 1. Env vars (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY).
40+
//
41+
// 2. Shared credentials file (https://docs.aws.amazon.com/ses/latest/DeveloperGuide/create-shared-credentials-file.html) (file at ~/.aws/credentials containing access key id and secret access key).
42+
//
43+
// 3. EC2 role credentials. This is an IAM role that the user specifies when they launch their EC2 container instance (ie ecsInstanceRole (https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html)).
44+
//
45+
// 4. Rotating shared credentials file located at /rotatingcreds/credentials
46+
//
47+
// The default credential chain provided by the SDK includes:
48+
// * EnvProvider
49+
// * SharedCredentialsProvider
50+
// * RemoteCredProvider (EC2RoleProvider)
51+
//
52+
// In the case of ECS-A, there are a couple considerations:
53+
//
54+
// * On Windows, the `SharedCredentialsProvider` takes
55+
// precedence over the `RotatingSharedCredentialsProvider` and this results
56+
// in the credentials not being refreshed. To mitigate this issue, we will
57+
// reorder the credential chain and ensure that `RotatingSharedCredentialsProvider`
58+
// takes precedence over the `SharedCredentialsProvider` for ECS-A.
59+
//
60+
// * On EC2, the `EC2RoleProvider` takes precedence over the `RotatingSharedCredentialsProvider`.
61+
// Any attempt to run ECS-A on EC2 with SSM credentials will fail if there is an instance role
62+
// attached to the EC2 instance. Prioritizing `RotatingSharedCredentialsProvider` over the
63+
// `EC2RoleProvider` ensures that SSM credentials will be used if they are available,
64+
// and the EC2 credentials will only be used as a last-resort.
65+
66+
func NewInstanceCredentialsCache(
67+
isExternal bool,
68+
rotatingSharedCreds aws.CredentialsProvider,
69+
imdsClient ec2rolecreds.GetMetadataAPIClient,
70+
) *aws.CredentialsCache {
71+
var providers []aws.CredentialsProvider
72+
73+
// If imdsClient is nil, the SDK will default to the EC2 IMDS client.
74+
// Pass a non-nil imdsClient to stub it out in tests.
75+
options := func(o *ec2rolecreds.Options) {
76+
o.Client = imdsClient
77+
}
78+
79+
if isExternal {
80+
providers = []aws.CredentialsProvider{
81+
envCreds,
82+
rotatingSharedCreds,
83+
sharedCreds,
84+
ec2rolecreds.New(options),
85+
}
86+
} else {
87+
providers = []aws.CredentialsProvider{
88+
defaultCreds(options),
89+
rotatingSharedCreds,
90+
}
91+
}
92+
93+
return aws.NewCredentialsCache(
94+
&InstanceCredentialsProvider{
95+
providers: providers,
96+
},
97+
)
98+
}
99+
35100
func defaultCreds(options func(*ec2rolecreds.Options)) aws.CredentialsProviderFunc {
36101
return func(ctx context.Context) (aws.Credentials, error) {
37102
cfg, err := config.LoadDefaultConfig(ctx, config.WithEC2RoleCredentialOptions(options))
@@ -43,3 +108,29 @@ func defaultCreds(options func(*ec2rolecreds.Options)) aws.CredentialsProviderFu
43108

44109
}
45110
}
111+
112+
var envCreds = aws.CredentialsProviderFunc(func(ctx context.Context) (aws.Credentials, error) {
113+
cfg, err := config.NewEnvConfig()
114+
return cfg.Credentials, err
115+
})
116+
117+
var sharedCreds = aws.CredentialsProviderFunc(func(ctx context.Context) (aws.Credentials, error) {
118+
// Load the env config to get shared config values from env vars (AWS_PROFILE and AWS_SHARED_CREDENTIALS_FILE).
119+
envCfg, err := config.NewEnvConfig()
120+
if err != nil {
121+
return aws.Credentials{}, err
122+
}
123+
124+
// If shared config env vars are unset, use the default values.
125+
if envCfg.SharedConfigProfile == "" {
126+
envCfg.SharedConfigProfile = config.DefaultSharedConfigProfile
127+
}
128+
if envCfg.SharedCredentialsFile == "" {
129+
envCfg.SharedCredentialsFile = config.DefaultSharedCredentialsFilename()
130+
}
131+
132+
cfg, err := config.LoadSharedConfigProfile(ctx, envCfg.SharedConfigProfile, func(option *config.LoadSharedConfigOptions) {
133+
option.CredentialsFiles = []string{envCfg.SharedCredentialsFile}
134+
})
135+
return cfg.Credentials, err
136+
})

0 commit comments

Comments
 (0)