In this article, we will outline how to create an Amazon Elastic Container Registry (ECR) in the Amazon Web Services (AWS) Cloud using Terraform.
We will explain what AWS ECR is, what it is used for, and its benefits, before presenting a step-by-step guide to constructing your Terraform file through to successfully deploying ECR.
Lifecycle policies are important to include when setting up your ECR, so we will cover them next. We will also discuss how to import an existing ECR registry into your Terraform state files. In the final example, we will discuss the AWS ECR Terraform module and demonstrate how it is used.
TL;DR
- Create a repository with the
aws_ecr_repositoryresource. Settingimage_tag_mutability = "IMMUTABLE"andscan_on_push = truegives you safer defaults out of the box. - Attach an
aws_ecr_lifecycle_policywith a JSON policy (camelCase keys) to expire old or untagged images and keep storage costs in check. - Bring an existing repository under Terraform management with a top-level import block. Requires Terraform 1.5 or later, and the
idis the repository name. - For multiple repositories that share configuration, use a public module like
terraform-aws-modules/ecr/awsorcloudposse/ecr/aws, or wrap the resource in your own module.
What is AWS ECR (Elastic Container Registry)?
AWS ECR (Elastic Container Registry) is a service offered by AWS that allows developers to store, manage, and deploy Docker container images and Open Container Initiative (OCI) images.
It integrates seamlessly with Amazon ECS, EKS, and other AWS services, enabling streamlined containerized application development and deployment. ECR also provides features like image versioning, access control, and automated scanning for vulnerabilities.
Each ECR account has its own private registry, where you can create one or more repositories to store Docker images, OCI images, and compatible artifacts.
Clients must authenticate to an Amazon ECR private registry as an AWS user before pushing or pulling images. Access must also be granted using the repository policy, which allows you to control permissions for repositories and their contents.
Once authenticated, you can push and pull container images to and from your repositories for local development or use in Amazon ECS (Elastic Container Service) and Amazon EKS (Elastic Kubernetes Service).
Benefits of using Amazon ECR
If you’re developing any kind of containerized application on AWS, ECR is a valuable service to consider for storing and managing your container images.
- Security: ECR is a secure way to store your container images with private repositories that use IAM permissions to control access. ECR provides security features such as encryption of images at rest using Amazon S3-managed encryption keys (SSE-S3) or customer-managed keys (SSE-CMKs).
AWS ECR offers image scanning capabilities that help identify vulnerabilities in your container images, ensuring that you deploy secure and compliant containers.
- Scalability: ECR can handle a large number of container images and scales automatically to meet your needs, allowing you to handle growing storage and traffic demands without manual intervention.
- Integration: ECR integrates well with other AWS services like Amazon Elastic Container Service (ECS), Amazon Elastic Kubernetes Service (EKS), and AWS Lambda, making it easy to deploy containerized applications.
- Fully managed service: AWS ECR eliminates the need to operate and scale the infrastructure required for container image management.
- High availability and durability: ECR ensures high availability and durability of your container images with Amazon S3 storage, providing 99.999999999% (11 9’s) of durability. It also supports Cross-Region and Cross-Account Replication to replicate images where needed easily.
- Cost: ECR offers a pay-as-you-go pricing model, meaning you only pay for the amount of storage used and the data transferred without upfront costs.
Example: Creating an ECR repository with Terraform
Below is an example of how you can write a Terraform configuration to create an ECR repository.
The steps to creating an ECR repository with Terraform are as follows:
- Install Terraform
- Configure Terraform AWS provider
- Create an ECR repository
- Run terraform init
- Run terraform plan
- Apply your configuration
- Verify the deployment in the AWS console
- Run terraform destroy
Step 1 — Install Terraform
Make sure you have Terraform installed on your machine.
You can download it from the official website or follow our step-by-step installation guide.
Step 2 — Configure Terraform AWS provider
Once you have Terraform installed, it’s time to add some configuration files.
Create a new Terraform configuration file (e.g., main.tf). Inside the file, define the AWS provider block with your credentials.
For authentication, you can use environment variables, a shared credentials file, or IAM roles.
provider "aws" {
region = "us-east-1" # Replace with your desired region
}Step 3 — Create an ECR repository
Define the aws_ecr_repository resource block in your main.tf file and specify the name of your ECR repository.
resource "aws_ecr_repository" "my_ecr_repo" {
name = "my-ecr-repo"
image_tag_mutability = "IMMUTABLE" # MUTABLE, IMMUTABLE, IMMUTABLE_WITH_EXCLUSION, or MUTABLE_WITH_EXCLUSION
image_scanning_configuration {
scan_on_push = true
}
}The _WITH_EXCLUSION variants require AWS provider 6.8.0+ and let you exempt specific tag patterns from the mutability setting via image_tag_mutability_exclusion_filter — useful when you want everything immutable except latest or dev-*.
You can find a full list of available arguments for the resource on the official Terraform documentation pages.
Step 4 — Run terraform init
Open a terminal in your project directory and run terraform init command to initialize the Terraform configuration and download the necessary plugins for the AWS provider.
Step 5 — Run terraform plan
Now, let’s run terraform plan to preview the changes Terraform will make to your AWS infrastructure based on your configuration. This allows you to review what will be created before applying it.
Step 6 — Apply your configuration
If the terraform plan output looks good, run terraform apply to create the ECR repository in your AWS account.
Step 7 — Verify the deployment in the AWS console
Log in to the AWS Management Console and navigate to the ECR service. Your newly created repository should be listed.
Step 8 — Run terraform destroy
When you’re finished with the ECR repository and want to remove it, run terraform destroy. This will destroy the resources in your AWS account.
Note: Be cautious, as this cannot be undone by default.
Setting up AWS ECR lifecycle policies in Terraform
With AWS ECR, you can define lifecycle policies to manage the lifecycle of your container images, such as automatically deleting old or unused images, which helps manage costs and storage.
To do this using Terraform, you’ll use the aws_ecr_lifecycle_policy resource block. This resource manages the lifecycle policy for your ECR repository.
For the policy definition, Terraform requires JSON documents to be encoded as a string. You can use the jsonencode function to convert your policy document into a Terraform-usable format.
Add this to your main.tf file:
resource "aws_ecr_lifecycle_policy" "my_policy" {
repository = aws_ecr_repository.my_ecr_repo.name
policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Keep only 10 images"
selection = {
tagStatus = "tagged"
tagPrefixList = ["prod"]
countType = "imageCountMoreThan"
countNumber = 10
}
action = {
type = "expire"
}
}
]
})
}You can customize your policy as needed by configuring multiple rules within the rules list.
rulePrioritydefines the order of execution. Lower numbers run first, and only one rule withtagStatus: anyis allowed, which must have the highest priority value.tagStatus: One oftagged,untagged, orany. Whentagged, you must also supplytagPrefixListortagPatternList.countType: One ofimageCountMoreThan(cap the number of images),sinceImagePushed(expire images older than N days based on push time),sinceImagePulled(transition images not pulled in N days to archive storage), orsinceImageTransitioned(expire archived images older than N days).countNumber: A positive integer. Its meaning depends oncountType: either the maximum image count to retain, or the age threshold in days.countUnit: Required whencountTypeissinceImagePushed,sinceImagePulled, orsinceImageTransitioned. The only accepted value isdays.action.type: Eitherexpire(delete the image) ortransition(move to archive storage).transitionis required whencountTypeissinceImagePulled.
How to import existing ECR repository into Terraform
If you have an existing ECR repository you want to bring under Terraform management, you’ll need to import it into the state. Terraform versions 1.5.0 and later allow importing existing resources using the import block within your resource definition.
Add a top-level import block that points to a matching aws_ecr_repository resource block. The two arguments are:
to: The Terraform resource address to import into. This is a resource reference, not a string.id: The identifier of the existing repository in AWS, which is the repository name.
import {
to = aws_ecr_repository.my_ecr_repo
id = "existing-repo-name" # Replace with your existing repo name
}
resource "aws_ecr_repository" "my_ecr_repo" {
name = "existing-repo-name"
image_tag_mutability = "MUTABLE"
# Add any other attributes that match the live repository
}Run terraform plan to preview the import. Terraform will show the resource being adopted into state with no changes if your configuration matches the live resource, or a diff if it doesn’t.
Run terraform apply to perform the import. Once the apply succeeds, you can remove the import block from your configuration — it’s only needed for the initial import.
AWS ECR Terraform module
If you plan to create multiple ECR repositories with similar configurations, you should consider using Terraform modules for reusability best practice.
Modules allow you to define the ECR repository configuration once and reuse it for multiple repositories with minor adjustments. Centralizing configuration in a module makes it easier to manage and update the code for all ECR repositories. Modules also promote code organization and separation between core infrastructure and specific resource configurations.
You can use a public or private module for this. Public modules offer a quick starting point, while private modules provide greater control and customization. Here is a good example of a public one.
If you prefer to develop a private module:
- Create a separate directory for your module code (e.g.,
modules/ecr). - Inside the directory, create a file named
main.tfcontaining theaws_ecr_repositoryresource definition with desired configuration options. - Optionally, create a
variables.tffile to define variables that can be customized when using the module. - Create an
outputs.tffile (also optional) to expose module outputs, such as the ECR repository URI.
Example: Using the Public ECR module in Terraform
Here’s an example using the terraform-aws-modules/ecr/aws module, which also lets you define the lifecycle policy inline. A popular alternative is cloudposse/ecr/aws, which uses a different input convention (namespace, stage, name, principals_full_access) if you prefer that style.
Follow the steps listed previously and replace the code in Step 3 with the following to use the module rather than the resource directly.
module "ecr" {
source = "terraform-aws-modules/ecr/aws"
repository_name = "private-example"
repository_read_write_access_arns = ["arn:aws:iam::012345678901:role/terraform"]
repository_lifecycle_policy = jsonencode({
rules = [
{
rulePriority = 1,
description = "Keep last 30 images",
selection = {
tagStatus = "tagged",
tagPrefixList = ["v"],
countType = "imageCountMoreThan",
countNumber = 30
},
action = {
type = "expire"
}
}
]
})
tags = {
Terraform = "true"
Environment = "dev"
}
}Deploying Terraform resources with Spacelift
Terraform is really powerful, but to achieve an end-to-end secure GitOps approach, you need a platform that can orchestrate your Terraform workflows.
Spacelift is the infrastructure orchestration platform built for the AI-accelerated software era. It manages the full lifecycle for both traditional infrastructure as code (IaC) and AI-provisioned infrastructure, giving you access to a powerful CI/CD workflow and unlocking features such as:
- Policies (based on Open Policy Agent) – You can control how many approvals you need for runs, what kind of resources you can create, and what kind of parameters these resources can have, and you can also control the behavior when a pull request is open or merged.
- Multi-IaC workflows – Combine Terraform with Kubernetes, Ansible, and other IaC tools such as OpenTofu, Pulumi, and CloudFormation, create dependencies among them, and share outputs.
- Build self-service infrastructure – You can use Templates and Blueprints to build self-service infrastructure; simply complete a form to provision infrastructure based on Terraform and other supported tools.
- AI-powered provisioning and diagnostics – Spacelift Intelligence adds an AI-powered layer for natural language provisioning, diagnostics, and operational insight across your infrastructure workflows.
- Integrations with any third-party tools – You can integrate with your favorite third-party tools and even build policies for them. For example, see how to integrate security tools in your workflows using Custom Inputs.
Spacelift enables you to create private workers inside your infrastructure, which helps you execute Spacelift-related workflows on your end. Read the documentation for more information on configuring private workers.
You can check it for free by creating a trial account or requesting a demo with one of our engineers.
Key points
AWS ECR simplifies the process of managing and deploying Docker container images, providing a secure, scalable, and highly available container registry service integrated within the AWS ecosystem.
Creating and managing your ECR with Terraform (using resource blocks or modules) allows you to reap the benefits of infrastructure as code, including improving the consistency, efficiency, and reliability of your AWS deployments.
If you want to learn more about Spacelift, create a free account today, or book a demo with one of our engineers.
Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.
Automate Terraform Deployments with Spacelift
Automate your infrastructure provisioning, build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization, and many more.
Frequently asked questions
Is ECR the same as Docker?
Amazon Elastic Container Registry (ECR) is a managed container image registry service provided by AWS, used to store, manage, and deploy Docker container images.
What is an ECR used for?
ECR is used to store, manage, and deploy Docker container images in AWS. It integrates with services like ECS, EKS, and CodeBuild, allowing secure, scalable image storage without managing your own registry.
Is ECR backed by S3?
ECR uses S3 as the underlying storage layer, which provides durability, availability, and lifecycle management for the images. However, access to this storage is abstracted, and users interact with ECR via its API or CLI, not directly with S3.
How do I make ECR tags immutable except for latest?
Set the repository’s tag mutability to IMMUTABLE_WITH_EXCLUSION and add a wildcard filter for the tags you want kept mutable, like this:
aws ecr put-image-tag-mutability --repository-name my-repo --image-tag-mutability IMMUTABLE_WITH_EXCLUSION --image-tag-mutability-exclusion-filters filterType=WILDCARD,filter=latest.What's the difference between basic and enhanced image scanning?
Basic scanning is free, runs on push or on demand, and only detects OS package CVEs using the Clair database. Enhanced scanning is powered by Amazon Inspector, costs extra, and continuously scans for both OS and programming language package vulnerabilities, with findings forwarded to Security Hub and EventBridge.
How do I delete an ECR repo that still has images?
Pass the force flag to skip the empty-repository requirement:
aws ecr delete-repository --repository-name my-repo --force. Without--force, ECR will reject the call and you must delete all images first.How do I let another AWS account pull from my ECR?
Attach a repository policy that grants the other account’s principal the pull actions (ecr:BatchGetImage, ecr:GetDownloadUrlForLayer, ecr:BatchCheckLayerAvailability), then have that account’s IAM identity hold matching pull permissions plus ecr:GetAuthorizationToken on *.
