Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions modules/lambda-edge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Lambda@Edge

This module deploys a Lambda@Edge function (published version) with IAM role for CloudFront association.

### Usage

```tf
module "edge_security_headers" {
source = "github.com/escaletech/terraform-modules/modules/lambda-edge"

lambda_file = "path/to/handler.js"
lambda_edge_role_name = "my-edge-role"
lambda_function_name = "my-edge-headers"

tags = {
Name = "my-edge-headers"
Environment = "production"
}
}
```

### X-Ray tracing and cost

Lambda@Edge runs on every CloudFront request that triggers the associated event. X-Ray charges per trace recorded (~$5 per million after the 100k/month free tier).

| Mode | Default | Behavior | X-Ray cost |
|------|---------|----------|------------|
| `PassThrough` | yes | Propagates trace context; does not create segments | ~zero |
| `Off` | no | Tracing disabled | zero |
| `Active` | no | Creates sampled segments (1 req/s + 5%) | scales with traffic |

**Recommendation:** keep the default `PassThrough` for edge functions (e.g. security headers). Use `Active` only when end-to-end distributed tracing at the edge is required.

```tf
# Explicit opt-in to active tracing (higher X-Ray cost on high-traffic distributions)
lambda_tracing_mode = "Active"

# Fully disable tracing
lambda_tracing_mode = "Off"
```

IAM permissions for X-Ray are attached only when `lambda_tracing_mode = "Active"`.
35 changes: 33 additions & 2 deletions modules/lambda-edge/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ data "archive_file" "lambda_zip" {
resource "aws_iam_role" "lambda_edge_role" {
name = var.lambda_edge_role_name

assume_role_policy = <<EOF
assume_role_policy = <<EOF_ASSUME_ROLE
{
"Version": "2012-10-17",
"Statement": [
Expand All @@ -28,11 +28,35 @@ resource "aws_iam_role" "lambda_edge_role" {
}
]
}
EOF
EOF_ASSUME_ROLE

tags = var.tags
}

resource "aws_iam_role_policy" "lambda_edge_xray" {
count = var.lambda_tracing_mode == "Active" ? 1 : 0

name = "${var.lambda_edge_role_name}-xray"
role = aws_iam_role.lambda_edge_role.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords",
"xray:GetSamplingRules",
"xray:GetSamplingTargets",
"xray:GetSamplingStatisticSummaries"
]
Resource = "*"
}
]
})
}

resource "aws_lambda_function" "edge_security_headers_lambda" {
function_name = var.lambda_function_name
filename = data.archive_file.lambda_zip.output_path
Expand All @@ -42,4 +66,11 @@ resource "aws_lambda_function" "edge_security_headers_lambda" {
source_code_hash = data.archive_file.lambda_zip.output_base64sha256 // Should only update when Lambda code changes
role = aws_iam_role.lambda_edge_role.arn
tags = var.tags

dynamic "tracing_config" {
for_each = var.lambda_tracing_mode == "Off" ? [] : [var.lambda_tracing_mode]
content {
mode = tracing_config.value
}
}
}
11 changes: 11 additions & 0 deletions modules/lambda-edge/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,14 @@ variable "lambda_function_name" {
error_message = "The lambda_function_name is required."
}
}

variable "lambda_tracing_mode" {
type = string
description = "AWS Lambda X-Ray tracing mode. PassThrough (default) propagates trace context without creating segments — recommended for Lambda@Edge to minimize X-Ray cost. Active creates sampled trace segments (1 req/s + 5%). Off disables tracing entirely."
default = "PassThrough"

validation {
condition = contains(["Active", "PassThrough", "Off"], var.lambda_tracing_mode)
error_message = "The lambda_tracing_mode must be Active, PassThrough, or Off."
}
}