Max
Posted on August 14, 2024
This post explores different configuration options for invoking AWS Lambda via CloudFront to demonstrate how different CloudFront and Lambda Function URL settings affect CORS and authorization headers.
Overview
AWS Lambda Functions can be invoked via a public AWS Lambda Function URL with an HTTP call from a browser script, e.g.
const lambdaResponse = await fetch(
"https://mq75dt64puwxk3u6gjw2rhak4m0bcmmi.lambda-url.us-east-1.on.aws",
{
headers: {
Authorization: `Bearer ${token}`,
},
},
);
There are two possible downsides to this type of invocation:
- you cannot use a custom domain
- no server-side caching
Calling your lambdas via CloudFront solves both of these issues.
Configuration complexity
There is quite a bit of configuration to be done upfront to make a Lambda function work with CloudFront:
- Lambda Function URL access control and CORS
- CloudFront origin and behaviors
- CloudFront caching policy
- CloudFront origin request policy
- CloudFront response headers policy
This guide complements the official AWS documentation with examples and shortcuts.
Core concepts
This section explains CloudFront terms and concepts that affect Lambda, CORS and the Authorization header.
General
- CloudFront forwards always forwards uncached HTTP OPTIONS requests to the Lambda URL
- CloudFront can cache OPTIONS responses
- CloudFront can drop or overwrite some of the request and response headers
- Authorization, Host and other headers are used by AWS in communication between CloudFront and Lambda and may conflict with the same headers used by the web client
CORS headers can be added in three different places:
- by the code inside the lambda function
- by AWS if Lambda Function URL CORS were configured
- by CloudFront via Response Headers Policy
Origin access control settings tell CloudFront if it should sign requests sent to the Lambda Function URL.
Signing requests takes over the Authorization header and drops the value sent by the client app.
Caching policy settings of a Behavior tell CloudFront which headers to use as caching keys:
- headers included in the caching key are passed onto the lambda
- you have to include your authorization key to avoid serving one user's response to another user
- even if you include the Authorization header in the key it may be taken over by the AWS signature configured in the Origin access control
- you do not have to have a caching policy for the CORS protocol to work
- AWS recommends CachingDisabled policy for Lambda URLs
Origin request policy settings tell CloudFront which headers to forward to the lambda:
- not all headers are forwarded by default
- you should not forward the Host header (it returns an error at runtime if you do)
- CloudFront may drop or replace some headers
- this policy depends on the options selected in the Caching Policy
- AllViewerExceptHostHeader policy works fine with CORS and is the default choice for Lambda URLs
Response headers policy tells CloudFront what headers to add to the response:
- you can choose None if the lambda function handles the CORS response
- you can choose a suitable managed CORS policy from the list to complement or overwrite the lambda's response
- you can create a custom policy to complement or overwrite the lambda's response
Header quotas set limits to how much data you can put into custom headers:
- Max length of a header value: 1,783 characters
- Max length of all headers: 10,240 characters
Lambda Function URL configuration for CloudFront
Let's assume that you already have a working Lambda function with a configured URL for public access and we need to make it work with CloudFront.
Lambda URL access control config
The following config lets CloudFront access a Lambda function via its URL in the most secure way.
We will add the CloudFront IAM policy to the Lambda at a later stage.
Setting your function URL access control to Auth type: NONE allows anyone, including CloudFront to invoke it.
Lambda URL CORS headers
Enabling CORS headers in Lambda Function URL settings intercepts all HTTP OPTIONS requests sent to the function and returns the configured response.
Disabling CORS headers forwards HTTP OPTIONS requests to the function handler.
CORS headers can be configured in CloudFront's Response Headers Policy.
CloudFront can cache HTTP OPTIONS responses regardless of which of the above strategies of handling CORS you choose.
CloudFront configuration
A Lambda function should be added as an Origin of a CloudFront distribution.
In this example, client-sync lambda origin is linked to /sync.html path. For example, if a client app makes a fetch()
call to https://d9tskged4za87.cloudfront.net/sync.html
the request will be forwarded to client-sync lambda for processing.
Origin configuration
-
origin domain: copy-paste the domain of the Lambda Function URL, e.g.
mq75dt64puwxk3u6gjw2rhak4m0bcmmi.lambda-url.us-east-1.on.aws
- origin path: leave blank
- name: give it an informative name, spaces are OK; it will not be used as an ID
Origin access control affects the use of Authorization header
Create a new Origin Access Policy that can be shared between multiple lambda functions.
Signing CloudFront requests to the lambda function URL also uses the Authorization header which can create a conflict if the web client uses the Authorization header for its authorization.
Do not sign requests
- CloudFront passes the Authorization header from the browser to the lambda
- the lambda must have Auth type: NONE and a public access policy enabled
Sign requests
- Authorization header from the browser is dropped
- CloudFront uses the Authorization header to sign requests to the lambda
- Authorization header is excluded from the lambda's payload
- the lambda can have Auth type: AWS_IAM and no public access
Do not override authorization header
This is a combination of the two previous policies:
- sign if there is no Authorization header coming from the browser
- do not sign if there is one coming from the browser
- the lambda must have Auth type: NONE and a public access policy enabled for this option to work
The Origin Access policy can be edited later from the sidebar under Security / Origin access menu.
Lambda access policy
Copy-paste and run the template generated by the console:
If you go back to your lambda function after running the aws lambda add-permission
command, you should see the newly added policy:
The policy should have your account and distribution IDs:
Behavior configuration
Create a new behavior with the path to the endpoint that invokes the Lambda (1) and the name of origin you created for the lambda earlier (2) as in the following example:
The address of this endpoint would be https://[CF distr ID].cloudfront.net/sync.html
or https://[custom domain]/sync.html
.
You must select an option with the HTTP OPTIONS method for CORS to work.
Caching OPTIONS requests prevents sending repeat OPTIONS requests to the lambda. This option depends on the selection of the caching policy discussed further in this guide.
In the policies section of the form select:
- Cache policy CachingDisabled
- Origin request policy AllViewerExceptHostHeader
-
Response headers policy:
- select None if the Lambda Function URL CORS option was configured, or
- create a new policy (more on this is further in the document), select None for now anyway
The above configuration should be sufficient to correctly process CORS and authorization requests to a lambda function via CloudFront.
CloudFront policies and CORS headers
Caching policies
Caching disabled
AWS recommends disabling caching for Lambda functions because most of the requests are unique and should not be cached.
Some headers, including the Authorization header, are removed by CloudFront if caching is disabled.
Caching enabled with Authorization header
Authorization header gets special treatment from AWS:
- CloudFront does not pass it to lambda functions for GET/HEAD requests unless it is included in the caching policy
- CloudFront forwards it for DELETE, PATCH, POST, and PUT HTTP methods
The above rule is affected by a different setting:
- AWS uses the Authorization header for IAM authentication, so even if you have Auth type: AWS_IAM in the Function URL settings the Authorization header will not reach the lambda no matter what the caching policy says
One workaround for passing Authorization header to lambdas is to:
- disable Lambda Function URL IAM authentication with Auth type: NONE,
- add Authorization header to the caching policy.
If disabling Lambda Function URL IAM authentication is not an option:
- keep Auth type: AWS_IAM in the Function URL settings
- use a custom header to pass the authentication value from your web client to your lambda, e.g.
x-myapp-auth: Bearer some-long-JWT-value
- always add the custom authorization header to the caching policy to prevent responses to one authenticated user served to someone else
Origin request policy
Use AllViewerExceptHostHeader or create a custom policy that excludes the Host header from being forwarded to lambda.
The AllViewer- part of the name of that origin request policy is misleading because CloudFront removes and repurposes some of the headers, e.g. Authorization and many others.
Response headers policy
Use this policy only if you want CloudFront to add CORS and other headers to the response on top or instead of what the lambda returns in its response. For example, this sample policy adds all the necessary CORS headers to let scripts running in your local DEV environment (https://localhost:8080) call the lambda function:
Use one of the AWS-managed CORS policies that add the Access-Control-Allow-Origin: *
header to allow scripts from any domain to access your lambda function.
References
AWS Lambda
CloudFront
- Cache policy headers
- Request and response behavior for custom origins
- Configure CloudFront to forward the Authorization header
CORS
- CORS overview on MDN
- CORS request headers:
- Required CORS response headers:
- Optional CORS response headers:
Posted on August 14, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.