Skip to content

Commit

Permalink
Conditionally enable ECS Exec auditing
Browse files Browse the repository at this point in the history
* Logs all activity with ECS Exec
* Allows the containers to send logs to S3
  • Loading branch information
Stretch96 committed Jul 18, 2024
1 parent c44893c commit 762eb8f
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 1 deletion.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_iam_policy.infrastructure_ecs_cluster_service_scheduled_task_ecs_run_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_service_scheduled_task_pass_role_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_service_task_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_service_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_service_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_service_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_service_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_service_task_execution_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
Expand Down Expand Up @@ -197,6 +199,8 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_scheduled_task_ecs_run_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_scheduled_task_pass_role_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_execution_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
Expand Down Expand Up @@ -410,6 +414,7 @@ This project creates and manages resources within an AWS account for infrastruct
| <a name="input_infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold"></a> [infrastructure\_ecs\_cluster\_ecs\_asg\_diff\_alert\_threshold](#input\_infrastructure\_ecs\_cluster\_ecs\_asg\_diff\_alert\_threshold) | Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert | `number` | n/a | yes |
| <a name="input_infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention"></a> [infrastructure\_ecs\_cluster\_ecs\_asg\_diff\_metric\_lambda\_log\_retention](#input\_infrastructure\_ecs\_cluster\_ecs\_asg\_diff\_metric\_lambda\_log\_retention) | Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda | `number` | n/a | yes |
| <a name="input_infrastructure_ecs_cluster_enable_debug_mode"></a> [infrastructure\_ecs\_cluster\_enable\_debug\_mode](#input\_infrastructure\_ecs\_cluster\_enable\_debug\_mode) | Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs) | `bool` | n/a | yes |
| <a name="input_infrastructure_ecs_cluster_enable_execute_command_logging"></a> [infrastructure\_ecs\_cluster\_enable\_execute\_command\_logging](#input\_infrastructure\_ecs\_cluster\_enable\_execute\_command\_logging) | Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket | `bool` | n/a | yes |
| <a name="input_infrastructure_ecs_cluster_instance_type"></a> [infrastructure\_ecs\_cluster\_instance\_type](#input\_infrastructure\_ecs\_cluster\_instance\_type) | The instance type for EC2 instances launched in the ECS cluster | `string` | n/a | yes |
| <a name="input_infrastructure_ecs_cluster_max_instance_lifetime"></a> [infrastructure\_ecs\_cluster\_max\_instance\_lifetime](#input\_infrastructure\_ecs\_cluster\_max\_instance\_lifetime) | Maximum lifetime in seconds of an instance within the ECS cluster | `number` | n/a | yes |
| <a name="input_infrastructure_ecs_cluster_max_size"></a> [infrastructure\_ecs\_cluster\_max\_size](#input\_infrastructure\_ecs\_cluster\_max\_size) | Maximum number of instances for the ECS cluster | `number` | n/a | yes |
Expand Down
42 changes: 42 additions & 0 deletions ecs-cluster-infrastructure-service.tf
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,48 @@ resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_service_ta
policy_arn = aws_iam_policy.infrastructure_ecs_cluster_service_task_ssm_create_channels[each.key].arn
}

resource "aws_iam_policy" "infrastructure_ecs_cluster_service_task_ecs_exec_log_s3_write" {
for_each = {
for k, v in local.infrastructure_ecs_cluster_services : k => v if v["enable_execute_command"] == true
}

name = "${local.resource_prefix}-${substr(sha512("ecs-cluster-service-task-${each.key}-ecs-exec-log-s3-write"), 0, 6)}"
description = "${local.resource_prefix}-ecs-cluster-service-task-${each.key}-ecs-exec-log-s3-write"
policy = templatefile("${path.root}/policies/s3-object-write.json.tpl", {
bucket_arn = aws_s3_bucket.infrastructure_logs[0].arn
path = "/ecs-exec/*"
})
}

resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_service_task_ecs_exec_log_s3_write" {
for_each = {
for k, v in local.infrastructure_ecs_cluster_services : k => v if v["enable_execute_command"] == true
}

role = aws_iam_role.infrastructure_ecs_cluster_service_task[each.key].name
policy_arn = aws_iam_policy.infrastructure_ecs_cluster_service_task_ecs_exec_log_s3_write[each.key].arn
}

resource "aws_iam_policy" "infrastructure_ecs_cluster_service_task_ecs_exec_log_kms_decrypt" {
for_each = {
for k, v in local.infrastructure_ecs_cluster_services : k => v if v["enable_execute_command"] == true && local.infrastructure_kms_encryption
}

name = "${local.resource_prefix}-${substr(sha512("ecs-cluster-service-task-${each.key}-ecs-exec-log-kms-decrypt"), 0, 6)}"
description = "${local.resource_prefix}-ecs-cluster-service-task-${each.key}-ecs-exec-log-kms-decrypt"
policy = templatefile("${path.root}/policies/kms-decrypt.json.tpl", {
kms_key_arn = aws_kms_key.infrastructure[0].arn
})
}
resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_service_task_ecs_exec_log_kms_decrypt" {
for_each = {
for k, v in local.infrastructure_ecs_cluster_services : k => v if v["enable_execute_command"] == true && local.infrastructure_kms_encryption
}

role = aws_iam_role.infrastructure_ecs_cluster_service_task[each.key].name
policy_arn = aws_iam_policy.infrastructure_ecs_cluster_service_task_ecs_exec_log_kms_decrypt[each.key].arn
}

resource "aws_iam_policy" "infrastructure_ecs_cluster_service_task_custom" {
for_each = merge([
for service_name, service in local.infrastructure_ecs_cluster_services : {
Expand Down
14 changes: 14 additions & 0 deletions ecs-cluster-infrastructure.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ resource "aws_ecs_cluster" "infrastructure" {
name = "containerInsights"
value = "enabled"
}

dynamic "configuration" {
for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []
execute_command_configuration {
kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null
logging = "OVERRIDE"

log_configuration {
s3_bucket_encryption_enabled = true
s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id
s3_key_prefix = "ecs-exec"
}
}
}
}

resource "aws_iam_role" "infrastructure_ecs_cluster" {
Expand Down
7 changes: 7 additions & 0 deletions kms-infrastructure.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ resource "aws_kms_key" "infrastructure" {
{
log_group_arn = length(local.infrastructure_ecs_cluster_services) > 0 && local.infrastructure_kms_encryption ? "arn:aws:logs:${local.aws_region}:${local.aws_account_id}:log-group:${local.resource_prefix}-infrastructure-ecs-cluster-service-logs-*" : ""
}
)}${length(local.infrastructure_ecs_cluster_services) > 0 && local.infrastructure_kms_encryption && local.infrastructure_ecs_cluster_enable_execute_command_logging ? "," : ""}
${templatefile("${path.root}/policies/kms-key-policy-statements/role-allow-encrypt.json.tpl",
{
role_arns = jsonencode([
for k, v in local.infrastructure_ecs_cluster_services : aws_iam_role.infrastructure_ecs_cluster_service_task_execution[k].name if v["enable_execute_command"] == true
])
}
)}${contains([for k, v in local.custom_s3_buckets : (v["cloudfront_dedicated_distribution"] == true || v["cloudfront_infrastructure_ecs_cluster_service"] != null) && v["create_dedicated_kms_key"] == false ? true : false], true) && local.infrastructure_kms_encryption ? "," : ""}
${templatefile("${path.root}/policies/kms-key-policy-statements/cloudfront-distribution-allow.json.tpl",
{
Expand Down
4 changes: 3 additions & 1 deletion locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ locals {
length(local.infrastructure_ecs_cluster_services) != 0 ||
length(local.custom_s3_buckets) != 0 ||
local.enable_cloudformatian_s3_template_store ||
local.enable_infrastructure_vpc_transfer_s3_bucket
local.enable_infrastructure_vpc_transfer_s3_bucket ||
local.infrastructure_ecs_cluster_enable_execute_command_logging
)
logs_bucket_s3_source_arns = concat(
length(local.infrastructure_ecs_cluster_services) != 0 ? [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store[0].arn] : [],
Expand Down Expand Up @@ -169,6 +170,7 @@ locals {
infrastructure_ecs_cluster_ecs_asg_diff_alert_slack = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack
infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie
infrastructure_ecs_cluster_enable_debug_mode = var.infrastructure_ecs_cluster_enable_debug_mode
infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging
infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs
infrastructure_ecs_cluster_enable_ssm_dhmc = local.enable_infrastructure_ecs_cluster ? data.external.ssm_dhmc_setting[0].result.setting_value != "$None" : false
infrastructure_ecs_cluster_user_data = base64encode(
Expand Down
11 changes: 11 additions & 0 deletions policies/kms-key-policy-statements/role-allow-encrypt.json.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
%{if role_arns != "[]"}{
"Effect": "Allow",
"Principal": {
"AWS": ${role_arns}
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
}%{endif}
21 changes: 21 additions & 0 deletions policies/s3-object-write.json.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
"${bucket_arn}${path}"
]
},
{
"Effect": "Allow",
"Action": "s3:GetEncryptionConfiguration",
"Resource": [
"${bucket_arn}"
]
}
]
}
5 changes: 5 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,11 @@ variable "infrastructure_ecs_cluster_enable_debug_mode" {
type = bool
}

variable "infrastructure_ecs_cluster_enable_execute_command_logging" {
description = "Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket"
type = bool
}

variable "infrastructure_ecs_cluster_wafs" {
description = "Map of WAF ACLs to craete, which can be used with service CloudFront distributions"
type = map(object({
Expand Down

0 comments on commit 762eb8f

Please sign in to comment.