Skip to content

lgallard/terraform-aws-ecr

Repository files navigation

Terraform

terraform-aws-ecr

Terraform module to create AWS ECR (Elastic Container Registry) which is a fully-managed Docker container registry.

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.

Versioning

This module follows Semantic Versioning principles. For full details on the versioning scheme, release process, and compatibility guarantees, see the following documentation:

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 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

Simple example

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
  }
}

Complete example with logging

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...
}

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:

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

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 = <<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
}
  1. Apply the configuration change:
terraform apply
  1. 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.

Security Best Practices

Here are key security best practices for your ECR repositories:

  1. Enable Immutable Tags: Prevent tags from being overwritten to ensure image integrity.

    image_tag_mutability = "IMMUTABLE"
  2. Enable Vulnerability Scanning: Automatically scan images for security vulnerabilities.

    scan_on_push = true
  3. Implement Least Privilege Access: Use repository policies that grant only necessary permissions.

  4. Enable KMS Encryption: Use AWS KMS for enhanced encryption of container images.

    encryption_type = "KMS"
  5. Configure Lifecycle Policies: Automatically clean up old or unused images.

For a comprehensive guide with detailed examples, see docs/security-best-practices.md.

Troubleshooting

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.

Variable Usage Examples

This module offers many configuration options through variables. Here are some examples of common variable configurations:

Basic Configuration

module "ecr" {
  source = "lgallard/ecr/aws"
  
  name   = "my-app-repo"
  tags   = {
    Environment = "Production"
  }
}

Security Settings

module "ecr" {
  source = "lgallard/ecr/aws"
  
  name                 = "secure-repo"
  image_tag_mutability = "IMMUTABLE"    # Prevent tag overwriting
  scan_on_push         = true           # Enable vulnerability scanning
  encryption_type      = "KMS"          # Use KMS encryption
  prevent_destroy      = true           # Protect from accidental deletion
}

Advanced Options

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.

Requirements

Name Version
terraform >= 1.3.0
aws >= 5.0.0

Providers

Name Version
aws >= 5.0.0

Modules

No modules.

Resources

Name Type
aws_cloudwatch_log_group.ecr_logs resource
aws_ecr_lifecycle_policy.lifecycle_policy resource
aws_ecr_repository.repo resource
aws_ecr_repository.repo_protected resource
aws_ecr_repository_policy.policy resource
aws_iam_role.ecr_logging resource
aws_iam_role_policy.ecr_logging resource
aws_kms_alias.kms_key_alias resource
aws_kms_key.kms_key resource
aws_caller_identity.current data source

Inputs

Name Description Type Default Required
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
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({
scan_on_push = bool
})
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_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
lifecycle_policy JSON string representing the lifecycle policy.
If null (default), no lifecycle policy will be created.
See: https://docs.aws.amazon.com/AmazonECR/latest/userguide/lifecycle_policy_examples.html
string null 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
name Name of the ECR repository. This name must be unique within the AWS account and region. string n/a yes
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
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
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({
delete = optional(string)
})
{} 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

Outputs

Name Description
cloudwatch_log_group_arn The ARN of the CloudWatch Log Group used for ECR logs (if logging is enabled)
kms_key_arn The ARN of the KMS key used for repository encryption.
logging_role_arn The ARN of the IAM role used for ECR logging (if logging is enabled)
registry_id ID of the ECR registry
repository_arn ARN of the ECR repository
repository_name Name of the ECR repository
repository_url URL of the ECR repository

About

Terraform module to create AWS ECR (Elastic Container Registry)

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 5

Languages