aws ecs iam security claude-curated

Every ECS task definition can attach two IAM roles. They look similar but they are used by different actors and serve different purposes. Confusing them — or collapsing them into one — is a common source of over-permissioned tasks.

The two roles

RoleUsed byUsed for
Task Execution RoleThe ECS agent / Fargate runtimeSetting up the container before code runs
Task RoleThe application code inside the containerCalling AWS APIs at runtime

The execution role runs before your container starts. The task role is what your code uses once it is running.

Task Execution Role

The execution role is assumed by the infrastructure that launches the task — the ECS agent on EC2, or the Fargate runtime. It needs permissions for things the agent does on behalf of the task:

AWS provides a managed policy for the common case: AmazonECSTaskExecutionRolePolicy. It grants ECR pull and CloudWatch Logs writes. You add Secrets Manager / SSM read permissions on top if your task references secrets.

{
  "executionRoleArn": "arn:aws:iam::ACCOUNT:role/ecsTaskExecutionRole",
  ...
}

Task Role

The task role is what your application code assumes via the task metadata endpoint. The AWS SDK inside the container picks up these credentials automatically — the SDK’s default credential provider chain finds the container credentials endpoint (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) and uses the task role.

This is what you scope to your application’s needs:

  • S3 read/write to specific buckets
  • DynamoDB access to specific tables
  • SQS send/receive on specific queues
  • KMS decrypt for specific keys
{
  "taskRoleArn": "arn:aws:iam::ACCOUNT:role/my-app-task-role",
  ...
}

Why they are separated

Separation of concerns. The agent has narrow, predictable infrastructure-level permissions. The application has app-specific permissions and nothing else.

Concrete benefits:

  • blast radius — a compromised application can only do what the task role allows. It cannot pull arbitrary images or read the log group’s secrets.
  • Auditing — execution-role activity (image pulls, log writes) is uniform across services. Task-role activity is per-app and meaningful for compliance.
  • Reuse — the same execution role can be shared across many services in an account. Each service has its own task role.

Common mistakes

  • Merging both into one role to “simplify” the task definition. This couples agent restart privileges with application data access. A bug that escalates within the container now controls log streams and image pulls.
  • Granting s3:* to the task role because it is “just for an internal app”. Scope down to the bucket prefix the app actually uses.
  • Forgetting the execution role’s Secrets Manager grant. If the task definition references secrets but the execution role cannot read them, the task fails to start with a misleading error before the application ever runs.
  • Putting application AWS calls under the execution role. The application code does not assume the execution role — it assumes the task role. Permissions there have no effect on running app calls.
  • Reusing the EC2 instance profile in place of the task role. On EC2 launch type, if no task role is set, the SDK can fall through to the instance profile credentials. That is over-permissioned and not what you want.

Least privilege patterns

  • One task role per service. Resist the urge to share.
  • Resource-scoped statements (Resource: arn:aws:s3:::my-bucket/prefix/*) instead of *.
  • Use IAM permission boundaries on the role-creation pipeline so a misconfigured policy cannot grant production write access.
  • Audit periodically with IAM Access Analyzer’s unused-access findings — task roles often accumulate dead permissions as features are removed.

Verifying which role is in effect

From inside a running task you can hit the task metadata endpoint:

curl ${ECS_CONTAINER_METADATA_URI_V4}/task

The response includes the task ARN and the role used to fetch credentials. The credentials themselves are at $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI — these are the task role credentials. The execution role’s credentials are never exposed inside the container; only the agent uses them.

See also

References