ECR lifecycle and repository policies - console guide
Amazon ECR is the hinge between CI/CD and EKS/ECS. Production setups combine immutable tags, scanning, lifecycle cleanup, and repository policies for cross-account pulls.
Policy JSON reference: ECR lifecycle policy · EKS ECR practices
Checklist: DevOps checklist
Use cases
| Need | Control |
|---|---|
| Prevent tag overwrite | Immutable tag mutability |
| Supply chain | Scan on push / enhanced scanning |
| Cost control | Lifecycle expire untagged/old SHAs |
| Central registry account | Repository policy for spoke accounts |
Console - create repository
- ECR → Create repository.
- Tag mutability: Immutable (prod).
- Scan on push: enable.
- KMS encryption: CMK optional.
Console - lifecycle policy
- Repository → Lifecycle policies → Create rule.
- Rules (separate per prefix - do not combine unrelated prefixes in one
tagPrefixList):
| Priority | Rule |
|---|---|
| 1 | Expire untagged images > 7 days |
| 2 | Keep last 30 images tagged prod-* |
| 3 | Expire feature-* > 14 days |
See lifecycle doc for JSON.
Console - repository permissions (cross-account)
- Repository → Permissions → Edit.
- JSON policy allowing
ecr:BatchGetImage,ecr:GetDownloadUrlForLayerfor spoke account root or role.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowPullFromProdAccount",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::SPOKE_ACCOUNT:root" },
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer"
]
}]
}
Spoke roles still need ecr:GetAuthorizationToken on *.
IAM for CI (push)
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
],
"Resource": "*"
}
Scope PutImage to repository ARN when possible.
Security
- Block public repositories (account setting).
- Sign images (Notary/Cosign) in advanced pipelines.
- Deny
latestin prod deploy - pin digest or semver tag.
Commonly missed
| Miss | Impact |
|---|---|
| Lifecycle prefix AND logic | Rule never matches |
Immutable + deploy pipeline retags latest | Pipeline failures |
No cross-account GetAuthorizationToken | Pull ImagePullBackOff |
| Scan findings ignored | CVEs ship to prod |
Troubleshooting
| Symptom | Fix |
|---|---|
ImageTagAlreadyExistsException | New tag or mutable repo |
| Pull 403 | Repository policy + IAM on node role |
| Disk cost spike | Lifecycle on untagged build layers |