CloudFront with API Gateway authorization headers
API Gateway supports a built-in CloudFront distribution using edge-optimized endpoints. If you want more control over the CloudFront distribution you will need to create your own behind an API Gateway regional endpoint.
This comes with some small challenges when it comes to Authorization
headers when they need to be forwarded to the API Gateway origin.
There is an AWS knowledge based article that explains how to do this using a cache policy.
This works, but what if you want to disable the cache? The article claims that You can't use an origin request policy to forward the Authorization header.
. If you attempt to create a custom origin policy with the Authorization
header you will get an error as seen below.
There is a built-in Managed-AllViewer
origin request policy that will forward all headers to the origin including the Authorization
header. However, this also forwards the Host
header which will be denied by API Gateway and return a 403 Forbidden
as it will not match the API endpoint.
There are some workarounds to this:
- Use API Gateway custom domain names to pass an expected Host header to API Gateway.
- Use Lambda@Edge to re-write the Host header.
- Use the cache and set a 0 TTL.
1. Use API Gateway custom domains
You can use API Gateway custom domains to match the custom domain used on the CloudFront distribution to avoid the Host header issue. You can then point your DNS entry to the CloudFront distribution rather than the API Gateway custom domain.
-
Create an API Gateway regional endpoint.
-
Create an AWS Certificate Manager (ACM) public certificate in the
us-east-1
region (required for CloudFront). If your API Gateway is not inus-east-1
then also create the same certificate in the API Gateway region e.g. eu-west-1. -
Create an API Gateway custom domain name (regional) using the created ACM certificate.
-
Map the custom domain name to the API Gateway stage.
-
Create a CloudFront distribution using the default endpoint as the origin (without the stage name in the origin path, as this has already been mapped in the custom domain name). Ensure you set the alternate domain name (CNAME) to your custom domain name.
-
Set the cache policy to
CacheDisabled
and the origin request policy toAllViewer
. -
Configure your DNS to point to the new CloudFront distribution.
Now you can make a call to the CloudFront distribution using an Authorizer header.
2. Use Lambda@Edge
Another option is to forward all headers as before using the AllViewer
origin request policy, but instead of using API Gateway custom domain names use Lambda@Edge to re-write the Host header.
-
Create a Lambda function in
us-east-1
usingBasic Lambda@Edge permissions
IAM role template. -
Within the Lambda code re-write the Host header.
def lambda_handler(event, context):
request = event['Records'][0]['cf']['request']
request['headers']['host'] = [{'key': 'host', 'value': '<your-api-id>.execute-api.<aws-region>.amazonaws.com'}]
print('Updated host header successfully')
return request
- Add a CloudFront trigger to the Lambda function for
origin-request
and select the CloudFront distribution you created earlier.
Now you can make a call to the CloudFront distribution using an Authorizer header. Be aware that with this method Lambda is invoked on every request as the cache is disabled. This can add latency and increase costs. In my testing the average function duration for the code sample above was 1ms
. Cold start (Init) duration was around 100ms
.
3. Use the cache and set a 0 TTL
The third option is to create a custom cache policy and set the Minimum TTL
and Default TTL
to 0
. This will essentially disable the cache but forward the Authorization
header.
-
Create a new custom cache policy in CloudFront. Set the following TTL settings:
- Minimum TTL: 0
- Maximum TTL: 1 (cannot be 0, but will not be used unless the origin uses
Cache-Control
headers) - Default TTL: 0
-
Set the cache key headers to include the
Authorization
header.
- Apply the cache policy to the CloudFront distribution by modifying the behavior.
Now you can make a call to the CloudFront distribution using an Authorizer header.