This post is a collection of examples with different configuration options for invoking AWS Lambda via CloudFront.
It demonstrates how configuration changes affect the lambda function invocations and request/response headers.
Example 1: CORS not required, no authorization headers, no caching
This simple GET request does not require the CORS protocol or authorization:
const response = await fetch("https://d9tskged4za87.cloudfront.net/sync.html");
Function URL configuration:
- Auth type: AWS_IAM
- CORS disabled (irrelevant as no CORS protocol is involved)
CloudFront configuration:
- origin access with signed requests
- CachingDisabled policy
- OPTIONS caching setting is irrelevant since caching is disabled via CachingDisabled policy
- Managed-AllViewerExceptHostHeader request policy
- No response policy
How it works:
- CloudFront replaces the value of Host and passes all other headers onto the lambda
- the lambda function handler is invoked for all HTTP request types
- all headers generated by the lambda function are forwarded back to the client
Request headers
Browser to CloudFront:
GET /sync.html HTTP/2
Host: d9tskged4za87.cloudfront.net
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:129.0) Gecko/20100101 Firefox/129.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br, zstd
Origin: https://localhost:8080
DNT: 1
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Priority: u=0
Pragma: no-cache
Cache-Control: no-cache
Headers in the payload passed to the lambda function:
{
"accept": "*/*",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-US,en;q=0.5",
"cache-control": "no-cache",
"cloudfront-forwarded-proto": "https",
"cloudfront-is-android-viewer": "false",
"cloudfront-is-desktop-viewer": "true",
"cloudfront-is-ios-viewer": "false",
"cloudfront-is-mobile-viewer": "false",
"cloudfront-is-smarttv-viewer": "false",
"cloudfront-is-tablet-viewer": "false",
"cloudfront-viewer-address": "2406:2d40:728d:fa10::c4a:42838",
"cloudfront-viewer-asn": "14593",
"cloudfront-viewer-city": "Auckland",
"cloudfront-viewer-country": "NZ",
"cloudfront-viewer-country-name": "New Zealand",
"cloudfront-viewer-country-region": "AUK",
"cloudfront-viewer-country-region-name": "Auckland",
"cloudfront-viewer-http-version": "2.0",
"cloudfront-viewer-latitude": "-36.85060",
"cloudfront-viewer-longitude": "174.76790",
"cloudfront-viewer-postal-code": "1010",
"cloudfront-viewer-time-zone": "Pacific/Auckland",
"cloudfront-viewer-tls": "TLSv1.3:TLS_AES_128_GCM_SHA256:sessionResumed",
"dnt": "1",
"host": "mq75dt64puwxk3u6gjw2rhak4m0bcmmi.lambda-url.us-east-1.on.aws",
"origin": "https://localhost:8080",
"pragma": "no-cache",
"priority": "u=0",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"user-agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:129.0) Gecko/20100101 Firefox/129.0",
"via": "2.0 03e8784cc6fbcd65ff743e9f537e8e88.cloudfront.net (CloudFront)",
"x-amz-cf-id": "Wtw2gvr0...o3nk-DQ==",
"x-amz-content-sha256": "e3b0c44...852b855",
"x-amz-date": "20240812T024912Z",
"x-amz-security-token": "IQoJb3...yM6wdjMEg==",
"x-amz-source-account": "512295225992",
"x-amz-source-arn": "arn:aws:cloudfront::512295225992:distribution/E3FGXRC3VXQ2IF",
"x-amzn-tls-cipher-suite": "ECDHE-RSA-AES128-GCM-SHA256",
"x-amzn-tls-version": "TLSv1.2",
"x-amzn-trace-id": "Root=1-66b97828-7217f26e68fb64c806f4daf5",
"x-forwarded-for": "2406:2d40:728d:fa10::c4a",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
}
Request headers of interest:
- browser to CloudFront
Host: d9tskged4za87.cloudfront.net
was replaced by CloudFront - CloudFront to Lambda:
host: mq75dt64puwxk3u6gjw2rhak4m0bcmmi.lambda-url.us-east-1.on.aws
-
origin: https://localhost:8080
is the same for both
Response headers
Lambda's response:
{
"statusCode": 200,
"headers": {
"x-foo-header": "bar",
"content-type": "text/html; charset=utf-8"
},
"body": "Hello from client-sync",
"isBase64Encoded": false,
"cookies": []
}
CloudFront to the browser:
HTTP/2 200
content-type: text/html; charset=utf-8
content-length: 22
date: Mon, 12 Aug 2024 02:49:14 GMT
x-amzn-requestid: 28b96338-a3a6-4a6e-aad2-8b7d25a4fe13
x-foo-header: bar
vary: Origin
x-amzn-trace-id: root=1-66b97828-7217f26e68fb64c806f4daf5;parent=717724cd0dc027c2;sampled=0;lineage=a964c7ca:0
x-cache: Miss from cloudfront
via: 1.1 03e8784cc6fbcd65ff743e9f537e8e88.cloudfront.net (CloudFront)
x-amz-cf-pop: LAX3-C3
x-amz-cf-id: Wtw2gvr045gDD6eqIC6s_rDEnugktHpg0YUjmrp2jRuN6PNo3nk-DQ==
X-Firefox-Spdy: h2
Response headers of interest:
-
x-foo-header: bar
custom header was passed from the lambda function to the browser -
x-cache: Miss from cloudfront
CloudFront header is alwaysMiss ...
because the caching is disabled
Example 2: CORS with custom authorization header and no caching
This request requires the CORS protocol, but the authorization is done through a custom header:
const response = await fetch(
"https://d9tskged4za87.cloudfront.net/sync.html",
{
headers: {
"X-Books-Authorization": "dummy-book-auth4",
},
},
);
In Function URL:
- Auth type: AWS_IAM
- CORS enabled
In CloudFront (unchanged):
- origin access with signed requests
- CachingDisabled policy
- OPTIONS caching is disabled
- Managed-AllViewerExceptHostHeader request policy
- No response policy
Flow changes:
- The browser sends the HTTP OPTIONS request first to obtain the CORS headers:
- CORS headers are added by AWS Lambda as part of the lambda handler invocation
- The browser sends a GET request after checking the CORS headers
OPTIONS request/response
CORS-related request headers for HTTP OPTIONS request:
OPTIONS /sync.html HTTP/2
Access-Control-Request-Method: GET
Access-Control-Request-Headers: x-books-authorization
Origin: https://localhost:8080
CloudFront OPTIONS response has four CORS headers generated by AWS Lambda without invoking the lambda function handler:
access-control-allow-origin: https://localhost:8080
access-control-allow-headers: authorization,content-type,x-books-authorization
access-control-allow-methods: GET,POST
access-control-allow-credentials: true
GET request/response
The OPTIONS request is followed by a GET request with a custom X-Books-Authorization header:
GET /sync.html HTTP/2
X-Books-Authorization: dummy-book-auth4
Origin: https://localhost:8080
...
The lambda function handler receives the X-Books-Authorization header inside the GET request payload:
{
"x-books-authorization": "dummy-book-auth4",
...
}
The lambda's response is identical to the previous GET example with no CORS:
{
"statusCode": 200,
"headers": {
"x-foo-header": "bar",
"content-type": "text/html; charset=utf-8"
},
"body": "Hello from client-sync",
"isBase64Encoded": false,
"cookies": []
}
CloudFront GET response has two CORS headers added to the Lambda's response by AWS Lambda (not the handler):
access-control-allow-origin: https://localhost:8080
access-control-allow-credentials: true
Example 3: CORS with Authorization header and caching
This request uses the Authorization header and requires the CORS protocol:
const response = await fetch(
"https://d9tskged4za87.cloudfront.net/sync.html",
{
headers: {
"Authorization": "dummy-auth",
},
},
);
In Function URL:
- Auth type: NONE
- CORS enabled
In CloudFront:
- origin access with unsigned requests
- custom caching policy that includes the Authorization header
- OPTIONS caching is enabled
- Managed-AllViewerExceptHostHeader request policy
- No response policy
Flow changes:
- the Lambda function is public (Auth type: NONE)
- CloudFront no longer uses the Authorization header (no request signing)
- repeat requests with the same value for the Authorization header are served from the CloudFront cache
- repeat OPTIONS requests are served from the CloudFront cache
All the request/response headers are nearly identical to the previous example, except for the common Authorization
header replacing the custom X-Books-Authorization
header.
The Authorization header is passed to the lambda function handler as part of the payload.
OPTIONS request/response:
- identical to the previous example
GET request headers
From browser to CloudFront:
GET /sync.html HTTP/2
Host: d9tskged4za87.cloudfront.net
Authorization: dummy-auth
Origin: https://localhost:8080
...
The Authorization header was added to the lambda handler payload:
{
"authorization": "dummy-auth",
...
}
Caching
Initial OPTIONS/GET requests:
- both OPTIONS and GET return
x-cache: Miss from cloudfront
header - AWS Lambda (not the handler) responds to OPTIONS request
- the lambda handler is invoked for the GET request
Repeat OPTIONS/GET requests with the same Authorization value:
- both return
x-cache: Hit from cloudfront
header - no lambda invocations
Repeat OPTIONS/GET requests with different Authorization values:
- OPTIONS returns
x-cache: Hit from cloudfront
header - GET returns
x-cache: Miss from cloudfront
header - the lambda handler is invoked for the GET request
Top comments (0)