Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Confused Deputy Prevention #1503

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

Conversation

dricross
Copy link
Contributor

@dricross dricross commented Jan 15, 2025

Description of the issue

To support confused deputy prevention, the CloudWatch Agent needs to be able to pass confused deputy context keys in the headers of STS AssumeRole calls so that dependent service teams can allow their customers to use confused deputy context keys in their role policies.

For background on the confused deputy problem, see: https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html

Description of changes

Enable the CloudWatch Agent to resource confused deputy context keys from environment variables and include the key values in the STS AssumeRole request headers.

License

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Tests

New assume_role integration test created in test repo: https://github.com/aws/amazon-cloudwatch-agent-test/tree/dricross/confused-deputy/test/assume_role. Example run: https://github.com/aws/amazon-cloudwatch-agent/actions/runs/12778135116/job/35673452648. See PR for amazon-cloudwatch-agent-test for more details: aws/amazon-cloudwatch-agent-test#449

Note: the tests are currently failing as the test accounts needs to be specially onboarded with the STS service in order for STS to accept confused deputy keys in the request headers.

Requirements

Before commit the code, please do the following steps.

  1. Run make fmt and make fmt-sh
  2. Run make lint

@dricross dricross requested a review from a team as a code owner January 15, 2025 20:13
}

func TestConfusedDeputyHeaders(t *testing.T) {
mockProvider := mockConfigProvider{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Could we use the mock.Session from github.com/aws/aws-sdk-go/awstesting/mock?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'll take a look at using that instead

Comment on lines +225 to +226
"x-amz-source-arn": sourceArn,
"x-amz-source-account": sourceAccount,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can we make the keys consts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea

client := sts.New(p, cfgs...)
if sourceAccount != "" && sourceArn != "" {
client.Handlers.Sign.PushFront(func(r *request.Request) {
r.ApplyOptions(request.WithSetRequestHeaders(map[string]string{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Could also add to the request headers directly like in

req.HTTPRequest.Header.Set(name, value)

In the end, that's all the WithSetRequestHeaders does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I'll switch the implementation

Comment on lines +209 to +210
sourceAccount = os.Getenv(envconfig.AMZ_SOURCE_ACCOUNT) // populates the "x-amz-source-account" header
sourceArn = os.Getenv(envconfig.AMZ_SOURCE_ARN) // populates the "x-amz-source-arn" header
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So these should not be modifiable after start up?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do these get configured on EC2? The systemd service won't pick up external environment variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, at this time these should not be modifiable after startup.

On EC2, when the agent is managed by systemd, these are set via the systemd service file, e.g.:

[Unit]
Description=Amazon CloudWatch Agent
After=network.target

[Service]
Type=simple
ExecStart=/opt/aws/amazon-cloudwatch-agent/bin/start-amazon-cloudwatch-agent
KillMode=process
Restart=on-failure
RestartSec=60s
Environment="AMZ_SOURCE_ACCOUNT=<some account>"
Environment="AMZ_SOURCE_ARN=<some ARN>"

[Install]
WantedBy=multi-user.target

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants