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 #449

Merged
merged 29 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1c093e3
Create first agent assume role test
dricross Jan 9, 2025
89e2d3a
Rename assume_role test to credentials_file
dricross Jan 9, 2025
272aa0d
Rename agent_assume_role to assume_role
dricross Jan 9, 2025
20bea9d
Use bash sudo commands instead of go built-ins
dricross Jan 10, 2025
5b8f9c7
Create 4 iam roles
dricross Jan 12, 2025
84e4d17
Fix role reference
dricross Jan 13, 2025
c7f6aeb
Create test suite
dricross Jan 13, 2025
9e08394
Run the test suite
dricross Jan 13, 2025
9c40b83
Fix path to service config
dricross Jan 13, 2025
f6f7748
Temporarily remove other tests
dricross Jan 13, 2025
69d7c45
Add more helpful errors
dricross Jan 14, 2025
ffa86d1
Fix instanceArn argument
dricross Jan 14, 2025
eb5551e
Fix output
dricross Jan 14, 2025
7438bde
More debugging info
dricross Jan 14, 2025
1ff94a0
More debugging
dricross Jan 14, 2025
394ca54
Use different delimiter for sed commands
dricross Jan 14, 2025
dcd96e4
sed commands need to be sudo
dricross Jan 14, 2025
f167c03
Fix role_arn setting in agent config
dricross Jan 14, 2025
f9e0d70
Use role arn instead of instance arn in config
dricross Jan 14, 2025
aef3939
Fixes and stuff
dricross Jan 15, 2025
d49b1ad
terraform fmt
dricross Jan 15, 2025
cbf2c86
Fix incorrect source arn/account tests
dricross Jan 28, 2025
0e07445
Re-add all the other tests
dricross Jan 28, 2025
6297669
Pass account id instead of hardcoding it
dricross Jan 29, 2025
c3111be
Improve validations
dricross Jan 29, 2025
134d2b7
Move daemon reload after all service file manipulation
dricross Jan 29, 2025
f2fa641
Minor PR feedback
dricross Jan 31, 2025
efe0716
Merge branch 'main' into dricross/confused-deputy
dricross Jan 31, 2025
dbcc6f3
Re-add required terraform variables
dricross Jan 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions environment/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type MetaData struct {
EKSClusterName string
ProxyUrl string
AssumeRoleArn string
InstanceArn string
InstanceId string
InstancePlatform string
AgentStartCommand string
Expand Down Expand Up @@ -81,6 +82,7 @@ type MetaDataStrings struct {
EKSClusterName string
ProxyUrl string
AssumeRoleArn string
InstanceArn string
InstanceId string
InstancePlatform string
AgentStartCommand string
Expand Down Expand Up @@ -179,6 +181,10 @@ func registerAssumeRoleArn(dataString *MetaDataStrings) {
flag.StringVar(&(dataString.AssumeRoleArn), "assumeRoleArn", "", "Arn for assume role to be used")
}

func registerInstanceArn(dataString *MetaDataStrings) {
flag.StringVar(&(dataString.InstanceArn), "instanceArn", "", "ec2 instance ARN that is being used by a test")
}

func registerInstanceId(dataString *MetaDataStrings) {
flag.StringVar(&(dataString.InstanceId), "instanceId", "", "ec2 instance ID that is being used by a test")
}
Expand Down Expand Up @@ -289,6 +295,7 @@ func RegisterEnvironmentMetaDataFlags() *MetaDataStrings {
registerExcludedTests(registeredMetaDataStrings)
registerProxyUrl(registeredMetaDataStrings)
registerAssumeRoleArn(registeredMetaDataStrings)
registerInstanceArn(registeredMetaDataStrings)
registerInstanceId(registeredMetaDataStrings)
registerInstancePlatform(registeredMetaDataStrings)
registerAgentStartCommand(registeredMetaDataStrings)
Expand All @@ -314,6 +321,7 @@ func GetEnvironmentMetaData() *MetaData {
metaDataStorage.CaCertPath = registeredMetaDataStrings.CaCertPath
metaDataStorage.ProxyUrl = registeredMetaDataStrings.ProxyUrl
metaDataStorage.AssumeRoleArn = registeredMetaDataStrings.AssumeRoleArn
metaDataStorage.InstanceArn = registeredMetaDataStrings.InstanceArn
metaDataStorage.InstanceId = registeredMetaDataStrings.InstanceId
metaDataStorage.InstancePlatform = registeredMetaDataStrings.InstancePlatform
metaDataStorage.AgentStartCommand = registeredMetaDataStrings.AgentStartCommand
Expand Down
7 changes: 6 additions & 1 deletion generator/test_case_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ var testTypeToTestConfig = map[string][]testConfig{
targets: map[string]map[string]struct{}{"os": {"ol9": {}}},
},
{
testDir: "./test/assume_role",
testDir: "./test/credentials_file",
terraformDir: "terraform/ec2/creds",
targets: map[string]map[string]struct{}{"os": {"al2": {}}},
},
Expand All @@ -121,6 +121,11 @@ var testTypeToTestConfig = map[string][]testConfig{
testDir: "./test/agent_otel_merging",
targets: map[string]map[string]struct{}{"os": {"al2": {}}, "arc": {"amd64": {}}},
},
{
testDir: "./test/assume_role",
terraformDir: "terraform/ec2/assume_role",
targets: map[string]map[string]struct{}{"os": {"al2": {}}},
},
},
/*
You can only place 1 mac instance on a dedicate host a single time.
Expand Down
221 changes: 221 additions & 0 deletions terraform/ec2/assume_role/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT

module "common" {
source = "../../common"
}

module "basic_components" {
source = "../../basic_components"

region = var.region
}

#####################################################################
# Generate EC2 Key Pair for log in access to EC2
#####################################################################

resource "tls_private_key" "ssh_key" {
count = var.ssh_key_name == "" ? 1 : 0
algorithm = "RSA"
rsa_bits = 4096
}

resource "aws_key_pair" "aws_ssh_key" {
count = var.ssh_key_name == "" ? 1 : 0
key_name = "ec2-key-pair-${module.common.testing_id}"
public_key = tls_private_key.ssh_key[0].public_key_openssh
}

locals {
ssh_key_name = var.ssh_key_name != "" ? var.ssh_key_name : aws_key_pair.aws_ssh_key[0].key_name
private_key_content = var.ssh_key_name != "" ? var.ssh_key_value : tls_private_key.ssh_key[0].private_key_pem
// Canary downloads latest binary. Integration test downloads binary connect to git hash.
binary_uri = var.is_canary ? "${var.s3_bucket}/release/amazon_linux/${var.arc}/latest/${var.binary_name}" : "${var.s3_bucket}/integration-test/binary/${var.cwa_github_sha}/linux/${var.arc}/${var.binary_name}"
}


#####################################################################
# Generate EC2 Instance and execute test commands
#####################################################################
resource "aws_instance" "cwagent" {
ami = data.aws_ami.latest.id
instance_type = var.ec2_instance_type
key_name = local.ssh_key_name
iam_instance_profile = module.basic_components.instance_profile
vpc_security_group_ids = [module.basic_components.security_group]
associate_public_ip_address = true
instance_initiated_shutdown_behavior = "terminate"

metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}

tags = {
Name = "cwagent-integ-test-ec2-${var.test_name}-${module.common.testing_id}"
}
}

#####################################################################
# Generate IAM Roles for Credentials
#####################################################################

locals {
roles = {
no_context_keys = {
suffix = ""
condition = {}
}
source_arn_key = {
suffix = "-source_arn_key"
condition = {
"aws:SourceArn" = aws_instance.cwagent.arn
}
}
source_account_key = {
suffix = "-source_account_key"
condition = {
"aws:SourceAccount" = "506463145083"
dricross marked this conversation as resolved.
Show resolved Hide resolved
}
}
all_context_keys = {
suffix = "-all_context_keys"
condition = {
"aws:SourceArn" = aws_instance.cwagent.arn
"aws:SourceAccount" = "506463145083"
}
}
}
}

resource "aws_iam_role" "roles" {
for_each = local.roles

name = "cwa-integ-assume-role-${module.common.testing_id}${each.value.suffix}"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
AWS = module.basic_components.role_arn
}
Condition = length(each.value.condition) > 0 ? {
StringEquals = each.value.condition
} : {}
}
]
})
}

resource "aws_iam_role_policy" "cloudwatch_policy" {
for_each = aws_iam_role.roles

name = "${each.value.name}_policy"
role = each.value.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"cloudwatch:PutMetricData",
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricStatistics",
"cloudwatch:GetMetricData",
"logs:PutRetentionPolicy",
"logs:PutLogEvents",
"logs:GetLogEvents",
"logs:DescribeLogStreams",
"logs:DescribeLogGroups",
"logs:DeleteLogStream",
"logs:DeleteLogGroup",
"logs:CreateLogStream",
"logs:CreateLogGroup",
"ssm:List*",
"ssm:Get*",
"ssm:Describe*",
"s3:PutObject",
"s3:ListBucket",
"s3:GetObjectAcl",
"s3:GetObject"
]
Effect = "Allow"
Resource = "*"
}
]
})
}

#####################################################################
# Run the integration test
#####################################################################

resource "null_resource" "integration_test_setup" {
connection {
type = "ssh"
user = var.user
private_key = local.private_key_content
host = aws_instance.cwagent.public_ip
}

# Prepare Integration Test
provisioner "remote-exec" {
inline = [
"echo sha ${var.cwa_github_sha}",
"sudo cloud-init status --wait",
"echo clone and install agent",
"rm -rf amazon-cloudwatch-agent-test",
dricross marked this conversation as resolved.
Show resolved Hide resolved
"git clone --branch ${var.github_test_repo_branch} ${var.github_test_repo}",
"cd amazon-cloudwatch-agent-test",
"aws s3 cp s3://${local.binary_uri} .",
"export PATH=$PATH:/snap/bin:/usr/local/go/bin",
var.install_agent,
]
}

depends_on = [
aws_iam_role.roles,
aws_iam_role_policy.cloudwatch_policy
]
}

resource "null_resource" "integration_test_run" {
connection {
type = "ssh"
user = var.user
private_key = local.private_key_content
host = aws_instance.cwagent.public_ip
}

#Run sanity check and integration test
provisioner "remote-exec" {
inline = [
"echo prepare environment",
"export LOCAL_STACK_HOST_NAME=${var.local_stack_host_name}",
"export AWS_REGION=${var.region}",
"export PATH=$PATH:/snap/bin:/usr/local/go/bin",
"echo run integration test",
"cd ~/amazon-cloudwatch-agent-test",
"echo run sanity test && go test ./test/sanity -p 1 -v",
"echo base assume role arn is ${aws_iam_role.roles["no_context_keys"].arn}",
"go test ${var.test_dir} -p 1 -timeout 1h -computeType=EC2 -bucket=${var.s3_bucket} -plugins='${var.plugin_tests}' -cwaCommitSha=${var.cwa_github_sha} -caCertPath=${var.ca_cert_path} -assumeRoleArn=${aws_iam_role.roles["no_context_keys"].arn} -instanceArn=${aws_instance.cwagent.arn} -v"
]
}

depends_on = [
null_resource.integration_test_setup,
]
}

data "aws_ami" "latest" {
most_recent = true

filter {
name = "name"
values = [var.ami]
}
}
6 changes: 6 additions & 0 deletions terraform/ec2/assume_role/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT

provider "aws" {
region = var.region
}
Loading