ECS Task Definition Logging Enabled
Overview
This check verifies that all containers within your Amazon ECS task definitions have logging configured. Specifically, it ensures each container has a logConfiguration with a non-null logDriver in the latest active revision.
Container logging is essential for monitoring application behavior, troubleshooting issues, and maintaining security visibility across your containerized workloads.
Risk
Without container logging enabled:
- Blind spots in security monitoring: Intrusions and data exfiltration can go undetected
- No audit trail: Missing logs compromise compliance posture and make forensic investigations impossible
- Slower incident response: Increased mean time to recovery (MTTR) when issues occur
- Operational blindness: Application errors and performance issues are harder to diagnose
Severity: High
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify ECS task definitions
- An existing CloudWatch Log Group (or permission to create one)
IAM permissions needed
Your IAM user or role needs these permissions:
ecs:RegisterTaskDefinitionecs:DescribeTaskDefinitionlogs:CreateLogGroup(if creating a new log group)iam:PassRole(if the task uses an execution role)
The ECS task execution role needs:
logs:CreateLogStreamlogs:PutLogEvents
The managed policy AmazonECSTaskExecutionRolePolicy includes these permissions.
AWS Console Method
- Open the Amazon ECS console
- In the left navigation, click Task definitions
- Select the task definition you need to update
- Click Create new revision
- Scroll down to the Container definitions section
- For each container listed:
- Click the container name to expand its settings
- Scroll to Log configuration
- For Log driver, select awslogs
- Enter the following options:
- awslogs-group:
/ecs/<your-task-family>(create this log group first if it does not exist) - awslogs-region:
us-east-1 - awslogs-stream-prefix:
ecs
- awslogs-group:
- Click Create to register the new revision
- Update your ECS service to use the new task definition revision
AWS CLI (optional)
First, create a CloudWatch Log Group if you do not have one:
aws logs create-log-group \
--log-group-name /ecs/my-app \
--region us-east-1
Then register a new task definition revision with logging enabled:
aws ecs register-task-definition \
--family my-app \
--execution-role-arn arn:aws:iam::<account-id>:role/ecsTaskExecutionRole \
--network-mode awsvpc \
--requires-compatibilities FARGATE \
--cpu 256 \
--memory 512 \
--container-definitions '[
{
"name": "my-container",
"image": "nginx:latest",
"essential": true,
"portMappings": [
{
"containerPort": 80,
"protocol": "tcp"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]' \
--region us-east-1
Replace <account-id> with your AWS account ID and adjust the container configuration as needed.
To update an existing service to use the new revision:
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--task-definition my-app \
--region us-east-1
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: ECS Task Definition with logging enabled
Parameters:
TaskFamily:
Type: String
Default: my-app
Description: The family name for the task definition
ContainerImage:
Type: String
Default: nginx:latest
Description: The Docker image for the container
Resources:
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /ecs/${TaskFamily}
RetentionInDays: 30
TaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Ref TaskFamily
ExecutionRoleArn: !GetAtt TaskExecutionRole.Arn
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: '256'
Memory: '512'
ContainerDefinitions:
- Name: !Ref TaskFamily
Image: !Ref ContainerImage
Essential: true
PortMappings:
- ContainerPort: 80
Protocol: tcp
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
Outputs:
TaskDefinitionArn:
Description: The ARN of the task definition
Value: !Ref TaskDefinition
LogGroupName:
Description: The name of the CloudWatch log group
Value: !Ref LogGroup
Terraform (optional)
variable "task_family" {
description = "The family name for the task definition"
type = string
default = "my-app"
}
variable "container_image" {
description = "The Docker image for the container"
type = string
default = "nginx:latest"
}
resource "aws_cloudwatch_log_group" "ecs_logs" {
name = "/ecs/${var.task_family}"
retention_in_days = 30
}
resource "aws_iam_role" "ecs_task_execution" {
name = "${var.task_family}-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy_attachment" "ecs_task_execution" {
role = aws_iam_role.ecs_task_execution.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
resource "aws_ecs_task_definition" "main" {
family = var.task_family
execution_role_arn = aws_iam_role.ecs_task_execution.arn
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = jsonencode([
{
name = var.task_family
image = var.container_image
essential = true
portMappings = [
{
containerPort = 80
protocol = "tcp"
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = aws_cloudwatch_log_group.ecs_logs.name
"awslogs-region" = "us-east-1"
"awslogs-stream-prefix" = "ecs"
}
}
}
])
}
output "task_definition_arn" {
description = "The ARN of the task definition"
value = aws_ecs_task_definition.main.arn
}
output "log_group_name" {
description = "The name of the CloudWatch log group"
value = aws_cloudwatch_log_group.ecs_logs.name
}
Verification
After enabling logging, verify the configuration:
- Go to ECS > Task definitions in the AWS Console
- Select your task definition and view the latest revision
- Confirm each container shows awslogs as the log driver
- Run a task using the new definition
- Check CloudWatch > Log groups to confirm logs are appearing
CLI verification commands
Describe the task definition to verify logging configuration:
aws ecs describe-task-definition \
--task-definition my-app \
--query 'taskDefinition.containerDefinitions[*].{Name:name,LogDriver:logConfiguration.logDriver,LogGroup:logConfiguration.options."awslogs-group"}' \
--output table \
--region us-east-1
Check that logs are being written to CloudWatch:
aws logs describe-log-streams \
--log-group-name /ecs/my-app \
--order-by LastEventTime \
--descending \
--limit 5 \
--region us-east-1
Additional Resources
- Using the awslogs log driver
- AWS Security Hub ECS.9 control
- AWS Config ecs-task-definition-log-configuration rule
- ECS Task Definition Parameters
Notes
- Task definition revisions are immutable: You cannot modify an existing revision. You must create a new revision with logging enabled, then update your services to use it.
- Execution role required: When using the
awslogsdriver, your task needs an execution role with permissions to write to CloudWatch Logs. The managed policyAmazonECSTaskExecutionRolePolicyprovides these permissions. - Log retention costs: CloudWatch Logs charges for storage. Set an appropriate retention period (e.g., 30 days) to manage costs.
- Alternative log drivers: While
awslogsis the most common choice, ECS also supportssplunk,fluentd,gelf, and other drivers depending on your logging infrastructure. - All containers need logging: This check validates that every container in the task definition has logging configured, not just the primary container.