Task & Execution Roles: Least Privilege

Keep the execution role and the task role separate, and scope each to exactly what it needs — nothing more.

ECS gives every task two IAM roles, and conflating them is one of the most common security mistakes I see in reviews. They exist for completely different reasons.

Two roles, two jobs

  • Execution role — used by the ECS agent to launch the task: pull the image from ECR, fetch secrets, write logs. Your application code never uses it.
  • Task role — the identity your running application assumes when it calls AWS: reading an S3 bucket, publishing to SQS, querying DynamoDB.

Why the split matters

If you merge them, your application inherits the power to pull any image and read every secret the execution role can reach. That is a huge blast radius for a compromised container. Keep them separate and scope the task role tightly — name the exact buckets, queues, and tables, and prefer resource-level ARNs over *.

Least privilege is not about distrust; it is about limiting the damage of a bad day. Assume one container will eventually be compromised and design so that it can barely do anything.

A quick sniff test

If your task role contains ecr:GetDownloadUrlForLayer or secretsmanager:GetSecretValue, those permissions are almost certainly in the wrong role — they belong to the execution role.

Example

Example · json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadOwnBucketOnly",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::orders-prod-uploads/*"
    },
    {
      "Sid": "PublishToOrdersQueue",
      "Effect": "Allow",
      "Action": "sqs:SendMessage",
      "Resource": "arn:aws:sqs:us-east-1:123456789012:orders-events"
    }
  ]
}

When to use it

  • A security team separates the task execution role from the task role so no application container can accidentally call ECR or CloudWatch Logs APIs.
  • A developer scopes the task role to only allow s3:GetObject on a specific bucket prefix so a compromised container cannot access other buckets.
  • An auditor confirms that no task role has AdministratorAccess by listing all task definitions and cross-referencing their role ARNs against IAM policies.

More examples

Minimal Task Execution Role Policy

Defines the minimal IAM policy for the task execution role — only the permissions ECS needs to pull images from ECR and write logs to CloudWatch.

Example · json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}

Scoped Task Role for S3 Access

Grants the task role read/write access to only one S3 prefix, following least-privilege so a breach cannot access other buckets or paths.

Example · json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["s3:GetObject", "s3:PutObject"],
    "Resource": "arn:aws:s3:::my-app-data/uploads/*"
  }]
}

Assign Both Roles in Task Definition

Shows both role ARNs in the task definition: executionRoleArn for ECS infrastructure actions and taskRoleArn for application AWS API calls.

Example · json
{
  "family": "api",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/ecsApiTaskRole",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "containerDefinitions": [
    {"name": "api", "image": "my-api:latest", "essential": true}
  ]
}

Discussion

  • Be the first to comment on this lesson.