ContainersIntermediate15 min read

    Amazon ECR Security Best Practices

    Tarek Cheikh

    Founder & AWS Security Expert

    View Security Card

    Amazon Elastic Container Registry (ECR) is the fully managed container registry at the heart of every AWS container workload. Whether you deploy to ECS, EKS, or Lambda, ECR stores and distributes the container images that become your running applications. A compromised or misconfigured registry can undermine your entire container supply chain -- an attacker who can push a poisoned image to ECR effectively controls what code runs in production.

    The container supply chain has become a top target. In 2025, AWS enhanced ECR with managed image signing, ECR-to-ECR pull through cache support, archive storage classes, and expanded Inspector scanning that now covers scratch, distroless, and Chainguard base images. Amazon Inspector also added image usage status tracking, showing which images are actively running on ECS and EKS clusters so teams can prioritize vulnerability remediation for images that actually matter.

    This guide covers 12 security best practices for ECR with real AWS CLI commands, directly aligned with AWS Security Hub controls [ECR.1], [ECR.2], and [ECR.3]. For a quick overview of ECR security posture, see our ECR security card.

    1. Enable Enhanced Image Scanning with Amazon Inspector

    Security Hub Control: [ECR.1] -- ECR private repositories should have image scanning configured. Enhanced scanning, powered by Amazon Inspector, goes far beyond basic scanning by providing continuous, automated vulnerability detection for both operating system packages and programming language dependencies (Python, Java, Node.js, Go, .NET, and more).

    As of early 2026, Inspector supports scanning of minimal container bases including scratch, distroless (Debian/Ubuntu-based), and Chainguard images, along with expanded ecosystem coverage for Go toolchains, Oracle JDK, Amazon Corretto, Apache Tomcat, and WordPress. Enhanced scanning also surfaces image usage status -- which clusters are running each image, when it was last pulled, and how many clusters reference it -- so you can focus remediation on actively deployed images.

    Implementation

    # Enable enhanced scanning at the registry level
    aws ecr put-registry-scanning-configuration \
      --scan-type ENHANCED \
      --rules '[{"scanFrequency":"CONTINUOUS_SCAN","repositoryFilters":[{"filter":"*","filterType":"WILDCARD"}]}]'
    
    # Verify the scanning configuration
    aws ecr get-registry-scanning-configuration
    
    # Check scan findings for a specific image
    aws ecr describe-image-scan-findings \
      --repository-name my-app \
      --image-id imageTag=latest
    
    # List images with CRITICAL or HIGH vulnerabilities using Inspector
    aws inspector2 list-findings \
      --filter-criteria '{
        "resourceType": [{"comparison":"EQUALS","value":"AWS_ECR_CONTAINER_IMAGE"}],
        "severity": [{"comparison":"EQUALS","value":"CRITICAL"}]
      }'

    For production environments, configure EventBridge rules to alert on new CRITICAL or HIGH findings so your team can respond before vulnerable images reach production.

    2. Enable Image Tag Immutability

    Security Hub Control: [ECR.2] -- ECR private repositories should have tag immutability configured. Without immutable tags, an attacker (or even a misconfigured CI pipeline) can overwrite an existing image tag such as v1.2.3 with a completely different image. Every service pulling that tag would then run the replaced image without any warning. Immutable tags prevent this by returning an ImageTagAlreadyExistsException if anyone attempts to push an image with a tag that already exists in the repository.

    Implementation

    # Create a new repository with immutable tags
    aws ecr create-repository \
      --repository-name my-app \
      --image-tag-mutability IMMUTABLE
    
    # Update an existing repository to use immutable tags
    aws ecr put-image-tag-mutability \
      --repository-name my-app \
      --image-tag-mutability IMMUTABLE
    
    # Verify the setting
    aws ecr describe-repositories \
      --repository-names my-app \
      --query 'repositories[0].imageTagMutability'

    With immutable tags enabled, your CI/CD pipeline must generate unique tags for every build (e.g., commit SHA, build number, or semantic version). Never rely on mutable tags like latest in production deployments.

    3. Configure Lifecycle Policies

    Security Hub Control: [ECR.3] -- ECR repositories should have at least one lifecycle policy configured. Without lifecycle policies, repositories accumulate images indefinitely, increasing storage costs and expanding your attack surface with stale, potentially vulnerable images. Lifecycle policies automate cleanup by expiring images based on age, count, or tag status.

    Implementation

    # Apply a lifecycle policy that keeps only the last 30 tagged images
    # and removes untagged images older than 1 day
    aws ecr put-lifecycle-policy \
      --repository-name my-app \
      --lifecycle-policy-text '{
        "rules": [
          {
            "rulePriority": 1,
            "description": "Remove untagged images after 1 day",
            "selection": {
              "tagStatus": "untagged",
              "countType": "sinceImagePushed",
              "countUnit": "days",
              "countNumber": 1
            },
            "action": { "type": "expire" }
          },
          {
            "rulePriority": 2,
            "description": "Keep only last 30 tagged images",
            "selection": {
              "tagStatus": "tagged",
              "tagPrefixList": ["v"],
              "countType": "imageCountMoreThan",
              "countNumber": 30
            },
            "action": { "type": "expire" }
          }
        ]
      }'
    
    # Preview what the policy would delete before applying
    aws ecr get-lifecycle-policy-preview \
      --repository-name my-app

    ECR now also supports an archive storage class for rarely accessed images. You can use lifecycle rules to automatically transition images to archive storage based on usage patterns, reducing costs while retaining images for compliance requirements. Note that archived images must remain in archive for a minimum of 90 days before deletion.

    4. Encrypt Repositories with Customer-Managed KMS Keys

    By default, ECR encrypts images at rest using Amazon S3-managed keys (SSE-S3). While this provides baseline encryption, customer-managed KMS keys give you full control over key rotation, access policies, and audit trails through CloudTrail. This is often required for compliance frameworks like PCI DSS, HIPAA, and FedRAMP.

    Implementation

    # Create a KMS key for ECR encryption
    aws kms create-key \
      --description "ECR repository encryption key" \
      --key-usage ENCRYPT_DECRYPT \
      --origin AWS_KMS
    
    # Create a repository with KMS encryption
    aws ecr create-repository \
      --repository-name my-secure-app \
      --encryption-configuration '{
        "encryptionType": "KMS",
        "kmsKey": "arn:aws:kms:us-east-1:111122223333:key/your-key-id"
      }' \
      --image-tag-mutability IMMUTABLE
    
    # Verify encryption configuration
    aws ecr describe-repositories \
      --repository-names my-secure-app \
      --query 'repositories[0].encryptionConfiguration'

    Important: encryption type cannot be changed after repository creation. Plan your encryption strategy before creating repositories. Use repository creation templates to enforce KMS encryption for all new repositories created via pull through cache or replication.

    5. Restrict Access with Repository Policies

    ECR repository policies provide resource-based access control at the repository level. Without explicit policies, repositories inherit broad permissions from IAM identity policies, which can lead to unauthorized image pulls or pushes. A well-crafted repository policy restricts who can push, pull, and manage images within each repository.

    Implementation

    # Set a repository policy that allows only specific roles to push
    # and restricts pull access to specific accounts
    aws ecr set-repository-policy \
      --repository-name my-app \
      --policy-text '{
        "Version": "2012-10-17",
        "Statement": [
          {
            "Sid": "AllowPushFromCICD",
            "Effect": "Allow",
            "Principal": {
              "AWS": "arn:aws:iam::111122223333:role/cicd-pipeline-role"
            },
            "Action": [
              "ecr:BatchCheckLayerAvailability",
              "ecr:CompleteLayerUpload",
              "ecr:InitiateLayerUpload",
              "ecr:PutImage",
              "ecr:UploadLayerPart"
            ]
          },
          {
            "Sid": "AllowPullFromECS",
            "Effect": "Allow",
            "Principal": {
              "AWS": "arn:aws:iam::111122223333:role/ecs-task-execution-role"
            },
            "Action": [
              "ecr:BatchGetImage",
              "ecr:GetDownloadUrlForLayer"
            ]
          }
        ]
      }'
    
    # Verify the repository policy
    aws ecr get-repository-policy --repository-name my-app

    For defense in depth, combine repository policies with IAM identity policies and VPC endpoint policies. Use condition keys like aws:SourceVpc or aws:SourceVpce to restrict access to specific VPCs or endpoints.

    6. Use VPC Endpoints for Private Network Access

    By default, ECR API calls and Docker image pulls traverse the public internet. VPC interface endpoints (powered by AWS PrivateLink) keep all ECR traffic within the AWS network, eliminating exposure to the public internet and reducing data transfer costs. This is essential for workloads in private subnets that have no internet gateway or NAT device.

    Implementation

    # Create the ECR API endpoint (for describe, create, list operations)
    aws ec2 create-vpc-endpoint \
      --vpc-id vpc-0123456789abcdef0 \
      --service-name com.amazonaws.us-east-1.ecr.api \
      --vpc-endpoint-type Interface \
      --subnet-ids subnet-aaa111 subnet-bbb222 \
      --security-group-ids sg-0123456789abcdef0 \
      --private-dns-enabled
    
    # Create the ECR Docker endpoint (for push/pull operations)
    aws ec2 create-vpc-endpoint \
      --vpc-id vpc-0123456789abcdef0 \
      --service-name com.amazonaws.us-east-1.ecr.dkr \
      --vpc-endpoint-type Interface \
      --subnet-ids subnet-aaa111 subnet-bbb222 \
      --security-group-ids sg-0123456789abcdef0 \
      --private-dns-enabled
    
    # Create an S3 Gateway endpoint (required -- ECR stores image layers in S3)
    aws ec2 create-vpc-endpoint \
      --vpc-id vpc-0123456789abcdef0 \
      --service-name com.amazonaws.us-east-1.s3 \
      --vpc-endpoint-type Gateway \
      --route-table-ids rtb-0123456789abcdef0
    
    # Verify the endpoints are available
    aws ec2 describe-vpc-endpoints \
      --filters "Name=service-name,Values=com.amazonaws.us-east-1.ecr.*" \
      --query 'VpcEndpoints[*].{Service:ServiceName,State:State}'

    Ensure the security group attached to the VPC endpoints allows inbound TCP traffic on port 443 from your private subnets. For ECS Fargate tasks, add condition keys to the task execution role that restrict ECR access to the specific VPC endpoint using aws:sourceVpce.

    7. Sign Container Images with ECR Managed Signing

    Image signing establishes a cryptographic chain of trust from build to deployment. Without signing, there is no way to verify that an image in ECR was actually produced by your CI/CD pipeline and has not been tampered with. ECR now offers managed signing, which automatically signs images during push using AWS Signer -- no need to install Notation or Cosign tooling in your pipeline.

    Implementation

    # Create an AWS Signer signing profile for container images
    aws signer put-signing-profile \
      --profile-name ecr-container-signing \
      --platform-id Notation-OCI-SHA384-ECDSA
    
    # For signing with Notation CLI and AWS Signer plugin:
    # Install the AWS Signer plugin for Notation
    notation plugin install --url https://d2hvyiie56hcat.cloudfront.net/linux/amd64/plugin/latest/notation-aws-signer-plugin.zip
    
    # Sign an image
    notation sign \
      111122223333.dkr.ecr.us-east-1.amazonaws.com/my-app:v1.0.0 \
      --plugin com.amazonaws.signer.notation.plugin \
      --id arn:aws:signer:us-east-1:111122223333:/signing-profiles/ecr-container-signing
    
    # Verify the signature
    notation verify \
      111122223333.dkr.ecr.us-east-1.amazonaws.com/my-app:v1.0.0

    For EKS deployments, integrate image verification with Kubernetes admission controllers so that only signed images are admitted to the cluster. Cross-account signing is supported -- a central security account can own signing profiles while developer accounts use them to sign images.

    8. Secure Pull Through Cache Rules

    Pull through cache rules allow you to cache images from upstream registries (Docker Hub, GitHub Container Registry, Quay, and as of March 2025, other ECR registries) into your private ECR registry. This reduces external dependencies, avoids Docker Hub rate limits, and gives you a controlled copy of third-party images that you can scan before deployment. However, misconfigured pull through caches can introduce unscanned upstream images into your environment.

    Implementation

    # Create a pull through cache rule for Docker Hub
    aws ecr create-pull-through-cache-rule \
      --ecr-repository-prefix docker-hub \
      --upstream-registry-url registry-1.docker.io \
      --credential-arn arn:aws:secretsmanager:us-east-1:111122223333:secret:dockerhub-creds
    
    # Create a repository creation template to enforce security settings
    # on all repositories created by pull through cache
    aws ecr create-repository-creation-template \
      --prefix "docker-hub/*" \
      --applied-for PULL_THROUGH_CACHE \
      --image-tag-mutability IMMUTABLE \
      --encryption-configuration '{"encryptionType":"KMS","kmsKey":"arn:aws:kms:us-east-1:111122223333:key/your-key-id"}' \
      --resource-tags '[{"Key":"source","Value":"pull-through-cache"}]' \
      --lifecycle-policy '{
        "rules": [{
          "rulePriority": 1,
          "selection": {"tagStatus":"untagged","countType":"sinceImagePushed","countUnit":"days","countNumber":7},
          "action": {"type":"expire"}
        }]
      }'
    
    # List existing pull through cache rules
    aws ecr describe-pull-through-cache-rules

    Always pair pull through cache rules with repository creation templates that enforce scanning, immutable tags, encryption, and lifecycle policies. Store upstream registry credentials in AWS Secrets Manager and rotate them regularly.

    9. Implement Least-Privilege Cross-Account Access

    Multi-account architectures are standard practice on AWS, but cross-account ECR access must be tightly controlled. A common pattern is a central "shared services" account that hosts container images, with workload accounts pulling from it. Overly permissive cross-account policies can allow unauthorized accounts to pull -- or worse, push -- images to your repositories.

    Implementation

    # In the source account: set a repository policy allowing cross-account pull
    aws ecr set-repository-policy \
      --repository-name shared/my-app \
      --policy-text '{
        "Version": "2012-10-17",
        "Statement": [
          {
            "Sid": "AllowCrossAccountPull",
            "Effect": "Allow",
            "Principal": {
              "AWS": [
                "arn:aws:iam::444455556666:root",
                "arn:aws:iam::777788889999:root"
              ]
            },
            "Action": [
              "ecr:BatchGetImage",
              "ecr:GetDownloadUrlForLayer",
              "ecr:BatchCheckLayerAvailability"
            ],
            "Condition": {
              "StringEquals": {
                "aws:PrincipalOrgID": "o-yourorgid"
              }
            }
          }
        ]
      }'
    
    # In the workload account: authenticate to the source account registry
    aws ecr get-login-password --region us-east-1 | \
      docker login --username AWS --password-stdin \
      111122223333.dkr.ecr.us-east-1.amazonaws.com

    Use the aws:PrincipalOrgID condition key to restrict cross-account access to accounts within your AWS Organization. Never grant push access cross-account unless absolutely necessary, and never use wildcard principals ("*") in repository policies.

    10. Use Repository Creation Templates for Governance

    Individual developers and CI/CD pipelines frequently create repositories on the fly. Without governance, these repositories inherit default settings -- mutable tags, S3-managed encryption, no lifecycle policies, and no scanning. Repository creation templates let you define security baselines that apply automatically to every new repository matching a prefix pattern.

    Implementation

    # Create a default template that applies to all new repositories
    aws ecr create-repository-creation-template \
      --prefix "" \
      --applied-for PULL_THROUGH_CACHE REPLICATION \
      --description "Default security baseline for all ECR repositories" \
      --image-tag-mutability IMMUTABLE \
      --encryption-configuration '{"encryptionType":"KMS","kmsKey":"arn:aws:kms:us-east-1:111122223333:key/your-key-id"}' \
      --lifecycle-policy '{
        "rules": [{
          "rulePriority": 1,
          "selection": {"tagStatus":"untagged","countType":"sinceImagePushed","countUnit":"days","countNumber":3},
          "action": {"type":"expire"}
        }]
      }'
    
    # List all repository creation templates
    aws ecr describe-repository-creation-templates
    
    # Audit existing repositories against the template settings
    aws ecr describe-repositories \
      --query 'repositories[?imageTagMutability==`MUTABLE`].repositoryName'

    If your template uses KMS encryption or resource tags, you must specify a customRoleArn -- an IAM role that ECR assumes when creating repositories on your behalf. Without this role, repository creation will fail silently.

    11. Use Minimal and Hardened Base Images

    The base image you choose determines the majority of your container's attack surface. A full Ubuntu or Amazon Linux image includes hundreds of packages your application does not need -- each one a potential vulnerability. Security-hardened, minimal base images like distroless, scratch, or Chainguard images dramatically reduce the number of packages and therefore the number of potential CVEs.

    Implementation

    # Example: multi-stage build with distroless base
    # Build stage
    FROM golang:1.22-alpine AS builder
    WORKDIR /app
    COPY . .
    RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server
    
    # Runtime stage -- distroless contains only the runtime, no shell, no package manager
    FROM gcr.io/distroless/static-debian12:nonroot
    COPY --from=builder /app/server /server
    USER 65534:65534
    ENTRYPOINT ["/server"]
    # Scan an image and count vulnerabilities by severity
    aws inspector2 list-finding-aggregations \
      --aggregation-type REPOSITORY \
      --aggregation-request '{
        "repositoryAggregation": {
          "repositories": [{"comparison":"EQUALS","value":"my-app"}]
        }
      }'
    
    # Compare vulnerability counts between a full base and distroless base
    aws ecr describe-image-scan-findings \
      --repository-name my-app \
      --image-id imageTag=v1.0.0-full \
      --query 'imageScanFindings.findingSeverityCounts'
    
    aws ecr describe-image-scan-findings \
      --repository-name my-app \
      --image-id imageTag=v1.0.0-distroless \
      --query 'imageScanFindings.findingSeverityCounts'

    Run containers as non-root users. In your Dockerfile, use USER to set a non-root UID and test that the application works correctly without elevated privileges.

    12. Monitor and Audit with CloudTrail and EventBridge

    Every ECR API call -- PutImage, GetAuthorizationToken, BatchDeleteImage, SetRepositoryPolicy -- is logged in AWS CloudTrail. Monitoring these events lets you detect unauthorized image pushes, policy changes, or unusual pull patterns. Combine CloudTrail logging with EventBridge rules to trigger automated responses.

    Implementation

    # Create an EventBridge rule to alert on image push events
    aws events put-rule \
      --name ecr-image-push-alert \
      --event-pattern '{
        "source": ["aws.ecr"],
        "detail-type": ["ECR Image Action"],
        "detail": {
          "action-type": ["PUSH"],
          "result": ["SUCCESS"]
        }
      }'
    
    # Create a rule to detect repository policy changes
    aws events put-rule \
      --name ecr-policy-change-alert \
      --event-pattern '{
        "source": ["aws.ecr"],
        "detail-type": ["AWS API Call via CloudTrail"],
        "detail": {
          "eventSource": ["ecr.amazonaws.com"],
          "eventName": ["SetRepositoryPolicy","DeleteRepositoryPolicy","PutRegistryPolicy"]
        }
      }'
    
    # Add an SNS target to the rule
    aws events put-targets \
      --rule ecr-policy-change-alert \
      --targets '[{"Id":"sns-target","Arn":"arn:aws:sns:us-east-1:111122223333:security-alerts"}]'

    For high-security environments, create a metric filter in CloudWatch Logs that triggers an alarm when BatchDeleteImage is called outside of lifecycle policy automation, which could indicate an attacker covering their tracks.

    Common Misconfigurations

    These are the most frequently encountered ECR security issues found during security assessments:

    • Mutable image tags in production: Allows image tag overwriting, enabling supply chain attacks. Always enable tag immutability [ECR.2].
    • No image scanning enabled: Repositories without scan-on-push or continuous scanning allow vulnerable images to run undetected [ECR.1].
    • Missing lifecycle policies: Repositories accumulate stale, unpatched images that expand the attack surface and increase costs [ECR.3].
    • Using default S3 encryption instead of KMS: Provides no key rotation control, no granular access policies, and no separate audit trail for key usage.
    • Wildcard principals in repository policies: Using "Principal": "*" grants any AWS account access to pull (or push) images from your repository.
    • No VPC endpoints for private workloads: Image pulls traverse the public internet, exposing traffic to potential interception and adding data transfer costs.
    • Using full OS base images: Images built on ubuntu:latest or amazonlinux:latest contain hundreds of unnecessary packages, each a potential vulnerability.
    • No image signing: Without cryptographic signatures, there is no verification that images were built by your pipeline and have not been tampered with.
    • Pull through cache without repository creation templates: Cached upstream images inherit insecure defaults -- mutable tags, no lifecycle policies, no KMS encryption.
    • Overly permissive cross-account access: Granting push access to workload accounts that should only pull, or not restricting access to your AWS Organization.

    Quick Reference Checklist

    Best Practice Security Hub Control Priority Status
    Enable enhanced image scanning (Inspector) [ECR.1] Critical
    Enable image tag immutability [ECR.2] Critical
    Configure lifecycle policies [ECR.3] High
    Encrypt with customer-managed KMS keys -- High
    Restrict access with repository policies -- High
    Use VPC endpoints for private access -- High
    Sign container images -- High
    Secure pull through cache rules -- Medium
    Implement least-privilege cross-account access -- High
    Use repository creation templates -- Medium
    Use minimal and hardened base images -- High
    Monitor with CloudTrail and EventBridge -- Medium

    Securing Amazon ECR requires a layered approach that spans image supply chain integrity, access control, network isolation, encryption, and continuous monitoring. By implementing these 12 best practices -- starting with the three Security Hub controls [ECR.1], [ECR.2], and [ECR.3] -- you establish a strong security baseline for your container registry that protects every downstream deployment on ECS, EKS, and Lambda. For more container security guidance, see our ECR security card and related guides on ECS security and EKS security.

    Go Deeper: The State of AWS Security 2026

    This article is just the start. Get the full picture with our free whitepaper - 8 chapters covering IAM, S3, VPC, monitoring, agentic AI security, compliance, and a prioritized action plan with 50+ CLI commands.

    ECRContainer RegistryImage ScanningContainer SecurityKMS EncryptionLifecycle PoliciesImage SigningVPC EndpointsSupply Chain SecurityInspector