https://github.com/lgallard/terraform-aws-ecr
Terraform module to create AWS ECR (Elastic Container Registry)
https://github.com/lgallard/terraform-aws-ecr
aws aws-ecr aws-ecr-terraform ecr-registry terraform terraform-module terraform-modules
Last synced: 3 months ago
JSON representation
Terraform module to create AWS ECR (Elastic Container Registry)
- Host: GitHub
- URL: https://github.com/lgallard/terraform-aws-ecr
- Owner: lgallard
- License: apache-2.0
- Created: 2020-04-30T19:59:34.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2025-07-20T00:48:36.000Z (3 months ago)
- Last Synced: 2025-07-20T05:24:57.988Z (3 months ago)
- Topics: aws, aws-ecr, aws-ecr-terraform, ecr-registry, terraform, terraform-module, terraform-modules
- Language: HCL
- Homepage:
- Size: 26.1 MB
- Stars: 11
- Watchers: 2
- Forks: 20
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README

# terraform-aws-ecrTerraform module to create [AWS ECR](https://aws.amazon.com/ecr/) (Elastic Container Registry) which is a fully-managed Docker container registry.
[](https://github.com/lgallard/terraform-aws-ecr/actions/workflows/test.yml)
## Architecture
The terraform-aws-ecr module enables several common architectures for container image management.
### Basic ECR Architecture
```
┌──────────────┐ ┌───────────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ 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](docs/diagrams.md).
## Versioning
This module follows [Semantic Versioning](https://semver.org/) principles. For full details on the versioning scheme, release process, and compatibility guarantees, see the following documentation:
- [VERSIONING.md](VERSIONING.md) - Details on the semantic versioning scheme and release process
- [VERSION_COMPATIBILITY.md](VERSION_COMPATIBILITY.md) - Terraform and AWS provider compatibility matrix## Usage
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](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### Simple example
This example creates an ECR registry using few parameters```hcl
module "ecr" {
source = "lgallard/ecr/aws"name = "ecr-repo-dev"
# Tags
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
```### Complete example with logging
In this example, the registry is defined in detail including CloudWatch logging:```hcl
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...
}
```### CloudWatch Logging
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:
```hcl
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 Group
- `logging_role_arn` - The ARN of the IAM role used for logging### CloudWatch Monitoring and Alerting
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#### Basic Monitoring Setup
```hcl
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"]
}
```#### Monitoring Features
**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#### Advanced Monitoring Configuration
```hcl
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 status
- `sns_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### Cross-Region Replication
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.
```hcl
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 regionsThe module provides replication-related outputs:
- `replication_status` - Overall replication configuration status
- `replication_regions` - List of destination regions
- `replication_configuration_arn` - ARN of the replication configurationFor more detailed examples, see the [replication example](examples/replication/) and [multi-region example](examples/multi-region/).
### Complete 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 = <
## Requirements| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.3.0 |
| [archive](#requirement\_archive) | >= 2.0.0 |
| [aws](#requirement\_aws) | >= 5.0.0 |## Providers
| Name | Version |
|------|---------|
| [archive](#provider\_archive) | >= 2.0.0 |
| [aws](#provider\_aws) | >= 5.0.0 |## Modules
| Name | Source | Version |
|------|--------|---------|
| [kms](#module\_kms) | ./modules/kms | n/a |## Resources
| Name | Type |
|------|------|
| [aws_cloudwatch_event_rule.pull_request_rules](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
| [aws_cloudwatch_event_target.pull_request_rules_sns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
| [aws_cloudwatch_event_target.pull_request_rules_webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
| [aws_cloudwatch_log_group.ecr_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_cloudwatch_metric_alarm.api_call_volume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |
| [aws_cloudwatch_metric_alarm.image_pull_count](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |
| [aws_cloudwatch_metric_alarm.image_push_count](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |
| [aws_cloudwatch_metric_alarm.repository_storage_usage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |
| [aws_cloudwatch_metric_alarm.security_findings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |
| [aws_ecr_lifecycle_policy.lifecycle_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_lifecycle_policy) | resource |
| [aws_ecr_pull_through_cache_rule.cache_rules](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_pull_through_cache_rule) | resource |
| [aws_ecr_registry_scanning_configuration.scanning](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_registry_scanning_configuration) | resource |
| [aws_ecr_replication_configuration.replication](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_replication_configuration) | resource |
| [aws_ecr_repository.repo](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |
| [aws_ecr_repository.repo_protected](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |
| [aws_ecr_repository_policy.policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource |
| [aws_iam_role.ecr_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.pull_request_rules_webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.pull_through_cache](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.ecr_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role_policy.pull_through_cache](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role_policy_attachment.pull_request_rules_webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_lambda_function.pull_request_rules_webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |
| [aws_lambda_permission.pull_request_rules_webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_sns_topic.ecr_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource |
| [aws_sns_topic.pull_request_rules](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource |
| [aws_sns_topic_subscription.ecr_monitoring_email](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_subscription) | resource |
| [archive_file.pull_request_rules_webhook](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [create\_sns\_topic](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_encryption\_type) | The encryption type for the repository. Valid values are "KMS" or "AES256". | `string` | `"AES256"` | no |
| [force\_delete](#input\_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](#input\_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 |
scan_on_push = bool
})
| [image\_tag\_mutability](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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 |
sid = optional(string)
effect = string
principals = optional(object({
type = string
identifiers = list(string)
}))
actions = list(string)
resources = optional(list(string), ["*"])
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
}))
| [kms\_deletion\_window\_in\_days](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_name) | Name of the ECR repository. This name must be unique within the AWS account and region. | `string` | n/a | yes |
| [normalize\_tag\_values](#input\_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](#input\_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](#input\_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](#input\_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 |
name = string
type = string
enabled = bool
conditions = optional(object({
tag_patterns = optional(list(string), [])
severity_threshold = optional(string, "MEDIUM")
require_scan_completion = optional(bool, true)
allowed_principals = optional(list(string), [])
}), {})
actions = optional(object({
require_approval_count = optional(number, 1)
notification_topic_arn = optional(string)
webhook_url = optional(string)
block_on_failure = optional(bool, true)
approval_timeout_hours = optional(number, 24)
}), {})
}))
| [pull\_through\_cache\_rules](#input\_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 |
ecr_repository_prefix = string
upstream_registry_url = string
credential_arn = optional(string)
}))
| [registry\_scan\_filters](#input\_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 |
name = string
values = list(string)
}))
| [registry\_scan\_type](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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](#input\_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 |
delete = optional(string)
})
| [timeouts\_delete](#input\_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 |## Outputs
| Name | Description |
|------|-------------|
| [applied\_tags](#output\_applied\_tags) | The final set of tags applied to all resources after normalization and default tag application |
| [cloudwatch\_alarms](#output\_cloudwatch\_alarms) | List of CloudWatch alarms created for ECR monitoring |
| [cloudwatch\_log\_group\_arn](#output\_cloudwatch\_log\_group\_arn) | The ARN of the CloudWatch Log Group used for ECR logs (if logging is enabled) |
| [kms\_alias\_arn](#output\_kms\_alias\_arn) | The ARN of the KMS alias (if created by this module). |
| [kms\_configuration](#output\_kms\_configuration) | Complete KMS configuration information. |
| [kms\_key\_arn](#output\_kms\_key\_arn) | The ARN of the KMS key used for repository encryption. |
| [kms\_key\_id](#output\_kms\_key\_id) | The globally unique identifier for the KMS key (if created by this module). |
| [lifecycle\_policy](#output\_lifecycle\_policy) | The lifecycle policy JSON applied to the repository (if any) |
| [logging\_role\_arn](#output\_logging\_role\_arn) | The ARN of the IAM role used for ECR logging (if logging is enabled) |
| [monitoring\_status](#output\_monitoring\_status) | Status of CloudWatch monitoring configuration |
| [pull\_request\_rules](#output\_pull\_request\_rules) | Information about pull request rules configuration |
| [pull\_through\_cache\_role\_arn](#output\_pull\_through\_cache\_role\_arn) | The ARN of the IAM role used for pull-through cache operations (if enabled) |
| [pull\_through\_cache\_rules](#output\_pull\_through\_cache\_rules) | List of pull-through cache rules (if enabled) |
| [registry\_id](#output\_registry\_id) | ID of the ECR registry |
| [registry\_scan\_filters](#output\_registry\_scan\_filters) | The configured scan filters for filtering scan results (e.g., by vulnerability severity) |
| [registry\_scanning\_configuration\_arn](#output\_registry\_scanning\_configuration\_arn) | The ARN of the ECR registry scanning configuration (if enhanced scanning is enabled) |
| [registry\_scanning\_status](#output\_registry\_scanning\_status) | Status of ECR registry scanning configuration |
| [replication\_configuration\_arn](#output\_replication\_configuration\_arn) | The ARN of the ECR replication configuration (if replication is enabled) |
| [replication\_regions](#output\_replication\_regions) | List of regions where ECR images are replicated to (if replication is enabled) |
| [replication\_status](#output\_replication\_status) | Status of ECR replication configuration |
| [repository\_arn](#output\_repository\_arn) | ARN of the ECR repository |
| [repository\_name](#output\_repository\_name) | Name of the ECR repository |
| [repository\_policy\_exists](#output\_repository\_policy\_exists) | Whether a repository policy exists for this ECR repository |
| [repository\_url](#output\_repository\_url) | URL of the ECR repository |
| [security\_status](#output\_security\_status) | Comprehensive security status of the ECR configuration |
| [sns\_topic\_arn](#output\_sns\_topic\_arn) | ARN of the SNS topic used for ECR monitoring alerts (if created) |
| [tag\_compliance\_status](#output\_tag\_compliance\_status) | Tag compliance and validation status |
| [tagging\_strategy](#output\_tagging\_strategy) | Summary of the tagging strategy configuration |