iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
To run a Docker container on Amazon ECS with Fargate, you push the image to Amazon ECR, define a task that points at that image, and then let ECS inject sensitive values from AWS Secrets Manager into the container at startup. Two IAM roles control the work: the task execution role lets the ECS/Fargate agent pull the image, write logs, and read the secret, while the optional task role gives your application code its own AWS API permissions. Keeping those roles separate, scoping them to specific resources, and deciding deliberately how traffic reaches the task are what make the deployment secure rather than merely working.
What you need before you start
- An AWS account and an IAM principal with permission to create ECR repositories, Secrets Manager secrets, IAM roles, ECS clusters, task definitions, and services.
- Docker (or a compatible build tool) on your workstation, and the AWS CLI configured for the target Region.
- A VPC with at least two subnets. Private subnets are the safer choice for application tasks; the approach in this guide works with either design, but the networking section explains what each one requires.
- A container image for a Linux application that listens on a known port and exposes a health endpoint. The examples below use a fictional application called
orders-api.
Task execution role versus task role
Most configuration errors in ECS come from mixing these two roles. They answer different questions. The task execution role answers “what does the ECS infrastructure need in order to start this task?” The task role answers “what does my application code need to call in AWS?”
| Aspect | Task execution role | Task role |
|---|---|---|
| Who uses it | The ECS/Fargate agent acting on the task’s behalf | Your application code, through the AWS SDK |
| Typical permissions | Pull a private image from ECR, write logs (for example through the awslogs driver), retrieve secrets referenced in the task definition |
Whatever the app calls: read an S3 bucket, send to an SQS queue, write to DynamoDB |
| When it matters | Before and during container startup | While the application is running |
| Required? | Required whenever the image is private or secrets or private log delivery are used | Optional; add it only when the application calls AWS APIs |
| Failure symptom | Task fails to start, with a stopped reason about pulling the image or retrieving a secret | Application starts but receives access-denied errors from an AWS API |
AWS recommends separate roles and advises narrowing permissions over time. The ECS IAM role guidance is in Best practices for IAM roles in Amazon ECS, and the task role specifics are in Amazon ECS task IAM role.
Recommended Free Tools
Step 1: Push the image to ECR and pin the version
Create a private repository, authenticate Docker, build, tag, and push. Replace the Region and account ID with your own values.
#1 Best Overall
aws ecr create-repository --repository-name orders-api --region us-east-1
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
docker build -t orders-api:1.4.2 .
docker tag orders-api:1.4.2 123456789012.dkr.ecr.us-east-1.amazonaws.com/orders-api:1.4.2
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/orders-api:1.4.2
In the task definition, reference the explicit tag (or the image digest) rather than latest. A mutable tag can change underneath a running service, so a redeploy may pick up a different image than the one you tested. Pinning makes rollbacks and audits traceable.
The execution role is what lets Fargate pull this private image. The permissions ECS needs for ECR are described in Using Amazon ECR images with Amazon ECS.
Step 2: Create the secret and grant read access narrowly
Store only sensitive values in Secrets Manager: database passwords, API keys, signing secrets. Non-sensitive settings such as feature flags or a log level belong in ordinary task-definition environment variables.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
- Create the secret in the Secrets Manager console (Secrets Manager, then Store a new secret) or with the CLI, for example
aws secretsmanager create-secret --name prod/orders-api/db --secret-string '{"username":"orders","password":"REPLACE_ME_LOCALLY"}'. Avoid typing real credentials into shell history; use a prompt or a file you then delete. - Copy the secret ARN. You need it for the IAM policy and the task definition.
- Attach an inline policy to the task execution role that allows
secretsmanager:GetSecretValueon that single ARN, not on*. - If the secret uses a customer-managed AWS KMS key, the principal also needs decrypt permission through the key policy. Confirm the exact key-policy statements in the AWS KMS and Secrets Manager documentation before you apply them, because they depend on how your key was created.
The AWS walkthrough for this flow is Specifying sensitive data using Secrets Manager secrets in Amazon ECS.
Step 3: Reference the secret in the task definition
ECS can inject a secret into a container in two ways. The secrets field maps an environment variable name to a Secrets Manager ARN, so the value is supplied when the container starts and is not written into the image or the task definition itself.
"containerDefinitions": [
{
"name": "orders-api",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/orders-api:1.4.2",
"essential": true,
"portMappings": [{ "containerPort": 8080, "protocol": "tcp" }],
"environment": [
{ "name": "LOG_LEVEL", "value": "info" }
],
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/orders-api/db-AbCdEf:password::"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/orders-api",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "orders"
}
}
}
],
"executionRoleArn": "arn:aws:iam::123456789012:role/ordersApiExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ordersApiTaskRole",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024"
The valueFrom value above selects one JSON key (password) from a secret that stores JSON. Omitting the key returns the whole secret string. The optional version-stage and version-id segments are left empty here so ECS uses the current version. Specific JSON-key and version injection depends on the Fargate platform version and operating system, so check the requirements in Pass Secrets Manager secrets through Amazon ECS environment variables before you rely on them.
Injection through environment variables is convenient, but it has an exposure trade-off. The value is visible to the application process, to anything that can read the container’s environment, and to any debugging tool that dumps it. Keep secret values out of application logs, restrict who can run commands in the container, and avoid printing the environment during troubleshooting. If your application supports fetching a secret directly with the AWS SDK at runtime, that approach lets you rotate values without redeploying tasks, at the cost of the code calling Secrets Manager and needing the task role.
Step 4: Configure networking and ingress
Each Fargate task runs with its own elastic network interface (ENI) in the subnet you choose. Every outbound dependency of the task must be reachable from that ENI: the ECR image registry, the Secrets Manager endpoint, and CloudWatch Logs for awslogs. The routing options are described in Amazon ECS task networking options for Fargate.
Rank #3
Option A: public subnet with a public IP
The task receives a public IP and reaches ECR and Secrets Manager over the internet gateway. This is the simplest way to get a first deployment running, and the introductory guide uses it. It is not a default you should keep in production: the task is directly addressable if its security group allows it.
Option B: private subnet with VPC endpoints
The task has no public IP and reaches AWS services through interface VPC endpoints. For a private deployment you typically need endpoints for Secrets Manager, ECR (API and Docker registry endpoints), and CloudWatch Logs, plus an S3 gateway endpoint if your image layers are served from S3 within the Region. Confirm the endpoint list against the current ECR and ECS documentation for your Region, because it is the most common cause of image pulls timing out in private subnets.
Ingress rules
The introductory AWS guide opens HTTP port 80 to 0.0.0.0/0 so the example is easy to test. Treat that as an illustrative tutorial setting. In production, allow inbound traffic only from the load balancer’s security group on the container port (8080 in this example), and allow outbound traffic only to what the task needs.
On Linux Fargate platform version 1.4.0, AWS states that image pulls, log delivery, and secret retrieval all flow over the task ENI, and that this traffic appears in VPC flow logs. Older platform versions behave differently. If you troubleshoot with flow logs, first confirm the platform version your service runs.
Step 5: Create the cluster and service, then run
- In the Amazon ECS console, choose Clusters, then Create cluster, and select AWS Fargate as the infrastructure. Alternatively, run
aws ecs create-cluster --cluster-name orders-cluster. - Register the task definition from Step 3 with
aws ecs register-task-definition --cli-input-json file://taskdef.json. - Create the service. Select the Fargate launch type or capacity provider, the private subnets, the security group from Step 4, and the desired task count. If the service sits behind an Application Load Balancer, attach the target group on the container port.
- Deploy and wait for the service to reach a steady state. Tasks should move from PROVISIONING and PENDING to RUNNING.
The step-by-step Fargate setup for a first task is in Learn how to create an Amazon ECS Linux task for Fargate.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Step 6: Verify the deployment and diagnose failures
A task showing RUNNING does not prove the application works. Check three things in order.
- The task is running. Confirm the desired and running counts match in the service view and that the task’s last status is RUNNING.
- The application responds. Call the health endpoint through the intended path, such as the load balancer DNS name or a client inside the VPC. The tutorial’s verification step does not define a health check for your application, so use the endpoint your service actually exposes.
- Logs contain no secret values. Search the CloudWatch log group for the password or key material, and fix any logging that echoes configuration.
When a deployment fails, start in the service’s Events tab and the stopped-task details. The symptom usually points to the role or network layer that broke:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall- Stopped reason mentions pulling the image or CannotPullContainerError: the execution role lacks ECR permissions, or the task has no route to ECR (check subnet routing or endpoints).
- Stopped reason mentions retrieving a secret or ResourceInitializationError for a secret: the execution role lacks
secretsmanager:GetSecretValueon the ARN, the ARN or JSON key is wrong, or KMS decrypt is missing. - Task runs but the application logs access-denied from an AWS API: the task role is missing or lacks the permission for that call. This is unrelated to the execution role.
- Health checks fail or the load balancer returns 503: the container port in the target group does not match the port the application listens on, or the ingress rule does not allow traffic from the load balancer.
Cleanup after a tutorial run
Delete the test resources to avoid ongoing charges and leftover access paths: scale the service to zero and delete it, delete the cluster, delete the secret (Secrets Manager schedules deletion and keeps it recoverable for a waiting period), remove the ECR images and repository, and detach or delete the roles you created for the exercise.
Best Value
What a container does and does not protect
A container packages an application and its dependencies, but it is not a security boundary by itself. AWS states this directly in its ECS task IAM role guidance: “Containers are not a security boundary and the use of task IAM roles does not change this.” The practical consequence is that least privilege belongs in the IAM roles, in the network rules, and in the secret scope, not in the assumption that the container isolates a compromised process. Fargate’s task isolation is described separately in AWS’s ECS documentation, and it does not replace the controls above.
The same guidance applies across deployment choices. Injecting secrets at startup and fetching them in application code are both defensible, provided each uses a narrowly scoped role. Public routing is acceptable for a demo; a private subnet with endpoints and a load balancer is the more typical production shape. The right balance depends on your application’s rotation needs and on your organization’s network policy.
As a last check, review the execution and task roles with IAM access information from the console and remove any action that the stopped-task and log evidence show is unused.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

