AWS Lambda with CloudFront configuration guide

rimutaka

Max

Posted on August 14, 2024

AWS Lambda with CloudFront configuration guide

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}`,
    },
  },
);
Enter fullscreen mode Exit fullscreen mode

There are two possible downsides to this type of invocation:

  1. you cannot use a custom domain
  2. 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.

Access control setting screenshot

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.

Lambda URL CORS

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.

CloudFront Origins

CloudFront Behaviors

Origin configuration

create origin

  • 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.

Origin Access Control

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:

Lambda access policy

If you go back to your lambda function after running the aws lambda add-permission command, you should see the newly added policy:

Access control policy screenshot

The policy should have your account and distribution IDs:

Access control policy contents

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:

Cloudfront behavior settings

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.

Allowed HTTP methods screen

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

Policy selection

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.

Caching policy disabled

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.

Origin request policy

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:

sample response policy

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

CORS

💖 💪 🙅 🚩
rimutaka
Max

Posted on August 14, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related