Skip to main content

Overview

The ECR (Elastic Container Registry) Module manages container image repositories for the Artos platform. It creates separate repositories for environment-specific application components and shared third-party services, with configurable lifecycle policies, security scanning, encryption, and cross-account access controls.

Key Features

  • Environment Isolation: Separate repositories per environment (development, staging, production)
  • Automatic Image Cleanup: Lifecycle policies to manage storage costs
  • Security Scanning: Automatic vulnerability scanning on image push
  • Encryption: Support for AES256 and KMS encryption
  • Cross-Account Access: Enable image sharing across AWS accounts
  • Third-Party Image Management: Centralized repositories for shared dependencies

Container Images

The module creates repositories for two types of container images: Environment-Specific images that are isolated per environment, and Third-Party/Shared images that are centralized across environments.

Environment-Specific Images

These repositories are created for each environment (development, staging, production) and contain custom Artos application code.

1. Backend API (artos-postgres-eks-backend)

Repository Name: {environment}/artos-postgres-eks-backend The main application backend API server that handles HTTP requests, business logic, and database interactions. Contains:
  • FastAPI REST API server for core Artos platform logic and routes
  • Database models and migrations
  • Authentication and authorization logic
Typical Images:
development/artos-postgres-eks-backend:latest
development/artos-postgres-eks-backend:v1.2.3
staging/artos-postgres-eks-backend:v1.2.3
production/artos-postgres-eks-backend:v1.2.3

2. Celery Workers (artos-postgres-eks-celery)

Repository Name: {environment}/artos-postgres-eks-celery Asynchronous task workers for background job processing, scheduled tasks, and long-running operations. Contains:
  • Celery worker processes
  • Task definitions and handlers
  • Background job processors
  • Scheduled task runners
  • Queue consumers
Typical Images:
development/artos-postgres-eks-celery:latest
staging/artos-postgres-eks-celery:v1.2.3
production/artos-postgres-eks-celery:v1.2.3
Use Cases:
  • Document generation workflows
  • Document editing workflows

3. Frontend Application (frontend)

Repository Name: {environment}/frontend The user-facing web application frontend built with modern JavaScript frameworks. Contains:
  • frontend UI and functionality for the Artos platform
Typical Images:
development/frontend:latest
development/frontend:feature-new-ui
staging/frontend:v2.1.0
production/frontend:v2.1.0

Third-Party/Shared Images

These repositories are created once (typically in a shared or production account) and used across all environments to avoid duplication and ensure consistency.
Important: Set create_thirdparty_repos = true in only one environment (typically production or a shared services account) to avoid repository name conflicts. Other environments should reference these shared repositories.

4. Redis Cache (thirdparty/redis)

Repository Name: thirdparty/redis Redis container images used for caching, session storage, and message brokering. Purpose:
  • Application caching layer
  • Celery message broker
  • Rate limiting data store
Typical Images:
thirdparty/redis:7.2-alpine
thirdparty/redis:7.0-alpine

5. OnlyOffice Document Server (thirdparty/onlyoffice)

Repository Name: thirdparty/onlyoffice OnlyOffice Document Server for collaborative document editing and viewing. Purpose:
  • Word document editing (DOCX)
  • Real-time collaboration
Typical Images:
thirdparty/onlyoffice:7.5
thirdparty/onlyoffice:7.4

6. LiteLLM Proxy (thirdparty/litellm)

Repository Name: thirdparty/litellm LiteLLM proxy server for unified LLM (Large Language Model) API access. Purpose:
  • Unified interface for multiple LLM providers (OpenAI, Anthropic, etc.)
  • API key management and rotation
  • Request rate limiting and cost tracking
  • Load balancing across LLM endpoints
  • Caching for improved performance
Typical Images:
thirdparty/litellm:latest
thirdparty/litellm:v1.0.0

7. PropelAuth (thirdparty/propelauth)

Repository Name: thirdparty/propelauth PropelAuth authentication and user management service. Purpose:
  • User authentication and authorization
  • SSO (Single Sign-On) integration
  • Multi-factor authentication (MFA)
  • User management and organization features
  • OAuth and SAML support
Typical Images:
thirdparty/propelauth:latest
thirdparty/propelauth:v2.0.0

Image Management Policies

1. Lifecycle Policies

Lifecycle policies automatically delete older images to manage storage costs while retaining recent versions. Note: all max_image_count values are set to 0 to ensure all versions are stored in ECR. How It Works:
  • Triggered when image count exceeds max_image_count
  • Deletes oldest images first (by push timestamp)
  • Applies to both tagged and untagged images
  • Runs automatically (no manual intervention needed)
Policy Behavior:
max_image_countBehavior
null or 0No lifecycle policy (keep all images indefinitely)
1-1000Keep only the specified number of most recent images
Example Lifecycle Policy:
{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep last 10 images",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 10
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}

2. Cross-Account Access Policies

Cross-account policies enable other AWS accounts to pull images from your ECR repositories, useful for multi-account architectures or shared services. Note: default terraform has cross_account_ids set to an empty list. Cross account ids are usually added manually after the terraform is spun up. Policy Configuration:
enable_cross_account_access = true
cross_account_ids = [
  "123456789012",  # Production account
  "234567890123"   # Staging account
]
Granted Permissions:
  • ecr:GetDownloadUrlForLayer - Download image layers
  • ecr:BatchGetImage - Retrieve image metadata
  • ecr:BatchCheckLayerAvailability - Check if layers exist
Example Repository Policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCrossAccountPull",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:root",
          "arn:aws:iam::234567890123:root"
        ]
      },
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability"
      ]
    }
  ]
}
Use Cases:
  • Centralized Image Registry: Production account hosts all images, other accounts pull as needed
  • Multi-Region Deployments: Share images across regions via cross-account replication
  • Shared Services: Development account provides common third-party images to all environments

3. Image Scanning

Automatically scans container images for security vulnerabilities (CVEs) upon push. Configuration:
scan_on_push = true  # Enable automatic scanning (default)
Scanning Process:
  1. Image is pushed to ECR repository
  2. ECR triggers automatic vulnerability scan
  3. Results available in AWS Console or via API within minutes
  4. Findings categorized by severity: CRITICAL, HIGH, MEDIUM, LOW, INFORMATIONAL
Viewing Scan Results:
# Get scan findings for an image
aws ecr describe-image-scan-findings \
    --repository-name production/artos-postgres-eks-backend \
    --image-id imageTag=v1.2.3 \
    --region us-east-1
CI/CD Integration:
# Example GitHub Actions workflow
- name: Scan for vulnerabilities
  run: |
    aws ecr wait image-scan-complete \
      --repository-name ${{ env.REPOSITORY }} \
      --image-id imageTag=${{ env.IMAGE_TAG }}
    
    SCAN_FINDINGS=$(aws ecr describe-image-scan-findings \
      --repository-name ${{ env.REPOSITORY }} \
      --image-id imageTag=${{ env.IMAGE_TAG }} \
      --query 'imageScanFindings.findingSeverityCounts')
    
    # Fail build if critical vulnerabilities found
    if echo $SCAN_FINDINGS | grep -q "CRITICAL"; then
      echo "Critical vulnerabilities found!"
      exit 1
    fi

5. Encryption

All images are encrypted at rest using either AWS-managed or customer-managed encryption keys. Configuration Options: AES256 (Default - AWS-Managed):
encryption_type = "AES256"  # No additional configuration needed
KMS (Customer-Managed Keys):
encryption_type = "KMS"
kms_key_arn     = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"

Module Configuration

Basic Configuration

module "ecr" {
  source = "./modules/ecr"

  environment = "production"

  # Standard security settings
  scan_on_push         = true
  image_tag_mutability = "IMMUTABLE"
  encryption_type      = "AES256"

  # Keep last 10 images
  max_image_count = 10

  # Do not create third-party repos (use shared ones)
  create_thirdparty_repos = false

  tags = {
    Environment = "production"
    ManagedBy   = "terraform"
  }
}

Production Configuration with KMS

module "ecr_production" {
  source = "./modules/ecr"

  environment = "production"

  # Production security settings
  scan_on_push         = true
  image_tag_mutability = "IMMUTABLE"  # Prevent tag overwrites
  encryption_type      = "KMS"
  kms_key_arn          = module.kms.ecr_key_arn

  # Retain more images for rollback capability
  max_image_count = 20

  # Enable cross-account access for disaster recovery
  enable_cross_account_access = true
  cross_account_ids = [
    "123456789012"  # DR account
  ]

  create_thirdparty_repos = false

  tags = {
    Environment = "production"
    Compliance  = "hipaa"
    BackupPlan  = "daily"
  }
}

Shared Services Configuration

# Create third-party repositories in a shared services account
module "ecr_shared" {
  source = "./modules/ecr"

  environment = "shared"

  # Shared repository settings
  scan_on_push         = true
  image_tag_mutability = "MUTABLE"  # Allow updates to shared images
  encryption_type      = "AES256"

  # Keep fewer images for third-party dependencies
  max_image_count = 5

  # CREATE third-party repos in shared account only
  create_thirdparty_repos = true

  # Allow all environment accounts to pull
  enable_cross_account_access = true
  cross_account_ids = [
    "111111111111",  # Development account
    "222222222222",  # Staging account
    "333333333333"   # Production account
  ]

  tags = {
    Environment = "shared"
    Purpose     = "third-party-images"
  }
}

Development Configuration

module "ecr_dev" {
  source = "./modules/ecr"

  environment = "development"

  # Relaxed settings for development
  scan_on_push         = true
  image_tag_mutability = "MUTABLE"   # Allow tag overwrites
  encryption_type      = "AES256"

  # Keep only recent images to minimize costs
  max_image_count = 3

  # Reference shared third-party repos
  create_thirdparty_repos = false

  tags = {
    Environment = "development"
    CostCenter  = "engineering"
  }
}

Repository Naming Convention

The module follows a consistent naming pattern for easy identification and organization: Environment-Specific Repositories:
{environment}/artos-postgres-eks-backend
{environment}/artos-postgres-eks-celery
{environment}/frontend
Third-Party/Shared Repositories:
thirdparty/redis
thirdparty/onlyoffice
thirdparty/litellm
thirdparty/propelauth
Examples:
development/artos-postgres-eks-backend
staging/artos-postgres-eks-celery
production/frontend
thirdparty/redis

Pushing Images to ECR

Authenticate Docker to ECR

# Get authentication token and login
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  123456789012.dkr.ecr.us-east-1.amazonaws.com

Build and Push Application Images

# Build backend image
docker build -t artos-backend:v1.2.3 -f backend/Dockerfile .

# Tag for ECR
docker tag artos-backend:v1.2.3 \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/production/artos-postgres-eks-backend:v1.2.3

# Push to ECR
docker push \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/production/artos-postgres-eks-backend:v1.2.3

# Also push as 'latest'
docker tag artos-backend:v1.2.3 \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/production/artos-postgres-eks-backend:latest

docker push \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/production/artos-postgres-eks-backend:latest

Pull Third-Party Images

# Pull Redis from Docker Hub
docker pull redis:7.2-alpine

# Tag for your ECR
docker tag redis:7.2-alpine \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/thirdparty/redis:7.2-alpine

# Push to your ECR
docker push \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/thirdparty/redis:7.2-alpine

Module Maintenance: This module is compatible with Terraform 1.0+ and AWS Provider 5.x. All repositories are automatically tagged with environment and component metadata for resource tracking and cost allocation.