Option 1: Lambda@Edge for CSP
To implement this Content Security Policy (CSP) using a Lambda@Edge function, you will use the Viewer Response event. This allows the function to intercept the response from S3 or the cache and inject the security header before it reaches the user's browser.
Lambda@Edge Code (Node.js 20.x or 22.x)
'use strict';
exports.handler = async (event, context) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
// Define your CSP string
const cspValue = "default-src 'self'; " +
"script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; " +
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " +
"img-src 'self' https: data:; " +
"font-src 'self' https://fonts.gstatic.com; " +
"connect-src 'self'; " +
"object-src 'none'; " +
"frame-ancestors 'none'; " +
"upgrade-insecure-requests;";
// Set the Content-Security-Policy header
headers['content-security-policy'] = [{
key: 'Content-Security-Policy',
value: cspValue
}];
// Recommended: Add other security headers while you are at it
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' }];
return response;
};
Important Implementation Steps for 2026
-
1
Region: You must create this Lambda function in the us-east-1 (N. Virginia) region. This is a requirement for all Lambda@Edge functions, regardless of where your users are located.
-
2
Execution Role: Ensure the Lambda's IAM role has a trust relationship that allows both lambda.amazonaws.com and edgelambda.amazonaws.com to assume the role.
-
3
Deployment:
- Click Actions > Deploy to Lambda@Edge in the Lambda console.
- Select your CloudFront distribution.
- Select the CloudFront Event: Set this to Viewer Response.
Note on Performance
For simple header manipulation like this, CloudFront Functions (which use a restricted JavaScript environment) are usually faster and cheaper than Lambda@Edge. However, Lambda@Edge is required if you plan to add more complex logic or body manipulation later.
Why this CSP works for your setup
https://cdn.tailwindcss.com
Allows the Tailwind play script to run.
'unsafe-inline'
Required for Tailwind and many Google Font implementations to inject styles/scripts directly into the HTML.
upgrade-insecure-requests
Automatically converts any http links in your code to https.
Option 2: CloudFront Functions (Recommended and Implemented)
Here is how to implement the CSP without incurring costs, assuming your traffic fits within the AWS "Always Free" limits.
This is the best method because it inserts the real HTTP header, supporting all CSP directives including frame-ancestors.
Create the Function:
- Go to the CloudFront Console > Functions (on the left sidebar).
- Click Create function.
- Name it (e.g., Add-CSP-Header) and select cloudfront-js-2.0.
Paste this Code:
async function handler(event) {
var response = event.response;
var headers = response.headers;
// Set the CSP header
headers['content-security-policy'] = { value:
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; " +
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " +
"img-src 'self' https: data:; " +
"font-src 'self' https://fonts.gstatic.com; " +
"connect-src 'self'; " +
"object-src 'none'; " +
"frame-ancestors 'none'; " +
"upgrade-insecure-requests;"
};
// Recommended security headers (optional but free to add)
headers['x-content-type-options'] = { value: 'nosniff' };
headers['x-frame-options'] = { value: 'DENY' };
headers['x-xss-protection'] = { value: '1; mode=block' };
return response;
}
Publish & Associate:
- Click Publish tab > Publish function.
- Scroll down to Associated distributions.
- Select your distribution.
- Event Type: Choose Viewer Response.
- Click Associate.
Option 3: HTML Meta Tag (Zero Config)
If you cannot use CloudFront Functions, you can add the CSP directly into your index.html file.
Warning:
The frame-ancestors directive is not supported in a <meta> tag. Browsers will ignore it.
Add this inside the <head> section of your index.html:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' https: data:; font-src 'self' https://fonts.gstatic.com; connect-src 'self'; object-src 'none'; upgrade-insecure-requests;">