ECR Repository Lifecycle Policy
Overview
This check verifies that your Amazon Elastic Container Registry (ECR) repositories have lifecycle policies configured. A lifecycle policy automatically manages your container images by deleting old or unused images based on rules you define.
Think of it like setting up automatic cleanup rules for your container image storage.
Risk
Without lifecycle policies, your ECR repositories will accumulate images indefinitely. This creates three problems:
- Service disruptions: ECR has storage quotas. When you hit them, new image pushes fail, breaking your CI/CD pipelines.
- Security vulnerabilities: Old images with known security issues remain available and could accidentally be deployed.
- Unnecessary costs: You pay for all stored images, even ones you no longer use.
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify ECR repositories
- Know which ECR repository needs the policy
Required IAM permissions
You need these permissions on the target repository:
ecr:GetLifecyclePolicyecr:PutLifecyclePolicyecr:GetRepositoryPolicy
AWS Console Method
- Open the Amazon ECR console
- Make sure you are in the us-east-1 region (check the dropdown in the top-right corner)
- In the left navigation, click Repositories
- Click on the repository name that needs a lifecycle policy
- Click the Lifecycle Policy tab
- Click Create rule
- Configure the rule:
- Rule priority:
1 - Rule description:
Expire untagged images older than 14 days - Image status: Select Untagged
- Match criteria: Select Since image pushed and enter
14days - Rule action: Leave as Expire
- Rule priority:
- Click Save
Your repository will now automatically delete untagged images older than 14 days.
AWS CLI (optional)
Create a lifecycle policy file (policy.json):
{
"rules": [
{
"rulePriority": 1,
"description": "Expire untagged images older than 14 days",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 14
},
"action": {
"type": "expire"
}
}
]
}
Apply the policy:
aws ecr put-lifecycle-policy \
--repository-name <your-repository-name> \
--lifecycle-policy-text file://policy.json \
--region us-east-1
Replace <your-repository-name> with your actual repository name.
Example with inline policy (single command):
aws ecr put-lifecycle-policy \
--repository-name my-app \
--lifecycle-policy-text '{"rules":[{"rulePriority":1,"description":"Expire untagged images older than 14 days","selection":{"tagStatus":"untagged","countType":"sinceImagePushed","countUnit":"days","countNumber":14},"action":{"type":"expire"}}]}' \
--region us-east-1
CloudFormation (optional)
Add a LifecyclePolicy property to your ECR repository resource:
AWSTemplateFormatVersion: '2010-09-09'
Description: ECR repository with lifecycle policy
Resources:
MyECRRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: my-application
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"rulePriority": 1,
"description": "Expire untagged images older than 14 days",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 14
},
"action": {
"type": "expire"
}
},
{
"rulePriority": 2,
"description": "Keep only the last 10 tagged images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["v"],
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": {
"type": "expire"
}
}
]
}
Terraform (optional)
Add an aws_ecr_lifecycle_policy resource linked to your repository:
resource "aws_ecr_repository" "my_repo" {
name = "my-application"
image_tag_mutability = "MUTABLE"
image_scanning_configuration {
scan_on_push = true
}
}
resource "aws_ecr_lifecycle_policy" "my_repo_policy" {
repository = aws_ecr_repository.my_repo.name
policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Expire untagged images older than 14 days"
selection = {
tagStatus = "untagged"
countType = "sinceImagePushed"
countUnit = "days"
countNumber = 14
}
action = {
type = "expire"
}
},
{
rulePriority = 2
description = "Keep only the last 10 tagged images"
selection = {
tagStatus = "tagged"
tagPrefixList = ["v"]
countType = "imageCountMoreThan"
countNumber = 10
}
action = {
type = "expire"
}
}
]
})
}
Verification
In the AWS Console:
- Go to ECR > Repositories
- Click on your repository name
- Click the Lifecycle Policy tab
- Confirm at least one rule is listed
Verify with AWS CLI
aws ecr get-lifecycle-policy \
--repository-name <your-repository-name> \
--region us-east-1
A successful response shows your policy:
{
"registryId": "123456789012",
"repositoryName": "my-app",
"lifecyclePolicyText": "{\"rules\":[...]}",
"lastEvaluatedAt": "2024-01-15T10:30:00.000Z"
}
If no policy exists, you will see an error: LifecyclePolicyNotFoundException.
Re-run the Prowler check
prowler aws --checks ecr_repositories_lifecycle_policy_enabled --region us-east-1
The check should now pass for your repository.
Additional Resources
Notes
- Policy evaluation: Lifecycle policies are evaluated once every 24 hours. Images are not deleted immediately after a policy is applied.
- Preview before applying: In the console, you can use the Preview feature to see which images would be affected before saving a rule.
- Multiple rules: You can have up to 50 rules per repository. Rules are evaluated in priority order (lowest number first).
- Tagged vs. untagged: Consider separate rules for tagged images (like release versions) and untagged images (often build artifacts).
- No undo: Once images are deleted by a lifecycle policy, they cannot be recovered. Test your rules with the preview feature first.