skip to content

In an ECS task definition, what is the difference between the task role (taskRoleArn) and the task execution role (executionRoleArn), and which of the two does application code inside the container use?

level: middleimportance: must knowfreq 70%

answer

  1. two identities, two consumers
  2. one acts before your code runs
  3. the other is your application's identity
  4. startup failure versus runtime AccessDenied
  5. SDK finds it via a credentials endpoint

basics

~20 s

The execution role is assumed by the ECS agent or Fargate infrastructure to pull the image, fetch secrets and write logs before your code runs. The task role is what application code inside the container uses to call AWS.

solid answer

~50 s

They have two different consumers. The **execution role** (`executionRoleArn`) belongs to the ECS infrastructure, not to your process: it is what pulls the image from ECR, resolves the `secrets` block from Secrets Manager or SSM Parameter Store, and creates the log stream for the `awslogs` driver. Its permissions matter during task startup and then stop mattering. The AWS-managed policy `AmazonECSTaskExecutionRolePolicy` covers the common case. The **task role** (`taskRoleArn`) is the identity of your running application: the AWS SDK inside the container picks it up automatically from the container credentials endpoint, and it is the role that needs `s3:GetObject`, `dynamodb:PutItem`, `sqs:ReceiveMessage` and so on. So the answer to the second half is: application code uses the *task* role. The practical tell is *when* a permission failure happens — a failure before your logs appear is an execution-role problem, and an `AccessDenied` inside your logs is a task-role problem.

go deeper

for a junior

Be able to state that the execution role is used by ECS itself to start the task and the task role is used by your application code, and that the SDK picks the task role up automatically.

for a middle

Explain the concrete permissions each role needs — ECR, Secrets Manager and CloudWatch Logs for one, business API calls for the other — and diagnose which one is at fault from the timing of the failure.

for a senior

Demonstrate least privilege in practice: per-service task roles, scoped execution roles, blocking instance-profile fallback on EC2 launch type, and using CloudTrail identity fields to settle a denial.

for a principal

Own the account-wide convention: who may create task roles, how boundaries or SCPs constrain them, and how per-task identity fits the wider workload-identity story across compute models.

## Two identities, two consumers ECS gives a task two IAM identities because two different actors act on its behalf, at two different times, and conflating them is the single most common ECS permissions bug. The **execution role** is assumed by the ECS container agent (EC2 launch type) or by the Fargate infrastructure. It acts *before and around* your container. The **task role** is assumed by the code inside your container. It acts *during* your container's life. Neither one grants the other's permissions. ## What the execution role does During task startup, the platform needs to: - **Pull the image.** For a private ECR repository that means `ecr:GetAuthorizationToken`, `ecr:BatchCheckLayerAvailability`, `ecr:GetDownloadUrlForLayer` and `ecr:BatchGetImage`. - **Resolve secrets.** If a container definition uses the `secrets` array to inject values, the platform calls `secretsmanager:GetSecretValue` or `ssm:GetParameters` — and `kms:Decrypt` if a customer-managed key encrypts them. Your application never makes that call; the value arrives as an environment variable already populated. - **Set up logging.** With `logDriver: awslogs`, the platform needs `logs:CreateLogStream` and `logs:PutLogEvents` (and `logs:CreateLogGroup` if you rely on `awslogs-create-group`). The managed policy `AmazonECSTaskExecutionRolePolicy` covers ECR pulls and CloudWatch Logs writes but *not* Secrets Manager or SSM reads — that is the most common gap, and it is why a task can start fine until someone adds a `secrets` entry and every subsequent task fails to launch. The execution role is optional in the narrow case of a public image, no injected secrets and no `awslogs` driver. In practice essentially every real task definition sets it. ## What the task role does The task role is the runtime identity of your process. It carries the business permissions: read this bucket, write this table, publish to this topic, assume that cross-account role. Nothing about pulling images or writing container logs belongs here. ## How the credentials actually reach your code ECS exposes a credentials endpoint on a link-local address and sets an environment variable in the container pointing at the relative path: ```bash echo $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI # /v2/credentials/2d1a0b1c-... curl -s http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ``` Every current AWS SDK checks that variable as part of its default credential provider chain, retrieves short-lived credentials for the task role, and refreshes them automatically. That is why correctly written application code needs no credential configuration at all — you set `taskRoleArn` and the SDK finds it. On the EC2 launch type this matters for a second reason: without a task role, an SDK falls further down the chain to the EC2 instance metadata service and picks up the **instance profile** instead. That silently gives your container whatever the host role can do — usually far more than the task should have, and shared with every other task on that instance. The ECS agent can be configured to block that path, but the correct fix is to give every task its own task role. ## Diagnosing which role is at fault Use the timeline: - The task never reaches `RUNNING`, `StoppedReason` mentions `CannotPullContainerError` or `ResourceInitializationError: unable to pull secrets or registry auth` → **execution role** (or networking, see the image-pull failure mode). - No log stream ever appears in CloudWatch Logs → **execution role**, missing `logs:` permissions. - Your application starts, logs normally, and then throws `AccessDenied` on an API call → **task role**. CloudTrail settles it either way: look at the `userIdentity.arn` on the denied call and see which of the two roles was in the session. ## Least privilege in practice A sound convention: one execution role per account or per broad workload class, scoped to the ECR repositories and log groups that class uses, and **one task role per service**, scoped to only that service's resources. Sharing one fat task role across a cluster destroys the main security benefit of per-task identity. Add `aws:SourceArn` or `aws:SourceAccount` conditions on the trust policy where a confused-deputy path exists, and note that both roles trust `ecs-tasks.amazonaws.com` as their principal — which is itself a common stumbling block, since a role trusting `ec2.amazonaws.com` will not work as a task role at all.

  • A team added a secret to a container definition's `secrets` array and now every task fails before starting. What is the likely cause?
    The execution role is missing `secretsmanager:GetSecretValue` or `ssm:GetParameters`, and `kms:Decrypt` if a customer-managed key is involved. The managed `AmazonECSTaskExecutionRolePolicy` does not cover secret retrieval. The platform, not the application, resolves those values at startup, so the failure appears as a stopped task with a resource-initialization reason and no application logs at all.
  • On the EC2 launch type, what happens if a task definition omits taskRoleArn entirely?
    The SDK falls through its credential chain to the instance metadata service and uses the EC2 instance profile. The container then inherits the host's permissions, shared with every other task on that instance — a real privilege-escalation path. Give every task an explicit task role, and restrict container access to the metadata service on the host.
  • Which IAM principal must both roles trust?
    `ecs-tasks.amazonaws.com`, via `sts:AssumeRole` in the trust policy. A role built for EC2 that trusts `ec2.amazonaws.com` cannot be used as a task or execution role, and the failure looks like an unhelpful role-assumption error at task launch rather than a permissions error at runtime.

saying these in an interview costs you the question

  • Puts application S3 or DynamoDB permissions on the execution role
  • Thinks one role covers both image pull and runtime calls
  • Configures static access keys in the container environment
  • Believes the task role pulls the image from ECR
  • Assumes AmazonECSTaskExecutionRolePolicy grants Secrets Manager access

context