You’re going to write and deploy two CloudFront Functions: one that adds security headers to every response and one that redirects a legacy URL to a new path. By the end of this exercise, your CloudFront distribution will enforce security headers on all responses and automatically redirect /old-path to /new-path—without touching your origin or your application code.
Why It Matters
On Vercel or Netlify, you configure security headers in a vercel.json or _headers file. On AWS, you can use a CloudFront response headers policy (which you set up in CloudFront Headers, CORS, and Security), but that approach is static configuration. A CloudFront Function gives you programmable control over headers—you can add headers conditionally, vary them by path, or include dynamic values. And for redirects, a CloudFront Function replaces what would otherwise be a redirect rule baked into your application code.
If you want AWS’s version of the runtime limits and deployment flow open while you work, keep the CloudFront Functions guide nearby.
This exercise reinforces the CloudFront Functions workflow: write the function, test it, publish it, associate it with a behavior. Once you’ve got this workflow down, you can adapt it for any of the use cases in Edge Function Use Cases.
Your Task
Build and deploy two CloudFront Functions:
security-headers—A viewer response function that adds security headers to every response from your distribution.legacy-redirect—A viewer request function that redirects requests for/old-pathto/new-pathwith a 301 status code.
Use the distribution E1A2B3C4D5E6F7, account 123456789012, and region us-east-1.
Write the Security Headers Function
Write a CloudFront Function that adds these headers to every response:
Strict-Transport-Security:max-age=63072000; includeSubDomains; preloadX-Content-Type-Options:nosniffX-Frame-Options:DENYReferrer-Policy:strict-origin-when-cross-origin
The function should:
- Be named
security-headers - Use the
cloudfront-js-2.0runtime - Trigger on
viewer-responseevents - Preserve any existing response headers (don’t overwrite the entire headers object)
Checkpoint
You have a JavaScript function that takes an event, adds four headers to event.response.headers, and returns the response.
Create and Test the Security Headers Function
Use the AWS CLI to create the function with aws cloudfront create-function. Save the ETag from the response.
Test the function with a sample viewer response event. The test event should include a basic response object with statusCode: 200 and at least one existing header (like content-type).
Verify that:
- The function executes without errors
- The four security headers appear in the output response
- The original
content-typeheader is preserved
Checkpoint
aws cloudfront test-function returns a successful result with all four security headers in the response and the original headers intact.
Write the Legacy Redirect Function
Write a CloudFront Function that:
- Checks if the request URI is
/old-path - If it matches, returns a 301 redirect response with the
Locationheader set to/new-path - If it doesn’t match, passes the request through unchanged
The function should:
- Be named
legacy-redirect - Use the
cloudfront-js-2.0runtime - Trigger on
viewer-requestevents
Checkpoint
You have a JavaScript function that returns a 301 response for /old-path and returns the unmodified request for all other paths.
Create and Test the Legacy Redirect Function
Create the function using the CLI and test it with two different events:
- A request to
/old-path—should return a 301 response withLocation: /new-path - A request to
/about—should return the request unchanged (pass-through)
Checkpoint
Both test cases produce the expected output: a redirect for /old-path and a pass-through for /about.
Publish Both Functions
Publish both functions from DEVELOPMENT to LIVE using aws cloudfront publish-function. Remember that each publish requires the current ETag.
Checkpoint
Both functions are in the LIVE stage. You can verify with aws cloudfront describe-function --name security-headers --stage LIVE --region us-east-1 --output json.
Associate Both Functions with Your Distribution
Retrieve your distribution configuration and update the default cache behavior to include both function associations:
legacy-redirecton theviewer-requesteventsecurity-headerson theviewer-responseevent
Remember: a single behavior can have one function per event type. You’re attaching two different functions to two different events on the same behavior.
After updating, wait for the distribution status to change from InProgress to Deployed.
Checkpoint
aws cloudfront get-distribution-config --id E1A2B3C4D5E6F7 --region us-east-1 --output json shows both function associations in the default cache behavior.
Verify in Production
Test the security headers by making a request to your distribution and inspecting the response headers:
curl -I https://d111111abcdef8.cloudfront.net/Test the redirect:
curl -I https://d111111abcdef8.cloudfront.net/old-pathCheckpoint
- The security headers response includes
Strict-Transport-Security,X-Content-Type-Options,X-Frame-Options, andReferrer-Policy - The
/old-pathrequest returns a301 Moved PermanentlywithLocation: /new-path
Checkpoints Summary
-
security-headersfunction adds four headers to viewer responses -
legacy-redirectfunction returns a 301 for/old-pathand passes through other requests - Both functions pass
test-functionwith expected output - Both functions are published to
LIVE - Both functions are associated with the default behavior on distribution
E1A2B3C4D5E6F7 -
curl -Iconfirms security headers in the response -
curl -I /old-pathconfirms the 301 redirect
Failure Diagnosis
- The function tests pass but production behavior never changes: CloudFront Functions do not affect traffic until you publish them to
LIVEand the distribution finishes deploying the new association. - The redirect works but the headers are missing: The functions are attached to the wrong event types. Redirect logic belongs on
viewer-request; header mutation belongs onviewer-response. - Every path redirects instead of just
/old-path: Your condition is too broad. Re-test the request URI comparison before republishing.
Stretch Goals
Add a
Content-Security-Policyheader. Extend the security headers function with a CSP directive. Start withdefault-src 'self'and adjust based on what your site actually loads.Redirect multiple paths. Extend the redirect function to handle a map of old-to-new paths instead of a single hardcoded path. Keep the function under 10 KB.
Combine both functions into one. You can’t have two CloudFront Functions on the same event type for one behavior. But can you handle both security headers (viewer response) and redirects (viewer request) with a single function if they’re on different events? Hint: you can’t—they require different event types. But it’s worth thinking about to understand the constraint.
When you’re ready, check your work against the Solution: Add a CloudFront Function to Your Distribution.