Skip to content

ECR (Container Registry)

First PublishedByAtif Alam

Amazon ECR (Elastic Container Registry) is a fully managed Docker container registry. It stores your container images and integrates natively with ECS, EKS, Lambda, and CodeBuild.

Build (CodeBuild / GitHub Actions)
docker push ──► ECR Repository ──► ECS / EKS / Lambda pulls image
├── Image scanning (vulnerabilities)
└── Lifecycle policies (cleanup old images)
ConceptWhat It Is
RegistryYour account’s ECR registry (123456789012.dkr.ecr.us-east-1.amazonaws.com)
RepositoryA collection of images for one application (like a Docker Hub repo)
ImageA Docker image identified by tag or digest
TagA label for an image (latest, v1.2.3, abc123) — mutable (can be moved)
DigestA SHA256 hash that uniquely and immutably identifies an image
Terminal window
aws ecr create-repository --repository-name my-app \
--image-scanning-configuration scanOnPush=true \
--encryption-configuration encryptionType=KMS

ECR uses temporary tokens — you must authenticate before push/pull:

Terminal window
# Login (token valid for 12 hours)
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
Terminal window
# Build the image
docker build -t my-app .
# Tag for ECR
docker tag my-app:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
# Also tag with the commit SHA for traceability
docker tag my-app:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:abc123def
# Push
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:abc123def
Terminal window
docker pull 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest

ECS and EKS pull images automatically using the task/pod IAM role — no manual docker pull needed.

StrategyTag ExampleProsCons
latestlatestSimpleDon’t know which version is running; not reproducible
Git SHAabc123defTraceable to exact commitNot human-readable
Semantic versionv1.2.3Clear release versioningMust manage version bumps
Bothv1.2.3 + abc123defBest of both worldsTwo tags per push

Best practice: Always push a git SHA tag alongside any other tag. This makes it trivial to trace a running container back to its source code.

Terminal window
# Enable immutability (prevents overwriting tags)
aws ecr put-image-tag-mutability \
--repository-name my-app \
--image-tag-mutability IMMUTABLE

With immutability enabled, pushing to an existing tag fails. This prevents accidental overwrites and ensures v1.2.3 always refers to the same image. Note: this means you can’t use a mutable latest tag.

Lifecycle policies automatically clean up old images to save storage costs:

Terminal window
aws ecr put-lifecycle-policy --repository-name my-app \
--lifecycle-policy-text '{
"rules": [
{
"rulePriority": 1,
"description": "Keep last 10 tagged images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["v"],
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": {"type": "expire"}
},
{
"rulePriority": 2,
"description": "Delete untagged images older than 7 days",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": {"type": "expire"}
}
]
}'

This keeps the 10 most recent version-tagged images and deletes untagged images after 7 days.

ECR can scan images for known vulnerabilities (CVEs):

TypeWhenCoverage
Basic scanningOn push or manual triggerOS package vulnerabilities
Enhanced scanning (Inspector)ContinuousOS + programming language vulnerabilities (pip, npm, etc.)
Terminal window
aws ecr put-registry-scanning-configuration \
--scan-type ENHANCED \
--rules '[{
"repositoryFilters": [{"filter": "*", "filterType": "WILDCARD"}],
"scanFrequency": "CONTINUOUS_SCAN"
}]'
Terminal window
aws ecr describe-image-scan-findings \
--repository-name my-app \
--image-id imageTag=latest

Findings include CVE ID, severity, affected package, and fixed version — same as Inspector findings.

Share images across AWS accounts using a repository policy:

{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCrossAccountPull",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::987654321098:root"
},
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
]
}]
}

The other account can now pull images from your repository. Useful for shared base images or a central registry account.

Automatically replicate images to other regions for faster pulls and disaster recovery:

Terminal window
aws ecr put-replication-configuration --replication-configuration '{
"rules": [{
"destinations": [
{"region": "eu-west-1", "registryId": "123456789012"},
{"region": "ap-southeast-1", "registryId": "123456789012"}
]
}]
}'
- name: Login to ECR
uses: aws-actions/amazon-ecr-login@v2
- name: Build and push
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $REGISTRY/my-app:$IMAGE_TAG .
docker push $REGISTRY/my-app:$IMAGE_TAG
buildspec.yml
phases:
pre_build:
commands:
- aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REGISTRY
build:
commands:
- docker build -t $ECR_REGISTRY/my-app:$CODEBUILD_RESOLVED_SOURCE_VERSION .
- docker push $ECR_REGISTRY/my-app:$CODEBUILD_RESOLVED_SOURCE_VERSION

ECR Public hosts public container images (like Docker Hub) at public.ecr.aws:

Terminal window
# Create a public repository
aws ecr-public create-repository --repository-name my-public-app
# Push to public
docker tag my-app:latest public.ecr.aws/a1b2c3d4/my-public-app:latest
docker push public.ecr.aws/a1b2c3d4/my-public-app:latest

Free tier: 50 GB storage, 500 GB/month data transfer for authenticated users.

ECRDocker HubGitHub Container Registry
Private imagesYes (default)PaidYes (free for public)
AWS integrationNative (IAM, ECS, EKS)Manual authManual auth
ScanningBuilt-in (basic + Inspector)PaidBasic
Lifecycle policiesYesNoNo
Cross-region replicationYesNoNo
Cost$0.10/GB/month storageFree (public), paid (private)Free (limited)
  • ECR stores Docker images with native IAM authentication — no Docker Hub credentials needed.
  • Always tag images with the git SHA for traceability alongside version tags.
  • Use lifecycle policies to automatically delete old images and control storage costs.
  • Enable scan on push (basic) or enhanced scanning (Inspector) to catch vulnerabilities before deployment.
  • Use cross-account policies for shared base images and replication for multi-region deployments.
  • Image tag immutability prevents accidental overwrites — use it for release tags.