Terraform module to create AWS ECR (Elastic Container Registry) which is a fully-managed Docker container registry.
The terraform-aws-ecr module enables several common architectures for container image management.
┌──────────────┐ ┌───────────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ Developer │────▶│ AWS ECR Registry │◀────│ CI/CD Pipeline │
│ Workstation │ │ │ │ │
│ │ └───────────────────────┘ └─────────────────┘
└──────────────┘ │ ▲
│ │
▼ │
┌─────────────────┐
│ │
│ ECS / EKS │
│ Services │
│ │
└─────────────────┘
For more detailed architecture diagrams including CI/CD integration, multi-region deployments, and security controls, see docs/diagrams.md.
This module follows Semantic Versioning principles. For full details on the versioning scheme, release process, and compatibility guarantees, see the following documentation:
- VERSIONING.md - Details on the semantic versioning scheme and release process
- VERSION_COMPATIBILITY.md - Terraform and AWS provider compatibility matrix
You can use this module to create an ECR registry using few parameters (simple example) or define in detail every aspect of the registry (complete example).
Check the examples directory for examples including:
- Simple - Basic ECR repository with minimal configuration
- Complete - Full-featured ECR repository with all options
- Protected - Repository with deletion protection
- With ECS Integration - ECR configured for use with ECS
- Multi-Region - Repository configured for cross-region replication (manual and automatic approaches)
- Replication - ECR repository with built-in cross-region replication support
- Advanced Tagging - Comprehensive tagging strategies with templates, validation, and normalization
- Enhanced Security - Advanced security features with scanning and compliance
- Lifecycle Policies - Image lifecycle management with predefined templates
- Pull Request Rules - Governance and approval workflows for container images
- Enhanced KMS - Advanced KMS key configuration with custom policies and access control
This example creates an ECR registry using few parameters
module "ecr" {
source = "lgallard/ecr/aws"
name = "ecr-repo-dev"
# Tags
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
In this example, the registry is defined in detail including CloudWatch logging:
module "ecr" {
source = "lgallard/ecr/aws"
name = "ecr-repo-dev"
scan_on_push = true
timeouts_delete = "60m"
image_tag_mutability = "IMMUTABLE"
encryption_type = "KMS"
# Enable CloudWatch logging
enable_logging = true
log_retention_days = 14
// ...rest of configuration...
}
The module supports sending ECR API actions and image push/pull events to CloudWatch Logs. When enabled:
- Creates a CloudWatch Log Group
/aws/ecr/{repository-name}
- Sets up necessary IAM roles and policies for ECR to write logs
- Configurable log retention period (default: 30 days)
To enable logging:
module "ecr" {
source = "lgallard/ecr/aws"
name = "ecr-repo-dev"
enable_logging = true
# Optional: customize retention period (in days)
log_retention_days = 14 # Valid values: 0,1,3,5,7,14,30,60,90,120,150,180,365,400,545,731,1827,3653
}
The module outputs logging-related ARNs:
cloudwatch_log_group_arn
- The ARN of the CloudWatch Log Grouplogging_role_arn
- The ARN of the IAM role used for logging
The module provides comprehensive CloudWatch monitoring with metric alarms and SNS notifications for proactive repository management. When enabled:
- Creates CloudWatch metric alarms for key ECR metrics
- Monitors storage usage, API calls, and security findings
- Sends notifications via SNS for alarm state changes
- Provides visibility into repository usage and costs
module "ecr" {
source = "lgallard/ecr/aws"
name = "monitored-app"
enable_monitoring = true
# Configure monitoring thresholds
monitoring_threshold_storage = 10 # GB
monitoring_threshold_api_calls = 1000 # calls per minute
monitoring_threshold_security_findings = 5 # findings count
# Create SNS topic for notifications
create_sns_topic = true
sns_topic_name = "ecr-alerts"
sns_topic_subscribers = ["admin@company.com", "devops@company.com"]
}
CloudWatch Alarms Created:
- Storage Usage: Monitors repository size in GB
- API Call Volume: Monitors API operations per minute
- Image Push Count: Monitors push frequency (10 pushes per 5 minutes)
- Image Pull Count: Monitors pull frequency (100 pulls per 5 minutes)
- Security Findings: Monitors vulnerability count (requires enhanced scanning)
SNS Integration:
- Automatic SNS topic creation with configurable name
- Email subscriptions for immediate notifications
- Alarm and OK state notifications
- Support for existing SNS topics
module "ecr" {
source = "lgallard/ecr/aws"
name = "production-app"
# Enable monitoring with custom thresholds
enable_monitoring = true
monitoring_threshold_storage = 50 # 50 GB threshold
monitoring_threshold_api_calls = 2000 # 2000 calls/minute
monitoring_threshold_security_findings = 0 # Zero tolerance for vulnerabilities
# Use existing SNS topic
create_sns_topic = false
sns_topic_name = "existing-alerts-topic"
# Enable enhanced scanning for security monitoring
enable_registry_scanning = true
registry_scan_type = "ENHANCED"
enable_secret_scanning = true
}
Monitoring Outputs:
monitoring_status
- Complete monitoring configuration statussns_topic_arn
- ARN of the SNS topic (if created)cloudwatch_alarms
- Details of all created CloudWatch alarms
Cost Considerations:
- CloudWatch alarms: $0.10 per alarm per month
- SNS notifications: First 1,000 emails free, then $0.75 per 1,000
- No additional charges for metrics collection
The module now supports automatic cross-region replication for disaster recovery and multi-region deployments. When enabled, images are automatically replicated to specified regions whenever they are pushed to the primary repository.
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-application"
# Enable cross-region replication
enable_replication = true
replication_regions = ["us-west-2", "eu-west-1", "ap-southeast-1"]
tags = {
Environment = "production"
Application = "my-app"
}
}
Key Benefits:
- Disaster Recovery - Images remain available if a region becomes unavailable
- Reduced Latency - Pull images from the nearest region
- High Availability - Improved resilience for multi-region workloads
- Automatic Sync - No manual intervention required for replication
Important Notes:
- Replication is configured at the registry level (affects all repositories in the account)
- Use immutable tags (
image_tag_mutability = "IMMUTABLE"
) for consistency across regions - Additional costs apply for cross-region data transfer and storage
- Replication is one-way from the source region to destination regions
The module provides replication-related outputs:
replication_status
- Overall replication configuration statusreplication_regions
- List of destination regionsreplication_configuration_arn
- ARN of the replication configuration
For more detailed examples, see the replication example and multi-region example.
In this example the register is defined in detailed.
module "ecr" {
source = "lgallard/ecr/aws"
name = "ecr-repo-dev"
scan_on_push = true
timeouts_delete = "60m"
image_tag_mutability = "MUTABLE"
prevent_destroy = true # Protect repository from accidental deletion
# Note that currently only one policy may be applied to a repository.
policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "repo policy",
"Effect": "Allow",
"Principal": "*",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:DescribeRepositories",
"ecr:GetRepositoryPolicy",
"ecr:ListImages",
"ecr:DeleteRepository",
"ecr:BatchDeleteImage",
"ecr:SetRepositoryPolicy",
"ecr:DeleteRepositoryPolicy"
]
}
]
}
EOF
# Only one lifecycle policy can be used per repository.
# To apply multiple rules, combined them in one policy JSON.
lifecycle_policy = <<EOF
{
"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 last 30 dev images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["dev"],
"countType": "imageCountMoreThan",
"countNumber": 30
},
"action": {
"type": "expire"
}
}
]
}
EOF
# Tags
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
### Deleting ECR Repositories Protected with prevent_destroy
By default, ECR repositories created by this module have `prevent_destroy = true` set in their lifecycle configuration to prevent accidental deletion. When you need to remove a repository:
1. Set the `prevent_destroy` parameter to `false` for the module:
```hcl
module "ecr" {
source = "lgallard/ecr/aws"
name = "ecr-repo-dev"
prevent_destroy = false # Allow repository to be destroyed
}
- Apply the configuration change:
terraform apply
- After successful apply, run destroy as normal:
terraform destroy
This approach allows protecting repositories by default while providing a controlled way to remove them when needed.
The module provides comprehensive tagging strategies to support better resource management, cost allocation, and organizational compliance. These features enable consistent, validated, and normalized tagging across all ECR resources while maintaining full backward compatibility.
- Default Tag Templates: Predefined organizational tag standards for common scenarios
- Tag Validation: Ensure required tags are present and follow naming conventions
- Tag Normalization: Consistent casing and format across all resources
- Cost Allocation: Specialized tags for financial tracking and reporting
- Compliance: Tags required for security and regulatory frameworks
- Backward Compatible: All advanced features are opt-in
The module provides four predefined templates for common organizational needs:
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Enable basic organizational tagging
enable_default_tags = true
default_tags_template = "basic"
default_tags_environment = "production"
default_tags_owner = "platform-team"
default_tags_project = "user-service"
}
Applied tags: CreatedBy
, ManagedBy
, Environment
, Owner
, Project
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Enable cost allocation tagging
enable_default_tags = true
default_tags_template = "cost_allocation"
default_tags_environment = "production"
default_tags_owner = "platform-team"
default_tags_project = "user-service"
default_tags_cost_center = "engineering-cc-001"
}
Applied tags: All basic tags plus CostCenter
, BillingProject
, ResourceType
, Service
, Billable
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Enable compliance tagging
enable_default_tags = true
default_tags_template = "compliance"
default_tags_environment = "production"
default_tags_owner = "security-team"
default_tags_project = "payment-service"
default_tags_cost_center = "security-cc-002"
}
Applied tags: All cost allocation tags plus DataClass
, Compliance
, BackupRequired
, MonitoringLevel
, SecurityReview
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Enable SDLC tagging
enable_default_tags = true
default_tags_template = "sdlc"
default_tags_environment = "development"
default_tags_owner = "dev-team"
default_tags_project = "mobile-app"
}
Applied tags: Basic organizational tags plus Application
, Version
, DeploymentStage
, LifecycleStage
, MaintenanceWindow
Ensure organizational compliance by validating that required tags are present:
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Enable tag validation
enable_tag_validation = true
required_tags = [
"Environment",
"Owner",
"Project",
"CostCenter"
]
# This will fail if any required tags are missing
default_tags_environment = "production"
default_tags_owner = "platform-team"
default_tags_project = "user-service"
default_tags_cost_center = "eng-001"
}
Ensure consistent tag formatting across all resources:
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Enable tag normalization
enable_tag_normalization = true
tag_key_case = "PascalCase" # Options: PascalCase, camelCase, snake_case, kebab-case
normalize_tag_values = true
tags = {
"cost-center" = " engineering-001 " # Will be normalized to "CostCenter" = "engineering-001"
"data_class" = "internal" # Will be normalized to "DataClass" = "internal"
}
}
Configure custom default tags without using templates:
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Enable custom default tags
enable_default_tags = true
default_tags_template = null # Use custom configuration
default_tags_environment = "staging"
default_tags_owner = "full-stack-team"
default_tags_project = "analytics-service"
default_tags_cost_center = "data-cc-003"
# Additional custom tags
tags = {
team_slack = "analytics-team"
oncall_rotation = "analytics-oncall"
}
}
Disable advanced tagging features for backward compatibility:
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Disable advanced tagging features
enable_default_tags = false
enable_tag_validation = false
enable_tag_normalization = false
# Traditional manual tagging
tags = {
Environment = "production"
Owner = "legacy-team"
ManagedBy = "Terraform"
}
}
- Start with Templates: Use predefined templates that match your organizational needs
- Enable Validation: Enforce required tags for compliance and consistency
- Normalize Consistently: Choose a casing strategy and apply it across all resources
- Plan for Cost Allocation: Include cost center and billing project tags early
- Consider Compliance: Include data classification and security review tags for regulated environments
- Monitor Tag Drift: Use the validation and normalization features to maintain consistency
For comprehensive examples demonstrating different tagging strategies, see examples/advanced-tagging.
The module provides enhanced lifecycle policy configuration through helper variables and predefined templates, making it easier to implement common lifecycle patterns without writing complex JSON. This feature significantly simplifies ECR image lifecycle management while maintaining full backwards compatibility.
There are three ways to configure lifecycle policies, listed in order of precedence:
- Manual JSON Policy (
lifecycle_policy
) - Highest precedence, full control - Predefined Templates (
lifecycle_policy_template
) - Medium precedence, common patterns - Helper Variables - Lowest precedence, individual settings
🚨 Important: Configuration Precedence Rules
- When
lifecycle_policy
is specified, ALL template and helper variable settings are ignored - When
lifecycle_policy_template
is specified, ALL helper variable settings are ignored - Only helper variables are used when neither
lifecycle_policy
norlifecycle_policy_template
are specified - AWS ECR Limitations: Maximum 25 rules per policy, rule priorities must be unique (1-999), up to 100 tag prefixes per rule
For complete AWS ECR lifecycle policy documentation and examples, see AWS ECR Lifecycle Policy Documentation.
Configure lifecycle policies using individual helper variables for maximum flexibility:
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app"
# Keep only the latest 30 images (range: 1-10000)
lifecycle_keep_latest_n_images = 30
# Delete untagged images after 7 days (range: 1-3650)
lifecycle_expire_untagged_after_days = 7
# Delete tagged images after 90 days (range: 1-3650)
lifecycle_expire_tagged_after_days = 90
# Apply rules only to specific tag prefixes (optional)
lifecycle_tag_prefixes_to_keep = ["v", "release", "prod"]
}
lifecycle_keep_latest_n_images
: Controls how many of the most recent images to retain. When combined withlifecycle_tag_prefixes_to_keep
, only applies to images with those tag prefixes.lifecycle_expire_untagged_after_days
: Automatically deletes untagged images after the specified number of days.lifecycle_expire_tagged_after_days
: Automatically deletes tagged images after the specified number of days.lifecycle_tag_prefixes_to_keep
: When specified, limits thelifecycle_keep_latest_n_images
rule to only images with these tag prefixes. Other lifecycle rules still apply to all images.
Use predefined templates for common scenarios. Each template encapsulates best practices for specific environments:
# Development environment - optimized for frequent builds and testing
module "ecr_dev" {
source = "lgallard/ecr/aws"
name = "dev-app"
lifecycle_policy_template = "development"
}
# Production environment - balanced retention and stability
module "ecr_prod" {
source = "lgallard/ecr/aws"
name = "prod-app"
lifecycle_policy_template = "production"
}
# Cost optimization - minimal storage costs
module "ecr_cost" {
source = "lgallard/ecr/aws"
name = "test-app"
lifecycle_policy_template = "cost_optimization"
}
# Compliance - long retention for audit requirements
module "ecr_compliance" {
source = "lgallard/ecr/aws"
name = "audit-app"
lifecycle_policy_template = "compliance"
}
Template | Keep Images | Untagged Expiry | Tagged Expiry | Tag Prefixes | Use Case |
---|---|---|---|---|---|
development |
50 | 7 days | - | ["dev", "feature"] |
Development workflows with frequent builds |
production |
100 | 14 days | 90 days | ["v", "release", "prod"] |
Production environments requiring stability |
cost_optimization |
10 | 3 days | 30 days | [] (all images) |
Test environments with aggressive cost optimization |
compliance |
200 | 30 days | 365 days | ["v", "release", "audit"] |
Compliance environments requiring long retention |
The module follows a clear precedence order when multiple configuration methods are specified:
module "ecr" {
source = "lgallard/ecr/aws"
name = "custom-app"
# This manual policy takes precedence over everything else
lifecycle_policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Custom rule"
selection = {
tagStatus = "untagged"
countType = "sinceImagePushed"
countUnit = "days"
countNumber = 5
}
action = { type = "expire" }
}
]
})
# These are ignored when lifecycle_policy is specified
lifecycle_policy_template = "production"
lifecycle_keep_latest_n_images = 30
}
module "ecr" {
source = "lgallard/ecr/aws"
name = "template-app"
# Template takes precedence over helper variables
lifecycle_policy_template = "production"
# These helper variables are ignored when template is specified
lifecycle_keep_latest_n_images = 30
lifecycle_expire_untagged_after_days = 5
}
module "ecr" {
source = "lgallard/ecr/aws"
name = "helper-app"
# Only helper variables specified - these will be used
lifecycle_keep_latest_n_images = 30
lifecycle_expire_untagged_after_days = 5
lifecycle_expire_tagged_after_days = 60
lifecycle_tag_prefixes_to_keep = ["v", "stable"]
}
# Development with custom retention
module "ecr_dev_custom" {
source = "lgallard/ecr/aws"
name = "dev-custom-app"
lifecycle_keep_latest_n_images = 20 # Fewer than default dev template
lifecycle_expire_untagged_after_days = 3 # Faster cleanup than default
lifecycle_tag_prefixes_to_keep = ["dev", "feat", "fix"]
}
# Production with extended retention for releases
module "ecr_prod_extended" {
source = "lgallard/ecr/aws"
name = "prod-extended-app"
lifecycle_keep_latest_n_images = 150 # More than default prod template
lifecycle_expire_untagged_after_days = 21 # Longer than default
lifecycle_expire_tagged_after_days = 180 # Extended retention
lifecycle_tag_prefixes_to_keep = ["v", "release", "hotfix"]
}
# Aggressive cleanup for test environments
module "ecr_test" {
source = "lgallard/ecr/aws"
name = "test-app"
lifecycle_keep_latest_n_images = 5 # Minimal retention
lifecycle_expire_untagged_after_days = 1 # Daily cleanup
lifecycle_expire_tagged_after_days = 7 # Weekly cleanup
}
# Balanced approach for staging
module "ecr_staging" {
source = "lgallard/ecr/aws"
name = "staging-app"
lifecycle_policy_template = "development" # Use template for consistency
}
- Use
development
for: CI/CD environments, feature branch testing, development workflows - Use
production
for: Live applications, staging environments, release candidates - Use
cost_optimization
for: Temporary test environments, proof-of-concepts, experimental workloads - Use
compliance
for: Regulated environments, audit trails, long-term archival needs
- Start with a template that's closest to your needs, then use helper variables if needed
- Use tag prefixes to apply different retention rules to different image types
- Monitor storage costs and adjust retention periods based on usage patterns
- Consider compliance requirements when setting retention periods
# Strategy 1: Environment-based prefixes
lifecycle_tag_prefixes_to_keep = ["prod", "staging", "release"]
# Strategy 2: Version-based prefixes
lifecycle_tag_prefixes_to_keep = ["v", "release-"]
# Strategy 3: Branch-based prefixes
lifecycle_tag_prefixes_to_keep = ["main", "develop", "hotfix"]
# Strategy 4: Mixed strategy
lifecycle_tag_prefixes_to_keep = ["v", "release", "prod", "stable"]
The module includes built-in validation to prevent common configuration errors:
- Image count: Must be between 1 and 10,000
- Days: Must be between 1 and 3,650 (10 years)
- Tag prefixes: Maximum 100 prefixes, each up to 255 characters
- Template names: Must be one of the four predefined templates
When using helper variables or templates, the module generates policies with this structure:
- Rule 1: Expire untagged images (if
expire_untagged_after_days
specified) - Rule 2: Keep latest N images (if
keep_latest_n_images
specified) - Rule 3: Expire tagged images (if
expire_tagged_after_days
specified)
To migrate from existing manual lifecycle_policy
to the enhanced configuration:
-
Analyze Your Current Policy: Review your existing JSON lifecycle policy to understand the rules.
# Get current policy from Terraform state terraform show | grep -A 20 lifecycle_policy
-
Choose Migration Path:
- Use a template if your policy matches common patterns
- Use helper variables for custom configurations
- Keep manual policy for complex, non-standard rules
-
Template Migration Example:
# Before (manual policy) module "ecr" { source = "lgallard/ecr/aws" name = "my-app" lifecycle_policy = jsonencode({ rules = [ { rulePriority = 1 description = "Keep last 100 images" selection = { tagStatus = "any" countType = "imageCountMoreThan" countNumber = 100 } action = { type = "expire" } }, { rulePriority = 2 description = "Expire untagged after 14 days" selection = { tagStatus = "untagged" countType = "sinceImagePushed" countUnit = "days" countNumber = 14 } action = { type = "expire" } } ] }) } # After (using production template) module "ecr" { source = "lgallard/ecr/aws" name = "my-app" lifecycle_policy_template = "production" # Matches the pattern above }
-
Helper Variables Migration Example:
# Before (manual policy) lifecycle_policy = jsonencode({ rules = [ { rulePriority = 1 description = "Keep 30 images with specific prefixes" selection = { tagStatus = "tagged" tagPrefixList = ["v", "release"] countType = "imageCountMoreThan" countNumber = 30 } action = { type = "expire" } } ] }) # After (using helper variables) lifecycle_keep_latest_n_images = 30 lifecycle_tag_prefixes_to_keep = ["v", "release"]
-
Test Migration: Apply changes in a non-production environment first:
terraform plan # Review the changes carefully terraform apply # Apply when ready
-
Verify Results: Check that lifecycle policies are correctly applied:
aws ecr describe-lifecycle-policy --repository-name my-app
- Before migration: Document current retention behavior
- After migration: Verify identical behavior with new configuration
- Monitor: Watch for unexpected image deletions in the first week
For more complex migration scenarios, see the migration examples.
See the lifecycle policies example for comprehensive usage examples and the troubleshooting guide for common issues.
The module provides pull request rules functionality to implement governance and approval workflows for container images, similar to pull request approval processes for code repositories. This feature enables organizations to enforce quality control, security validation, and compliance requirements before images are deployed to production.
Pull request rules provide:
- Approval workflows: Require manual approval for production images
- Security validation: Automatic checks for vulnerabilities and compliance
- CI/CD integration: Webhook notifications for external systems
- Governance controls: Policy-based restrictions on image usage
- Audit trails: Complete tracking of image approval workflows
module "ecr" {
source = "lgallard/ecr/aws"
name = "production-app"
# Enable pull request rules
enable_pull_request_rules = true
# Configure approval requirements
pull_request_rules = [
{
name = "production-approval"
type = "approval"
enabled = true
conditions = {
tag_patterns = ["prod-*", "release-*"]
severity_threshold = "HIGH"
}
actions = {
require_approval_count = 2
notification_topic_arn = "arn:aws:sns:region:account:topic"
}
}
]
}
Require manual approval before images can be used in production:
{
name = "security-approval"
type = "approval"
enabled = true
conditions = {
tag_patterns = ["prod-*", "release-*"]
severity_threshold = "HIGH"
require_scan_completion = true
allowed_principals = ["arn:aws:iam::account:role/SecurityTeam"]
}
actions = {
require_approval_count = 2
notification_topic_arn = "arn:aws:sns:region:account:topic"
block_on_failure = true
approval_timeout_hours = 24
}
}
Automatically validate images against security criteria:
{
name = "vulnerability-check"
type = "security_scan"
enabled = true
conditions = {
severity_threshold = "MEDIUM"
require_scan_completion = true
}
actions = {
notification_topic_arn = "arn:aws:sns:region:account:topic"
block_on_failure = true
}
}
Integrate with CI/CD systems through webhooks:
{
name = "ci-validation"
type = "ci_integration"
enabled = true
conditions = {
tag_patterns = ["feature-*", "dev-*"]
}
actions = {
webhook_url = "https://ci.company.com/webhook/ecr"
block_on_failure = false
}
}
tag_patterns
: List of tag patterns that trigger the ruleseverity_threshold
: Minimum vulnerability severity (LOW
,MEDIUM
,HIGH
,CRITICAL
)require_scan_completion
: Whether to require completed security scansallowed_principals
: List of IAM principals allowed to interact with approved images
require_approval_count
: Number of approvals required (1-10)notification_topic_arn
: SNS topic for notificationswebhook_url
: Webhook URL for external integrationsblock_on_failure
: Whether to block operations on rule failureapproval_timeout_hours
: Hours to wait for approval (1-168)
- Image Push: Developer pushes image to ECR repository
- Rule Evaluation: Pull request rules evaluate the image against configured criteria
- Notification: If approval is required, notifications are sent to configured channels
- Security Scan: Automatic vulnerability scanning is performed
- Manual Review: Security team reviews scan results and compliance
- Approval: If acceptable, image is tagged with approval status
- Deployment: Approved images can be deployed to production
module "ecr_governance" {
source = "lgallard/ecr/aws"
name = "critical-application"
enable_pull_request_rules = true
pull_request_rules = [
# Production approval workflow
{
name = "production-security-approval"
type = "approval"
enabled = true
conditions = {
tag_patterns = ["prod-*", "release-*"]
severity_threshold = "HIGH"
require_scan_completion = true
allowed_principals = [
"arn:aws:iam::123456789012:role/SecurityTeam",
"arn:aws:iam::123456789012:role/ReleaseManagers"
]
}
actions = {
require_approval_count = 3
notification_topic_arn = aws_sns_topic.security_alerts.arn
block_on_failure = true
approval_timeout_hours = 48
}
},
# Automatic security validation
{
name = "security-scan-gate"
type = "security_scan"
enabled = true
conditions = {
tag_patterns = ["*"]
severity_threshold = "MEDIUM"
require_scan_completion = true
}
actions = {
notification_topic_arn = aws_sns_topic.security_alerts.arn
block_on_failure = true
}
},
# CI/CD integration
{
name = "ci-pipeline-integration"
type = "ci_integration"
enabled = true
conditions = {
tag_patterns = ["feature-*", "dev-*", "staging-*"]
}
actions = {
webhook_url = "https://ci.company.com/webhook/ecr-validation"
block_on_failure = false
}
}
]
# Enhanced security scanning
enable_registry_scanning = true
registry_scan_type = "ENHANCED"
enable_secret_scanning = true
}
After implementing pull request rules, use these commands to manage approvals:
# Check image scan results
aws ecr describe-image-scan-findings \
--repository-name production-app \
--image-id imageTag=prod-v1.0.0
# Approve image for production use
aws ecr put-image \
--repository-name production-app \
--image-tag prod-v1.0.0 \
--tag-list Key=ApprovalStatus,Value=approved
# List images with approval status
aws ecr describe-images \
--repository-name production-app \
--query 'imageDetails[*].[imageTags[0],imageTagMutability,imageScanFindingsSummary.findings]'
- Layered Approach: Use multiple rule types for comprehensive governance
- Graduated Enforcement: Strict rules for production, flexible for development
- Clear Workflows: Document approval processes and responsibilities
- Monitoring: Set up CloudWatch alarms for rule violations
- Regular Reviews: Periodically review and update rule configurations
- Testing: Test rule configurations in non-production environments first
Pull request rules integrate seamlessly with CI/CD pipelines:
# GitHub Actions example
- name: Check ECR approval status
run: |
STATUS=$(aws ecr describe-images \
--repository-name $REPO_NAME \
--image-ids imageTag=$IMAGE_TAG \
--query 'imageDetails[0].imageTags' \
--output text | grep -o 'ApprovalStatus.*approved' || echo "not-approved")
if [[ "$STATUS" != *"approved"* ]]; then
echo "Image not approved for deployment"
exit 1
fi
See the pull request rules example for a complete implementation guide.
Here are key security best practices for your ECR repositories:
-
Enable Immutable Tags: Prevent tags from being overwritten to ensure image integrity.
image_tag_mutability = "IMMUTABLE"
-
Enable Enhanced Scanning: Use AWS Inspector for comprehensive vulnerability assessment.
enable_registry_scanning = true registry_scan_type = "ENHANCED" enable_secret_scanning = true
-
Configure Pull-Through Cache: Reduce external dependencies and improve performance.
enable_pull_through_cache = true pull_through_cache_rules = [ { ecr_repository_prefix = "docker-hub" upstream_registry_url = "registry-1.docker.io" } ]
-
Enable Basic Scanning: Automatically scan images for security vulnerabilities (if not using enhanced).
scan_on_push = true
-
Implement Least Privilege Access: Use repository policies that grant only necessary permissions.
-
Enable KMS Encryption: Use AWS KMS for enhanced encryption of container images.
encryption_type = "KMS"
For advanced KMS configuration options, see the Enhanced KMS Configuration section below.
-
Configure Lifecycle Policies: Automatically clean up old or unused images.
For a comprehensive guide with detailed examples, see docs/security-best-practices.md.
Common issues and solutions when working with ECR repositories:
Issue | Solution |
---|---|
Authentication failures | Re-authenticate with aws ecr get-login-password |
Permission denied errors | Check IAM policies and repository policies |
Cannot delete repository | Check for prevent_destroy setting and set to false |
Image scan failures | Verify supported image format and AWS region |
Lifecycle policy not working | Check rule syntax and priorities |
For detailed troubleshooting steps, see docs/troubleshooting.md.
This module includes a dedicated KMS submodule that provides enhanced encryption configuration options for ECR repositories. The KMS submodule offers fine-grained control over key policies, rotation settings, and access management.
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-encrypted-repo"
encryption_type = "KMS"
# Enhanced KMS options
kms_deletion_window_in_days = 14
kms_enable_key_rotation = true
kms_key_rotation_period = 90
tags = {
Environment = "production"
}
}
module "ecr" {
source = "lgallard/ecr/aws"
name = "production-app"
encryption_type = "KMS"
# Advanced KMS configuration
kms_deletion_window_in_days = 30
kms_enable_key_rotation = true
kms_key_rotation_period = 180
kms_multi_region = true
# Access control
kms_key_administrators = [
"arn:aws:iam::123456789012:role/KMSAdminRole"
]
kms_key_users = [
"arn:aws:iam::123456789012:role/ECRAccessRole",
"arn:aws:iam::123456789012:role/CI-CD-Role"
]
# Custom alias
kms_alias_name = "production/ecr/my-app"
# KMS-specific tags
kms_tags = {
KeyType = "ECR-Encryption"
Rotation = "180-days"
MultiRegion = "true"
}
}
module "ecr" {
source = "lgallard/ecr/aws"
name = "custom-policy-repo"
encryption_type = "KMS"
# Custom policy statements
kms_custom_policy_statements = [
{
sid = "AllowCrossAccountAccess"
effect = "Allow"
principals = {
type = "AWS"
identifiers = ["arn:aws:iam::TRUSTED-ACCOUNT:root"]
}
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
conditions = [
{
test = "StringEquals"
variable = "kms:ViaService"
values = ["ecr.us-east-1.amazonaws.com"]
}
]
}
]
}
Feature | Variable | Description |
---|---|---|
Key Management | kms_deletion_window_in_days |
Days before key deletion (7-30) |
kms_enable_key_rotation |
Enable automatic rotation | |
kms_key_rotation_period |
Rotation period in days (90-2555) | |
kms_multi_region |
Create multi-region key | |
Access Control | kms_key_administrators |
Principals with full key access |
kms_key_users |
Principals with encrypt/decrypt access | |
kms_additional_principals |
Additional principals with basic access | |
Policy Customization | kms_custom_policy_statements |
Additional policy statements |
kms_custom_policy |
Complete custom policy JSON | |
Naming & Tagging | kms_alias_name |
Custom alias name |
kms_tags |
KMS-specific tags |
- Granular Access Control: Define specific roles for key administration and usage
- Flexible Rotation: Configure custom rotation periods for compliance requirements
- Multi-Region Support: Create keys that work across multiple AWS regions
- Custom Policies: Add specific policy statements or use completely custom policies
- Enhanced Monitoring: KMS-specific tags for better cost tracking and compliance
- Cross-Account Access: Secure sharing of encrypted repositories across AWS accounts
module "production_ecr" {
source = "lgallard/ecr/aws"
name = "production-microservice"
# Production-grade KMS encryption
encryption_type = "KMS"
kms_deletion_window_in_days = 30 # Longer window for recovery
kms_enable_key_rotation = true
kms_key_rotation_period = 90 # Quarterly rotation
kms_multi_region = true # Multi-region deployment
# Role-based access control
kms_key_administrators = [
"arn:aws:iam::123456789012:role/ProductionKMSAdmins"
]
kms_key_users = [
"arn:aws:iam::123456789012:role/ProductionECRAccess",
"arn:aws:iam::123456789012:role/GitHubActions-Production"
]
# Production tagging strategy
tags = {
Environment = "production"
Application = "microservice"
Owner = "platform-team"
CostCenter = "engineering"
}
kms_tags = {
EncryptionType = "ECR-Production"
ComplianceLevel = "SOC2"
BackupRequired = "true"
}
}
For complete examples and advanced use cases, see the enhanced-kms example.
This module offers many configuration options through variables. Here are some examples of common variable configurations:
module "ecr" {
source = "lgallard/ecr/aws"
name = "my-app-repo"
tags = {
Environment = "Production"
}
}
module "ecr" {
source = "lgallard/ecr/aws"
name = "secure-repo"
image_tag_mutability = "IMMUTABLE" # Prevent tag overwriting
scan_on_push = true # Enable basic vulnerability scanning
encryption_type = "KMS" # Use KMS encryption
prevent_destroy = true # Protect from accidental deletion
}
module "ecr" {
source = "lgallard/ecr/aws"
name = "enhanced-secure-repo"
image_tag_mutability = "IMMUTABLE"
encryption_type = "KMS"
# Enhanced scanning with AWS Inspector
enable_registry_scanning = true
registry_scan_type = "ENHANCED"
enable_secret_scanning = true
# Registry scan filters for high/critical vulnerabilities
registry_scan_filters = [
{
name = "PACKAGE_VULNERABILITY_SEVERITY"
values = ["HIGH", "CRITICAL"]
}
]
# Pull-through cache for Docker Hub
enable_pull_through_cache = true
pull_through_cache_rules = [
{
ecr_repository_prefix = "docker-hub"
upstream_registry_url = "registry-1.docker.io"
}
]
}
module "ecr" {
source = "lgallard/ecr/aws"
name = "advanced-repo"
force_delete = false
enable_logging = true
# Set custom timeouts
timeouts = {
delete = "45m"
}
}
For detailed examples of all variables with explanations, see docs/variable-examples.md.
This module uses Terratest for automated testing of the module functionality. The tests validate that the module can correctly:
- Create an ECR repository with basic settings
- Apply repository and lifecycle policies
- Configure KMS encryption
- Set up image tag mutability
- Configure scan on push features
To run the tests locally, you'll need:
# Clone the repository
git clone https://github.com/lgallard/terraform-aws-ecr.git
cd terraform-aws-ecr
# Run the tests
cd test
go mod tidy
go test -v
For more details on tests, see the test directory README.
Name | Version |
---|---|
terraform | >= 1.3.0 |
archive | >= 2.0.0 |
aws | >= 5.0.0 |
Name | Version |
---|---|
archive | >= 2.0.0 |
aws | >= 5.0.0 |
Name | Source | Version |
---|---|---|
kms | ./modules/kms | n/a |
Name | Description | Type | Default | Required |
---|---|---|---|---|
create_sns_topic | Whether to create an SNS topic for CloudWatch alarm notifications. When enabled, creates a new SNS topic for sending alerts. Only applicable when enable_monitoring is true. Defaults to false. |
bool |
false |
no |
default_tags_cost_center | Cost center tag value for financial tracking and allocation. Should specify the cost center, budget code, or billing department. Example: "engineering", "marketing", "cc-1234" Set to null to disable automatic cost center tagging. |
string |
null |
no |
default_tags_environment | Environment tag value to be automatically applied to all resources. Common values: production, staging, development, test Set to null to disable automatic environment tagging. |
string |
null |
no |
default_tags_owner | Owner tag value to be automatically applied to all resources. Should specify the team, department, or individual responsible for the resource. Example: "platform-team", "data-engineering", "john.doe@company.com" Set to null to disable automatic owner tagging. |
string |
null |
no |
default_tags_project | Project tag value to be automatically applied to all resources. Should specify the project or application name this resource belongs to. Example: "web-app", "data-pipeline", "user-service" Set to null to disable automatic project tagging. |
string |
null |
no |
default_tags_template | Predefined default tag template to use for organizational compliance. Available templates: - "basic": Minimal set of organizational tags (CreatedBy, ManagedBy, Environment) - "cost_allocation": Tags optimized for cost tracking and allocation - "compliance": Tags required for security and compliance frameworks - "sdlc": Tags for software development lifecycle management - null: Use custom default_tags configuration When using a template, it will override individual default_tags_* variables. |
string |
null |
no |
enable_default_tags | Whether to enable automatic default tags for all resources. When enabled, standard organizational tags will be automatically applied. Defaults to true for better resource management and compliance. |
bool |
true |
no |
enable_logging | Whether to enable CloudWatch logging for the repository. When enabled, ECR API actions and image push/pull events will be logged to CloudWatch. Defaults to false. |
bool |
false |
no |
enable_monitoring | Whether to enable CloudWatch monitoring and alerting for the ECR repository. When enabled, creates metric alarms for storage usage, API calls, and security findings. Defaults to false to maintain backward compatibility. |
bool |
false |
no |
enable_pull_request_rules | Whether to enable pull request rules for enhanced governance and quality control. Pull request rules provide approval workflows and validation requirements for container images, similar to pull request approval processes for code repositories. When enabled, additional governance controls will be applied to the ECR repository. Defaults to false. |
bool |
false |
no |
enable_pull_through_cache | Whether to create pull-through cache rules. Pull-through cache rules allow you to cache images from upstream registries. Defaults to false. |
bool |
false |
no |
enable_registry_scanning | Whether to enable enhanced scanning for the ECR registry. Enhanced scanning uses Amazon Inspector to provide detailed vulnerability assessments. This is a registry-level configuration that affects all repositories in the account. Defaults to false. |
bool |
false |
no |
enable_replication | Whether to enable cross-region replication for the ECR registry. When enabled, images will be automatically replicated to the specified regions. Note: This is a registry-level configuration that affects all repositories in the account. Defaults to false. |
bool |
false |
no |
enable_secret_scanning | Whether to enable secret scanning as part of enhanced scanning. This feature detects secrets like API keys, passwords, and tokens in container images. When enabled, automatically sets the registry scan type to ENHANCED, overriding registry_scan_type. Requires enable_registry_scanning to be true. Defaults to false. |
bool |
false |
no |
enable_tag_normalization | Whether to enable automatic tag normalization. When enabled, normalizes tag keys to consistent casing and handles special characters. Defaults to true for better tag consistency across resources. |
bool |
true |
no |
enable_tag_validation | Whether to enable tag validation to ensure compliance with organizational standards. When enabled, validates that required tags are present and follow naming conventions. Defaults to false to maintain backward compatibility. |
bool |
false |
no |
encryption_type | The encryption type for the repository. Valid values are "KMS" or "AES256". | string |
"AES256" |
no |
force_delete | Whether to delete the repository even if it contains images. Setting this to true will delete all images in the repository when the repository is deleted. Use with caution as this operation cannot be undone. Defaults to false for safety. |
bool |
false |
no |
image_scanning_configuration | Configuration block that defines image scanning configuration for the repository. Set to null to use the scan_on_push variable setting. Example: { scan_on_push = true } |
object({ |
null |
no |
image_tag_mutability | The tag mutability setting for the repository. - MUTABLE: Image tags can be overwritten - IMMUTABLE: Image tags cannot be overwritten (recommended for production) Defaults to MUTABLE to maintain backwards compatibility. |
string |
"MUTABLE" |
no |
kms_additional_principals | List of additional IAM principals (ARNs) to grant access to the KMS key. These principals will be granted encrypt/decrypt permissions. Only applicable when a new KMS key is created by this module. Example: ["arn:aws:iam::123456789012:role/CrossAccountRole"] |
list(string) |
[] |
no |
kms_alias_name | Custom alias name for the KMS key (without 'alias/' prefix). If not provided, uses 'ecr/{repository_name}'. Only applicable when a new KMS key is created by this module. Example: "production/ecr/my-app" |
string |
null |
no |
kms_custom_policy | Complete custom policy JSON for the KMS key. If specified, this will override all other policy settings. Only applicable when a new KMS key is created by this module. Use with caution as this bypasses all built-in security policies. |
string |
null |
no |
kms_custom_policy_statements | List of custom policy statements to add to the KMS key policy. These statements will be added to the generated policy. Only applicable when a new KMS key is created by this module. Example: [ { sid = "AllowCloudTrailEncryption" effect = "Allow" principals = { type = "Service" identifiers = ["cloudtrail.amazonaws.com"] } actions = [ "kms:Encrypt", "kms:Decrypt", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:DescribeKey" ] resources = ["*"] } ] |
list(object({ |
[] |
no |
kms_deletion_window_in_days | Number of days to wait before actually deleting the KMS key (7-30 days). Only applicable when a new KMS key is created by this module. Defaults to 7 days for faster cleanup in development environments. |
number |
7 |
no |
kms_enable_key_rotation | Whether to enable automatic key rotation for the KMS key. Only applicable when a new KMS key is created by this module. Defaults to true for enhanced security. |
bool |
true |
no |
kms_key | The ARN of an existing KMS key to use for repository encryption. Only applicable when encryption_type is set to 'KMS'. If not specified when using KMS encryption, a new KMS key will be created. |
string |
null |
no |
kms_key_administrators | List of IAM principals (ARNs) who can administer the KMS key. These principals will have full administrative access to the key. Only applicable when a new KMS key is created by this module. Example: ["arn:aws:iam::123456789012:role/KMSAdminRole"] |
list(string) |
[] |
no |
kms_key_rotation_period | Number of days between automatic key rotations (90-2555 days). Only applicable when a new KMS key is created and key rotation is enabled. If not specified, AWS uses the default rotation period. |
number |
null |
no |
kms_key_users | List of IAM principals (ARNs) who can use the KMS key for cryptographic operations. These principals will be granted encrypt/decrypt permissions. Only applicable when a new KMS key is created by this module. Example: ["arn:aws:iam::123456789012:role/ECRAccessRole"] |
list(string) |
[] |
no |
kms_multi_region | Whether to create a multi-region KMS key. Multi-region keys can be used in multiple AWS regions without cross-region calls. Only applicable when a new KMS key is created by this module. Defaults to false. |
bool |
false |
no |
kms_tags | Additional tags specific to KMS resources. These tags will be applied to the KMS key and alias in addition to the general tags. Only applicable when a new KMS key is created by this module. Example: { KeyType = "ECR-Encryption", Rotation = "Enabled" } |
map(string) |
{} |
no |
lifecycle_expire_tagged_after_days | Number of days after which tagged images should be expired. If specified, creates a lifecycle policy rule to delete tagged images older than N days. This rule applies to ALL tagged images regardless of lifecycle_tag_prefixes_to_keep. Use with caution as this may delete images you want to keep long-term. Range: 1-3650 days (up to 10 years). Set to null to disable this rule. Examples: - 90: Delete tagged images after 90 days (production default) - 30: Delete tagged images after 30 days (cost optimization) - 365: Delete tagged images after 1 year (compliance) |
number |
null |
no |
lifecycle_expire_untagged_after_days | Number of days after which untagged images should be expired. If specified, creates a lifecycle policy rule to delete untagged images older than N days. This rule applies to ALL untagged images regardless of lifecycle_tag_prefixes_to_keep. Range: 1-3650 days (up to 10 years). Set to null to disable this rule. Examples: - 7: Delete untagged images after 7 days (development default) - 14: Delete untagged images after 14 days (production default) - 1: Delete untagged images daily (aggressive cleanup) |
number |
null |
no |
lifecycle_keep_latest_n_images | Number of latest images to keep in the repository. If specified, creates a lifecycle policy rule to keep only the N most recent images. When used with lifecycle_tag_prefixes_to_keep, only applies to images with those tag prefixes. Other images are not affected by this rule and may be managed by other rules. Range: 1-10000 images. Set to null to disable this rule. Examples: - 30: Keep the 30 most recent images - 100: Keep the 100 most recent images (production default) - 10: Keep only 10 images (cost optimization) |
number |
null |
no |
lifecycle_policy | JSON string representing the lifecycle policy. If null (default), no lifecycle policy will be created. Takes precedence over helper variables and templates if specified. See: https://docs.aws.amazon.com/AmazonECR/latest/userguide/lifecycle_policy_examples.html |
string |
null |
no |
lifecycle_policy_template | Predefined lifecycle policy template to use for common scenarios. Templates provide tested configurations and best practices for different environments. Available templates: - "development": Optimized for dev workflows with frequent builds * Keep 50 images * Expire untagged after 7 days * No tagged expiry (developers may need old builds) * Tag prefixes: ["dev", "feature"] - "production": Balanced retention for production stability * Keep 100 images * Expire untagged after 14 days * Expire tagged after 90 days * Tag prefixes: ["v", "release", "prod"] - "cost_optimization": Aggressive cleanup to minimize storage costs * Keep 10 images * Expire untagged after 3 days * Expire tagged after 30 days * Tag prefixes: [] (applies to all images) - "compliance": Long retention for audit and compliance * Keep 200 images * Expire untagged after 30 days * Expire tagged after 365 days (1 year) * Tag prefixes: ["v", "release", "audit"] Set to null to use custom helper variables or manual lifecycle_policy. Configuration precedence: 1. Manual lifecycle_policy (highest - overrides template) 2. Template lifecycle_policy_template (overrides helper variables) 3. Helper variables (lowest precedence) Note: When using a template, all helper variables (lifecycle_keep_latest_n_images, lifecycle_expire_untagged_after_days, etc.) will be ignored to prevent conflicts. |
string |
null |
no |
lifecycle_tag_prefixes_to_keep | List of tag prefixes for images that should be managed by the keep-latest rule. When used with lifecycle_keep_latest_n_images, applies the keep rule ONLY to images with these tag prefixes. Images without these prefixes are not affected by the keep-latest rule. The expire rules (untagged/tagged) still apply to ALL images regardless of this setting. Common patterns: - ["v"]: Apply keep rule to semantic versions (v1.0.0, v2.1.3, etc.) - ["release-", "prod-"]: Apply to release and production builds - ["main", "develop"]: Apply to main branch builds - []: Apply keep rule to ALL images (empty list) Constraints: Maximum 100 prefixes, each up to 255 characters. Set to empty list to apply rules to all images. |
list(string) |
[] |
no |
log_retention_days | Number of days to retain ECR logs in CloudWatch. Only applicable when enable_logging is true. Defaults to 30 days. |
number |
30 |
no |
monitoring_threshold_api_calls | API call volume threshold per minute to trigger CloudWatch alarm. When API calls exceed this threshold, an alarm will be triggered. Only applicable when enable_monitoring is true. Defaults to 1000 calls per minute. |
number |
1000 |
no |
monitoring_threshold_security_findings | Security findings threshold to trigger CloudWatch alarm. When security findings exceed this threshold, an alarm will be triggered. Only applicable when enable_monitoring is true. Defaults to 10 findings. |
number |
10 |
no |
monitoring_threshold_storage | Storage usage threshold in GB to trigger CloudWatch alarm. When repository storage exceeds this threshold, an alarm will be triggered. Only applicable when enable_monitoring is true. Defaults to 10 GB. |
number |
10 |
no |
name | Name of the ECR repository. This name must be unique within the AWS account and region. | string |
n/a | yes |
normalize_tag_values | Whether to normalize tag values by trimming whitespace and handling special characters. Applies common normalizations like removing leading/trailing spaces. Defaults to true for cleaner tag values. |
bool |
true |
no |
policy | JSON string representing the repository policy. If null (default), no repository policy will be created. See: https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html |
string |
null |
no |
prevent_destroy | Whether to protect the repository from being destroyed. When set to true, the repository will have the lifecycle block with prevent_destroy = true. When set to false, the repository can be destroyed. This provides a way to dynamically control protection against accidental deletion. Defaults to false to allow repository deletion. |
bool |
false |
no |
pull_request_rules | List of pull request rule configurations for enhanced governance. Each rule defines governance controls for container image changes. Rule structure: - name: Unique identifier for the rule - type: Type of rule (approval, security_scan, ci_integration) - enabled: Whether the rule is active - conditions: Conditions that trigger the rule - actions: Actions to take when rule conditions are met Example: [ { name = "require-security-approval" type = "approval" enabled = true conditions = { tag_patterns = ["prod-", "release-"] severity_threshold = "HIGH" } actions = { require_approval_count = 2 notification_topic_arn = "arn:aws:sns:region:account:topic" } } ] |
list(object({ |
[] |
no |
pull_through_cache_rules | List of pull-through cache rules to create. Each rule should specify ecr_repository_prefix and upstream_registry_url. Example: [{ ecr_repository_prefix = "docker-hub", upstream_registry_url = "registry-1.docker.io" }] |
list(object({ |
[] |
no |
registry_scan_filters | List of scan filters for filtering scan results when querying ECR scan findings. These filters can be used by external tools or scripts to filter scan results by criteria such as vulnerability severity. Each filter should specify name and values. Example: [{ name = "PACKAGE_VULNERABILITY_SEVERITY", values = ["HIGH", "CRITICAL"] }] Note: These filters are not applied at the registry scanning configuration level, but are made available as outputs for use in querying and filtering scan results. |
list(object({ |
[] |
no |
registry_scan_type | The type of scanning to configure for the registry. - BASIC: Basic scanning for OS vulnerabilities - ENHANCED: Enhanced scanning with Amazon Inspector integration Only applicable when enable_registry_scanning is true. |
string |
"ENHANCED" |
no |
replication_regions | List of AWS regions to replicate ECR images to. Only applicable when enable_replication is true. Example: ["us-west-2", "eu-west-1"] |
list(string) |
[] |
no |
required_tags | List of tag keys that are required to be present. Validation will fail if any of these tags are missing from the final tag set. Example: ["Environment", "Owner", "Project"] Empty list disables required tag validation. |
list(string) |
[] |
no |
scan_on_push | Indicates whether images should be scanned for vulnerabilities after being pushed to the repository. - true: Images will be automatically scanned after each push - false: Images must be scanned manually Only used if image_scanning_configuration is null. |
bool |
true |
no |
scan_repository_filters | List of repository filters to apply for registry scanning. Each filter specifies which repositories should be scanned. Supports wildcard patterns using '' character. If empty, defaults to scanning all repositories (""). Example: ["my-app-*", "important-service"] |
list(string) |
[ |
no |
sns_topic_name | Name of the SNS topic to create or use for alarm notifications. If create_sns_topic is true, this will be the name of the created topic. If create_sns_topic is false, this should be the name of an existing topic. Only applicable when enable_monitoring is true. Defaults to null. |
string |
null |
no |
sns_topic_subscribers | List of email addresses to subscribe to the SNS topic for alarm notifications. Each email address will receive notifications when alarms are triggered. Only applicable when enable_monitoring and create_sns_topic are true. Example: ["admin@company.com", "devops@company.com"] |
list(string) |
[] |
no |
tag_key_case | Enforce consistent casing for tag keys. - "PascalCase": Capitalize first letter of each word (Environment, CostCenter) - "camelCase": First word lowercase, subsequent words capitalized (environment, costCenter) - "snake_case": All lowercase with underscores (environment, cost_center) - "kebab-case": All lowercase with hyphens (environment, cost-center) - null: No case enforcement (preserve original casing) |
string |
"PascalCase" |
no |
tags | A map of tags to assign to all resources created by this module. Tags are key-value pairs that help you manage, identify, organize, search for and filter resources. Example: { Environment = "Production", Owner = "Team" } |
map(string) |
{} |
no |
timeouts | Timeout configuration for repository operations. Specify as an object with a 'delete' key containing a duration string (e.g. "20m"). Example: { delete = "20m" } |
object({ |
{} |
no |
timeouts_delete | Deprecated: Use timeouts = { delete = "duration" } instead. How long to wait for a repository to be deleted. Specify as a duration string, e.g. "20m" for 20 minutes. |
string |
null |
no |
Name | Description |
---|---|
applied_tags | The final set of tags applied to all resources after normalization and default tag application |
cloudwatch_alarms | List of CloudWatch alarms created for ECR monitoring |
cloudwatch_log_group_arn | The ARN of the CloudWatch Log Group used for ECR logs (if logging is enabled) |
kms_alias_arn | The ARN of the KMS alias (if created by this module). |
kms_configuration | Complete KMS configuration information. |
kms_key_arn | The ARN of the KMS key used for repository encryption. |
kms_key_id | The globally unique identifier for the KMS key (if created by this module). |
lifecycle_policy | The lifecycle policy JSON applied to the repository (if any) |
logging_role_arn | The ARN of the IAM role used for ECR logging (if logging is enabled) |
monitoring_status | Status of CloudWatch monitoring configuration |
pull_request_rules | Information about pull request rules configuration |
pull_through_cache_role_arn | The ARN of the IAM role used for pull-through cache operations (if enabled) |
pull_through_cache_rules | List of pull-through cache rules (if enabled) |
registry_id | ID of the ECR registry |
registry_scan_filters | The configured scan filters for filtering scan results (e.g., by vulnerability severity) |
registry_scanning_configuration_arn | The ARN of the ECR registry scanning configuration (if enhanced scanning is enabled) |
registry_scanning_status | Status of ECR registry scanning configuration |
replication_configuration_arn | The ARN of the ECR replication configuration (if replication is enabled) |
replication_regions | List of regions where ECR images are replicated to (if replication is enabled) |
replication_status | Status of ECR replication configuration |
repository_arn | ARN of the ECR repository |
repository_name | Name of the ECR repository |
repository_policy_exists | Whether a repository policy exists for this ECR repository |
repository_url | URL of the ECR repository |
security_status | Comprehensive security status of the ECR configuration |
sns_topic_arn | ARN of the SNS topic used for ECR monitoring alerts (if created) |
tag_compliance_status | Tag compliance and validation status |
tagging_strategy | Summary of the tagging strategy configuration |