@@ -16,9 +16,11 @@ import (
16
16
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
17
17
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
18
18
"github.com/aws/aws-sdk-go/aws/endpoints"
19
+ "github.com/aws/aws-sdk-go/aws/request"
19
20
"github.com/aws/aws-sdk-go/aws/session"
20
21
"github.com/aws/aws-sdk-go/service/sts"
21
22
23
+ "github.com/aws/amazon-cloudwatch-agent/cfg/envconfig"
22
24
"github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/stats/agent"
23
25
)
24
26
@@ -174,7 +176,7 @@ func (s *stsCredentialProvider) Retrieve() (credentials.Value, error) {
174
176
175
177
func newStsCredentials (c client.ConfigProvider , roleARN string , region string ) * credentials.Credentials {
176
178
regional := & stscreds.AssumeRoleProvider {
177
- Client : sts . New (c , & aws.Config {
179
+ Client : newStsClient (c , & aws.Config {
178
180
Region : aws .String (region ),
179
181
STSRegionalEndpoint : endpoints .RegionalSTSEndpoint ,
180
182
HTTPClient : & http.Client {Timeout : 1 * time .Minute },
@@ -188,7 +190,7 @@ func newStsCredentials(c client.ConfigProvider, roleARN string, region string) *
188
190
fallbackRegion := getFallbackRegion (region )
189
191
190
192
partitional := & stscreds.AssumeRoleProvider {
191
- Client : sts . New (c , & aws.Config {
193
+ Client : newStsClient (c , & aws.Config {
192
194
Region : aws .String (fallbackRegion ),
193
195
Endpoint : aws .String (getFallbackEndpoint (fallbackRegion )),
194
196
STSRegionalEndpoint : endpoints .RegionalSTSEndpoint ,
@@ -203,6 +205,36 @@ func newStsCredentials(c client.ConfigProvider, roleARN string, region string) *
203
205
return credentials .NewCredentials (& stsCredentialProvider {regional : regional , partitional : partitional })
204
206
}
205
207
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
+
206
238
// The partitional STS endpoint used to fallback when regional STS endpoint is not activated.
207
239
func getFallbackEndpoint (region string ) string {
208
240
partition := getPartition (region )
0 commit comments