• November 24, 2025
  • nitesh taliyan
  • 0
Lambda Edge Deep Dive - Signiance (Nitesh) 1

Transforming Viewer and Origin Requests/Responses Like a Pro

Lambda@Edge is a powerful AWS compute service that allows you to run code closer to your users by executing Lambda functions at AWS edge locations worldwide. Unlike traditional Lambda functions that run in specific AWS regions, Lambda@Edge functions run in response to CloudFront events, enabling you to customize content delivery with minimal latency. In this comprehensive tutorial, you’ll learn how to create, deploy, and test Lambda@Edge functions that modify HTTP requests and responses at different CloudFront event triggers.​

What You’ll Build

By the end of this tutorial, you’ll have created a Lambda@Edge function that:

  • Adds security headers to HTTP responses for enhanced website security
  • Modifies viewer requests to implement custom routing logic
  • Handles origin requests to add authentication tokens
  • Transforms responses before they reach end users

Prerequisites

Before starting this tutorial, ensure you have:

  • An active AWS account with administrative access
  • Basic knowledge of JavaScript (Node.js) or Python
  • Understanding of the HTTP request/response cycle
  • Familiarity with CloudFront distributions
  • An S3 bucket for testing (we’ll create one in this tutorial)

Estimated completion time: 45–60 minutes
Estimated cost: Less than $1 USD (within free tier limits)

Understanding Lambda@Edge Event Triggers

Lambda@Edge can be triggered at four different CloudFront event stages:​

  1. Viewer Request: Triggered when CloudFront receives a request from a viewer (before checking the CloudFront cache)
  2. Origin Request: Triggered when CloudFront forwards a request to the origin (cache miss)
  3. Origin Response: Triggered when CloudFront receives a response from the origin
  4. Viewer Response: Triggered before returning the response to the viewer

Each trigger type serves different use cases, and you can attach multiple functions to the same distribution.

Part 1: Setting Up Your CloudFront Distribution

Step 1: Create an S3 Bucket for Origin Content

  1. Navigate to the S3 console at https://console.aws.amazon.com/s3/
  2. Click Create bucket
  3. Enter a unique bucket name (e.g., lambda-edge-demo-yourname-2025)
  4. Select your preferred AWS Region
  5. Keep Block all public access unchecked (we’ll use CloudFront for access control)
  6. Acknowledge the warning about public access
  7. Click Create bucket
  8. Upload a simple index.html file to your bucket with the following content:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lambda@Edge Demo</title>
</head>
<body>
<h1>Welcome to Lambda@Edge Tutorial</h1>
<p>This content is delivered through CloudFront with Lambda@Edge modifications.</p>
<p id="timestamp"></p>
<script>
document.getElementById('timestamp').textContent =
'Page loaded at: ' + new Date().toLocaleString();
</script>
</body>
</html>

Step 2: Create CloudFront Distribution

  1. Navigate to the CloudFront console at https://console.aws.amazon.com/cloudfront/
  2. Click Create distribution
  3. Under Origin domain, select your S3 bucket from the dropdown
  4. For Origin access, select Origin access control settings (recommended)
  5. Click Create control setting and accept the default settings
  6. Under Default cache behavior:
  • Viewer protocol policy: Redirect HTTP to HTTPS
  • Allowed HTTP methods: GET, HEAD
  • Cache key and origin requests: Cache policy and origin request policy (recommended)

7. Under Settings:

  • Price class: Use all edge locations (best performance)
  • Alternate domain name (CNAME): Leave blank for now
  • Keep other settings as the default

8. Click Create distribution

9. Wait for the distribution status to change from “Deploying” to “Enabled” (this takes 5–10 minutes)

10. Copy the S3 bucket policy that CloudFront provides and update your S3 bucket permissions

Part 2: Creating Your First Lambda@Edge Function

Step 3: Create Lambda Function in us-east-1

Note: Lambda@Edge functions MUST be created in the us-east-1 (N. Virginia) region.​

  1. Navigate to the Lambda console at https://console.aws.amazon.com/lambda/
  2. Ensure you’re in the US East (N. Virginia) region (check the top-right corner)
  3. Click Create function
  4. Select Use a blueprint
  5. In the search box, type cloudfront to filter CloudFront blueprints
  6. Select cloudfront-modify-response-header blueprint
  7. Configure the basic information:
  • Function name: AddSecurityHeadersEdge
  • Execution role: Create a new role from AWS policy templates
  • Role name: lambda-edge-security-headers-role
  • Policy templates: Select Basic Edge Lambda permissions​

8. Click Create function

9. In the Deploy to Lambda@Edge popup that appears, click Cancel (we’ll configure this later)

Step 4: Update Function Code

Replace the default code with the following enhanced security headers implementation:

'use strict';

export const handler = async (event, context) => {
// Get contents of response
const response = event.Records[0].cf.response;
const headers = response.headers;

// Set comprehensive security headers
headers['strict-transport-security'] = [{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubdomains; preload'
}];

headers['content-security-policy'] = [{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
}];

headers['x-content-type-options'] = [{
key: 'X-Content-Type-Options',
value: 'nosniff'
}];

headers['x-frame-options'] = [{
key: 'X-Frame-Options',
value: 'DENY'
}];

headers['x-xss-protection'] = [{
key: 'X-XSS-Protection',
value: '1; mode=block'
}];

headers['referrer-policy'] = [{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin'
}];

// Add custom header to track Lambda@Edge execution
headers['x-lambda-edge-modified'] = [{
key: 'X-Lambda-Edge-Modified',
value: 'true'
}];

return response;
};

Code Explanation:

  • We’re modifying the origin response event, which fires when CloudFront receives content from the origin
  • Each security header is added to the response headers object
  • The function returns the modified response
  • Headers improve security by preventing XSS attacks, clickjacking, and enforcing HTTPS

10. Click Deploy to save your changes

11. Wait for the “Successfully updated function” message

Step 5: Publish Function Version

Lambda@Edge requires a numbered version (not $LATEST).​

  1. Click Actions → Publish new version
  2. Enter description: Initial version with security headers
  3. Click Publish
  4. Note the function version ARN (you’ll see it changes to include :1 at the end)

Part 3: Deploying to Lambda@Edge

Step 6: Add CloudFront Trigger

  1. On your Lambda function page, scroll to the Function overview section
  2. Click Add trigger
  3. In the trigger configuration:
  • Select a trigger: CloudFront
  • Deploy to Lambda@Edge: Click the checkbox to confirm
  • Distribution: Select your CloudFront distribution from the dropdown
  • CloudFront event: Select Origin response​
  • Cache behavior: Default (*)
  • Check I acknowledge that the execution role…

4. Click Deploy

5. Confirm the deployment in the popup (this will replicate your function globally)

Wait Time: The function replication takes 5–15 minutes. CloudFront needs to deploy the updated configuration to all edge locations worldwide.​

6. Go back to your CloudFront distribution

7. You’ll see the status changed to “Deploying”

8. Wait until it shows the last modified timestamp

Part 4: Testing Your Lambda@Edge Function

Step 7: Verify Function Execution

  1. Copy your CloudFront distribution domain name (e.g., d1234567890abc.cloudfront.net)
  2. Open the URL in your browser
  3. You should see your index.html content
  4. Open Browser Developer Tools (F12)
  5. Go to the Network tab
  6. Refresh the page
  7. Click on the HTML document request
  8. Navigate to the Headers section
  9. Scroll to Response Headers

Expected Headers to Verify:​

  • strict-transport-security: max-age=63072000; includeSubdomains; preload
  • content-security-policy: default-src ‘self’…
  • x-content-type-options: nosniff
  • x-frame-options: DENY
  • x-xss-protection: 1; mode=block
  • referrer-policy: strict-origin-when-cross-origin
  • x-lambda-edge-modified: true

Step 8: Test from Different Locations (Optional)

Use online tools to test from different geographic locations:

This confirms your Lambda@Edge function runs at edge locations globally.

Part 5: Advanced Modifications, Viewer Request Function

Step 9: Create a URL Rewrite Function

Let’s create a second function that modifies viewer requests to implement custom routing.

  1. Return to Lambda console (us-east-1)
  2. Create a new function:
  • Function name: URLRewriteEdge
  • Runtime: Node.js 20.x
  • Execution role: Use existing role lambda-edge-security-headers-role

3. Add the following code:

'use strict';

export const handler = async (event, context) => {
const request = event.Records[0].cf.request;
const uri = request.uri;

// Rewrite /blog to /blog/index.html
if (uri.endsWith('/blog')) {
request.uri = '/blog/index.html';
}

// Add trailing slash if missing and no file extension
else if (!uri.includes('.') && !uri.endsWith('/')) {
request.uri = uri + '/';
}

// Default document handling
if (uri.endsWith('/')) {
request.uri += 'index.html';
}

// Add custom header to track request modification
request.headers['x-rewrite-applied'] = [{
key: 'X-Rewrite-Applied',
value: 'true'
}];

console.log(`Original URI: ${uri}, Modified URI: ${request.uri}`);

return request;
};

4. Deploy and publish Version 1

Get Nitesh Taliyan’s stories in your inbox

Join Medium for free to get updates from this writer.Subscribe

5. Add CloudFront trigger:

  • CloudFront event: Viewer request
  • Use the same distribution

6. Wait for deployment (5–15 minutes)

Part 6: Origin Request Modification

Step 10: Add Authentication Headers

Create a function that adds custom headers to origin requests:

'use strict';

export const handler = async (event, context) => {
const request = event.Records[0].cf.request;

// Add custom origin headers
request.headers['x-custom-origin-header'] = [{
key: 'X-Custom-Origin-Header',
value: 'lambda-edge-origin-request'
}];

// Add timestamp
request.headers['x-request-timestamp'] = [{
key: 'X-Request-Timestamp',
value: new Date().toISOString()
}];

// You could add authentication tokens here
// request.headers['authorization'] = [{
// key: 'Authorization',
// value: 'Bearer YOUR-TOKEN'
// }];

return request;
};

Deploy as Origin request trigger.

Monitoring and Debugging

Step 11: CloudWatch Logs

  1. Navigate to the CloudWatch console
  2. Go to Logs → Log groups
  3. Look for log groups matching: /aws/lambda/us-east-1.{FunctionName}
  4. Note: Logs appear in the region closest to where the function executed
  5. Click into a log group to see execution details
  6. Each invocation shows:
  • Request ID
  • Duration
  • Memory used
  • Any console.log() output

Step 12: CloudWatch Metrics

  1. In your Lambda function, click the Monitor tab
  2. View metrics:
  • Invocations
  • Duration
  • Error count
  • Throttles

Testing Different Scenarios

Test Case 1: Security Headers Validation

Command:

curl -I https://your-distribution.cloudfront.net/

Expected Output:

HTTP/2 200
strict-transport-security: max-age=63072000; includeSubdomains; preload
x-lambda-edge-modified: true
content-security-policy: default-src 'self'...

Test Case 2: URL Rewrite Testing

Command:

curl -I https://your-distribution.cloudfront.net/blog

Should internally rewrite to /blog/index.html

Test Case 3: Edge Location Verification

Check which edge location served your request:

  • x-cache: Shows HIT or MISS from CloudFront
  • x-amz-cf-pop: Shows the edge location code (e.g., IAD89-P2)

Performance Considerations

Function Execution Limits​

Lambda@Edge has specific limitations:

  • Viewer request/response: 128 MB memory, 5-second timeout
  • Origin request/response: 128 MB memory, 30-second timeout
  • Maximum response body size: 1 MB
  • No environment variables support
  • No VPC access

Best Practices

  1. Keep functions lightweight: Minimize dependencies and code size
  2. Use appropriate triggers: Viewer request for routing, origin response for headers
  3. Avoid heavy computations: Edge functions should execute quickly
  4. Cache responses when possible: Reduce function invocations
  5. Monitor costs: Each invocation is billed​

Cost Analysis

Pricing Breakdown (as of November 2025)

Lambda@Edge Costs:

  • Requests: $0.60 per 1 million requests
  • Duration: $0.00005001 per GB-second

Example Monthly Cost:

  • 1 million requests
  • Average duration: 50ms
  • Memory: 128 MB

Calculation:

Requests: 1,000,000 × $0.60/1M = $0.60
Duration: 1,000,000 × 0.05s × 0.125GB × $0.00005001 = $0.31
Total: ~$0.91/month

CloudFront Costs:

  • Data transfer and HTTP requests apply separately
  • First 10 TB: $0.085 per GB (varies by region)

Cost Optimization Tips:

  • Use CloudFront caching aggressively to reduce function invocations
  • Monitor and optimize function execution time
  • Consider CloudFront Functions for simpler use cases (cheaper alternative)

Cleanup Resources

Step 13: Remove Lambda@Edge Associations

  1. Go to CloudFront distribution
  2. Select Behaviors tab
  3. Edit default behavior
  4. Remove all Lambda@Edge function associations
  5. Save changes
  6. Wait for deployment
  7. Delete Lambda functions (must wait until all replicas are removed — can take several hours)
  8. Disable and delete the CloudFront distribution
  9. Empty and delete the S3 bucket

Troubleshooting Common Issues

Issue 1: Function Not Executing

Symptoms: Headers not appearing in responses

Solutions:

  • Verify function is published (not $LATEST version)
  • Check the CloudFront distribution status is “Deployed”
  • Wait for full replication time (15+ minutes)
  • Clear browser cache and test in incognito mode
  • Check CloudWatch logs for errors

Issue 2: “The function execution role must be assumable by edgelambda.amazonaws.com”

Solution:
Ensure your Lambda execution role has this trust policy:

{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"edgelambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}]
}

Issue 3: Response Size Limit Exceeded

Error: “The Lambda@Edge response size exceeded the maximum allowed size”

Solution:

  • Origin response body limit: 1 MB
  • Ensure you’re not adding large headers
  • Compress response bodies if needed

Conclusion

You’ve successfully created and deployed three Lambda@Edge functions that modify CloudFront requests and responses at different event triggers. You’ve learned how to:​

  • Set up CloudFront distributions with S3 origins
  • Create Lambda@Edge functions in us-east-1
  • Deploy functions to global edge locations
  • Modify viewer and origin requests/responses
  • Monitor function execution through CloudWatch
  • Implement security headers for enhanced website protection
  • Test and validate edge function behavior

Lambda@Edge provides powerful capabilities to customize content delivery with minimal latency, enabling sophisticated edge computing scenarios. The functions you’ve built demonstrate practical use cases for security, routing, and request modification that can be applied to production workloads.​

Key Takeaways:

  • Always create Lambda@Edge functions in us-east-1 region
  • Publish numbered versions before deployment
  • Allow adequate time for global replication
  • Monitor costs and optimize function execution time
  • Use appropriate event triggers for different use cases

Leave a Reply

Your email address will not be published. Required fields are marked *