Skip to content
Back to skills

Terraform Aws Lambda Containers

ASecurity

Container-native AWS Lambda deployment patterns with Terraform. Use when deploying Lambda functions from ECR images, setting up ECR repositories with lifecycle policies, configuring VPC-connected Lambdas, or integrating with API Gateway. Covers Docker multi-stage builds optimized for Lambda, X-Ray tracing setup, environment variables and secrets integration, and IAM role configuration. Includes templates for reusable Lambda modules, ECR lifecycle management, and production-ready Dockerfiles.

  • 6 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 6, 2026
ai-agentspythonbashsqldockerawsterraformapidatabasesecurity

Works with

  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 5 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add ArieGoldkin/claude-forge --skill terraform-aws-lambda-containers --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Terraform Aws Lambda Containers?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Terraform Aws Lambda Containers
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ariegoldkin-terraform-aws-lambda-containers/badge)](https://www.skillsdirectory.com/skills/ariegoldkin-terraform-aws-lambda-containers)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: terraform-aws-lambda-containers
description: |
  Container-native AWS Lambda deployment patterns with Terraform. Use when deploying Lambda
  functions from ECR images, setting up ECR repositories with lifecycle policies, configuring
  VPC-connected Lambdas, or integrating with API Gateway. Covers Docker multi-stage builds
  optimized for Lambda, X-Ray tracing setup, environment variables and secrets integration,
  and IAM role configuration. Includes templates for reusable Lambda modules, ECR lifecycle
  management, and production-ready Dockerfiles.
paths:
  - "terraform/**"
  - "*.tf"
  - "Dockerfile*"
  - "**/*lambda*"
  - "**/*ecr*"
---

# Terraform AWS Lambda Containers Skill

Container-native AWS Lambda deployment patterns using Terraform and ECR.

## When to Use

- Deploying Lambda functions from container images
- Setting up ECR repositories with lifecycle policies
- Configuring VPC-connected Lambdas
- Integrating Lambdas with API Gateway
- Building Docker images optimized for Lambda runtime

## Architecture Overview

```
┌─────────────┐   ┌─────────────┐   ┌─────────────┐   ┌─────────────┐
│   Docker    │──▶│    ECR      │──▶│   Lambda    │──▶│ API Gateway │
│   Build     │   │  Registry   │   │  Function   │   │  (Optional) │
└─────────────┘   └─────────────┘   └─────────────┘   └─────────────┘
       │                 │                 │                 │
       ▼                 ▼                 ▼                 ▼
   Multi-stage      Lifecycle         VPC Config        HTTP/REST
   Slim Image        Policies         IAM Role           Routes
```

## Key Concepts

### ECR Repository Setup

Container images are stored in Amazon ECR:

```hcl
resource "aws_ecr_repository" "lambda" {
  name                 = "${var.app_name}-${var.function_name}"
  image_tag_mutability = "MUTABLE"

  image_scanning_configuration {
    scan_on_push = true
  }

  encryption_configuration {
    encryption_type = "AES256"
  }
}
```

**Best Practices**:
- Enable `scan_on_push` for vulnerability detection
- Use lifecycle policies to limit image count
- Immutable tags for production (`IMMUTABLE`)

> See `${CLAUDE_SKILL_DIR}/templates/ecr-repository.tf` for complete configuration

### Lifecycle Policies

Automatically clean up old images:

```hcl
resource "aws_ecr_lifecycle_policy" "lambda" {
  repository = aws_ecr_repository.lambda.name

  policy = jsonencode({
    rules = [
      {
        rulePriority = 1
        description  = "Keep last 10 images"
        selection = {
          tagStatus   = "any"
          countType   = "imageCountMoreThan"
          countNumber = 10
        }
        action = {
          type = "expire"
        }
      }
    ]
  })
}
```

### Lambda from Container Image

Reference ECR image in Lambda:

```hcl
resource "aws_lambda_function" "main" {
  function_name = "${var.app_name}-${var.function_name}-${var.environment}"
  role          = aws_iam_role.lambda.arn
  package_type  = "Image"
  image_uri     = "${aws_ecr_repository.lambda.repository_url}:${var.image_tag}"

  memory_size = var.memory_size
  timeout     = var.timeout

  environment {
    variables = var.environment_variables
  }
}
```

**Key settings**:
- `package_type = "Image"` enables container mode
- `image_uri` points to ECR repository with tag
- Memory: 128MB-10GB
- Timeout: up to 15 minutes

> See `${CLAUDE_SKILL_DIR}/templates/lambda-module.tf` for complete module

### VPC Configuration

Connect Lambda to private resources:

```hcl
resource "aws_lambda_function" "main" {
  # ... other config

  vpc_config {
    subnet_ids         = var.private_subnet_ids
    security_group_ids = [aws_security_group.lambda.id]
  }
}
```

**Requirements**:
- Private subnets with NAT Gateway (for internet access)
- Security group for outbound rules
- VPC execution role permissions

> See `${CLAUDE_SKILL_DIR}/references/vpc-configuration.md` for networking details

### X-Ray Tracing

Enable distributed tracing:

```hcl
resource "aws_lambda_function" "main" {
  tracing_config {
    mode = "Active"  # or "PassThrough"
  }
}
```

**Modes**:
- `Active`: Lambda creates trace segments
- `PassThrough`: Lambda only forwards upstream traces

### Docker Multi-Stage Build

Optimized Dockerfile for Lambda:

```dockerfile
# Stage 1: Build
FROM public.ecr.aws/lambda/python:3.12 AS builder
COPY requirements.txt .
RUN pip install -r requirements.txt -t /opt/python

# Stage 2: Runtime
FROM public.ecr.aws/lambda/python:3.12
COPY --from=builder /opt/python ${LAMBDA_TASK_ROOT}
COPY src/ ${LAMBDA_TASK_ROOT}/
CMD ["app.handler"]
```

**Best Practices**:
- Use AWS base images for compatibility
- Multi-stage builds reduce image size
- Copy only production dependencies
- Set `CMD` to handler location

> See `${CLAUDE_SKILL_DIR}/templates/Dockerfile.lambda` for examples

## Quick Start

### 1. Create ECR Repository

```hcl
module "ecr" {
  source = "./modules/ecr-repository"

  app_name      = "myapp"
  function_name = "api-handler"
  max_images    = 10
}
```

### 2. Build and Push Image

```bash
# Authenticate to ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin ${ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com

# Build image
docker build -t myapp-api-handler .

# Tag for ECR
docker tag myapp-api-handler:latest ${ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/myapp-api-handler:latest

# Push
docker push ${ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/myapp-api-handler:latest
```

### 3. Deploy Lambda

```hcl
module "lambda" {
  source = "./modules/lambda-function"

  app_name      = "myapp"
  function_name = "api-handler"
  environment   = "production"

  ecr_repository_url = module.ecr.repository_url
  image_tag          = "latest"

  memory_size = 512
  timeout     = 30

  environment_variables = {
    DATABASE_URL = "postgresql://..."
    LOG_LEVEL    = "INFO"
  }
}
```

## Common Patterns

### API Gateway Integration

```hcl
resource "aws_apigatewayv2_api" "main" {
  name          = "${var.app_name}-api"
  protocol_type = "HTTP"
}

resource "aws_apigatewayv2_integration" "lambda" {
  api_id             = aws_apigatewayv2_api.main.id
  integration_type   = "AWS_PROXY"
  integration_uri    = aws_lambda_function.main.invoke_arn
  integration_method = "POST"
  payload_format_version = "2.0"
}

resource "aws_apigatewayv2_route" "main" {
  api_id    = aws_apigatewayv2_api.main.id
  route_key = "ANY /{proxy+}"
  target    = "integrations/${aws_apigatewayv2_integration.lambda.id}"
}
```

### Secrets Manager Integration

```hcl
data "aws_secretsmanager_secret_version" "db" {
  secret_id = "myapp/database"
}

resource "aws_lambda_function" "main" {
  environment {
    variables = {
      DATABASE_SECRET_ARN = data.aws_secretsmanager_secret_version.db.arn
    }
  }
}

# Lambda IAM policy for secrets access
resource "aws_iam_role_policy" "secrets" {
  role = aws_iam_role.lambda.id
  policy = jsonencode({
    Statement = [{
      Effect   = "Allow"
      Action   = ["secretsmanager:GetSecretValue"]
      Resource = [data.aws_secretsmanager_secret_version.db.arn]
    }]
  })
}
```

### CloudWatch Logs

```hcl
resource "aws_cloudwatch_log_group" "lambda" {
  name              = "/aws/lambda/${aws_lambda_function.main.function_name}"
  retention_in_days = 30
}
```

### Provisioned Concurrency

Reduce cold starts for critical functions:

```hcl
resource "aws_lambda_alias" "live" {
  name             = "live"
  function_name    = aws_lambda_function.main.function_name
  function_version = aws_lambda_function.main.version
}

resource "aws_lambda_provisioned_concurrency_config" "main" {
  function_name                     = aws_lambda_alias.live.function_name
  provisioned_concurrent_executions = 5
  qualifier                         = aws_lambda_alias.live.name
}
```

## IAM Best Practices

### Minimal Permissions

```hcl
resource "aws_iam_role" "lambda" {
  name = "${var.app_name}-${var.function_name}-role"

  assume_role_policy = jsonencode({
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = {
        Service = "lambda.amazonaws.com"
      }
    }]
  })
}

# Basic execution (CloudWatch Logs)
resource "aws_iam_role_policy_attachment" "basic" {
  role       = aws_iam_role.lambda.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# VPC access (if needed)
resource "aws_iam_role_policy_attachment" "vpc" {
  count      = var.vpc_enabled ? 1 : 0
  role       = aws_iam_role.lambda.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}
```

## Troubleshooting

### Image Pull Errors

```
Error: InvalidParameterValueException: Source image does not exist
```

**Check**:
- ECR repository exists
- Image tag is correct
- Lambda role has `ecr:GetDownloadUrlForLayer` permission

### Cold Start Issues

Container Lambdas have longer cold starts (~1-3s). Mitigate with:
- Provisioned concurrency
- Smaller images (< 500MB)
- Optimize initialization code

### VPC Timeout

```
Task timed out after 30.00 seconds
```

**Check**:
- NAT Gateway in public subnet
- Route table for private subnet → NAT
- Security group allows outbound

## Templates Reference

| Template | Purpose |
|----------|---------|
| `lambda-module.tf` | Reusable Lambda module |
| `ecr-repository.tf` | ECR with lifecycle policies |
| `Dockerfile.lambda` | Multi-stage Lambda build |

## References

- `${CLAUDE_SKILL_DIR}/references/vpc-configuration.md` - VPC networking for Lambda

Files in this skill

  • SKILL.md9.6 KB
  • references/vpc-configuration.md7.9 KB
  • templates/Dockerfile.lambda3.1 KB
  • templates/ecr-repository.tf3.3 KB
  • templates/lambda-module.tf5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.