@@ -16,9 +16,11 @@ import (
1616 "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
1717 "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
1818 "github.com/aws/aws-sdk-go/aws/endpoints"
19+ "github.com/aws/aws-sdk-go/aws/request"
1920 "github.com/aws/aws-sdk-go/aws/session"
2021 "github.com/aws/aws-sdk-go/service/sts"
2122
23+ "github.com/aws/amazon-cloudwatch-agent/cfg/envconfig"
2224 "github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/stats/agent"
2325)
2426
@@ -174,7 +176,7 @@ func (s *stsCredentialProvider) Retrieve() (credentials.Value, error) {
174176
175177func newStsCredentials (c client.ConfigProvider , roleARN string , region string ) * credentials.Credentials {
176178 regional := & stscreds.AssumeRoleProvider {
177- Client : sts . New (c , & aws.Config {
179+ Client : newStsClient (c , & aws.Config {
178180 Region : aws .String (region ),
179181 STSRegionalEndpoint : endpoints .RegionalSTSEndpoint ,
180182 HTTPClient : & http.Client {Timeout : 1 * time .Minute },
@@ -188,7 +190,7 @@ func newStsCredentials(c client.ConfigProvider, roleARN string, region string) *
188190 fallbackRegion := getFallbackRegion (region )
189191
190192 partitional := & stscreds.AssumeRoleProvider {
191- Client : sts . New (c , & aws.Config {
193+ Client : newStsClient (c , & aws.Config {
192194 Region : aws .String (fallbackRegion ),
193195 Endpoint : aws .String (getFallbackEndpoint (fallbackRegion )),
194196 STSRegionalEndpoint : endpoints .RegionalSTSEndpoint ,
@@ -203,6 +205,36 @@ func newStsCredentials(c client.ConfigProvider, roleARN string, region string) *
203205 return credentials .NewCredentials (& stsCredentialProvider {regional : regional , partitional : partitional })
204206}
205207
208+ const (
209+ SourceArnHeaderKey = "x-amz-source-arn"
210+ SourceAccountHeaderKey = "x-amz-source-account"
211+ )
212+
213+ // newStsClient creates a new STS client with the provided config and options.
214+ // Additionally, if specific environment variables are set, it also appends the confused deputy headers to requests
215+ // made by the client. These headers allow resource-based policies to limit the permissions that a service has to
216+ // a specific resource. Note that BOTH environment variables need to contain non-empty values in order for the headers
217+ // to be set.
218+ //
219+ // See https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html#cross-service-confused-deputy-prevention
220+ func newStsClient (p client.ConfigProvider , cfgs ... * aws.Config ) * sts.STS {
221+
222+ sourceAccount := os .Getenv (envconfig .AmzSourceAccount )
223+ sourceArn := os .Getenv (envconfig .AmzSourceArn )
224+
225+ client := sts .New (p , cfgs ... )
226+ if sourceAccount != "" && sourceArn != "" {
227+ client .Handlers .Sign .PushFront (func (r * request.Request ) {
228+ r .HTTPRequest .Header .Set (SourceArnHeaderKey , sourceArn )
229+ r .HTTPRequest .Header .Set (SourceAccountHeaderKey , sourceAccount )
230+ })
231+
232+ log .Printf ("I! Found confused deputy header environment variables: source account: %q, source arn: %q" , sourceAccount , sourceArn )
233+ }
234+
235+ return client
236+ }
237+
206238// The partitional STS endpoint used to fallback when regional STS endpoint is not activated.
207239func getFallbackEndpoint (region string ) string {
208240 partition := getPartition (region )
0 commit comments