2
votes

I am building a serverless app with my SPA hosted on S3 and my APIs on lambda front ended by API gateway. Pretty standard stuff. Now I want my cloudfront distribution to sit in front of S3 and API gateway so that they are on same domain so as to prevent a CORS preflight request from my SPA.

The simplest way to turn cloudfront into non-caching mode I believe is to forward all headers. Unfortunately when I do this by setting the behavior I start getting cloudfront error 403. I am being forced to send cache control headers ( from my lambda 'Cache-Control': 'no-cache, no-store, must-revalidate') to prevent caching.

Request to API Gateway through cloudfront:

GET - https://dev.b*******e.in/dev/b******e/
:authority:dev.b******e.in
:method:GET
:path:/dev/b******e/
:scheme:https
accept:application/json, text/plain, */*
accept-encoding:gzip, deflate, sdch, br
accept-language:en-US,en;q=0.8
authorization:Bearer eyJmYWNlYm9vayI6eyJhY2Nlc3NfdG9rZW4iOiJFQUFZWGhyd1ZoTnNCQUlmOE5BUWU2ZnpwT2xDd2dUVVpBR1k0VmJZWkFMV0R4ekdYcEttek9NR0paQlNIdzdTeU5oRTloMTY3Nmh3bEZ4d2NpQ1laQnhDQ1IwUWZMWkFmVU1UMTRXOUxME1vWkQiLCJ0b2tlbl90eXBlIjoiYmVhcmVyIiwiZXhwaXJlc19pbiI6IjUxODM5NjcifX0=
cache-control:no-cache
dnt:1
pragma:no-cache
referer:https://dev.b******e.in/b***
user-agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36

Response - Status Code:403 
Response headers:
content-length:551
content-type:text/html
date:Fri, 21 Apr 2017 02:54:23 GMT
server:CloudFront
status:403
via:1.1 3336340a46390eb94ce8a4b00e4863fc.cloudfront.net (CloudFront), 1.1 efe8f585d51dfd5d8d354f74f0385a50.cloudfront.net (CloudFront), 1.1 84760d59a7d324aa7adc2bf9d8f7fd4b.cloudfront.net (CloudFront)
x-amz-cf-id:npw8LPJPvy1Ti_709BvUAHpZOdmOe1wsxm1jO7WdLACyzFESFGtMnQ==
x-cache:Error from cloudfront

Response Body:`

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Bad request.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: 7BVUPh3HiZZGVKLWN9tMEz31gHzq762iPGHHW1fg2I7uNa87205P_Q==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>

`

How is everyone solving this problem? Below is my distribution setting. enter image description here

My behavior setting (This does not work): enter image description here

My behavior setting (This WORKS): enter image description here

2
Did you set the CNAME on the CloudFront distribution?Bram
Yeah. I did add CNAME to the distribution.Prabhat
Did you receive 403 on the request to API GW API call? Or s3 call? What was in the response body?Balaji
Received 403 from cloudfront. Call did not reach API gateway.Prabhat
What was the error message in the response body? Providing more details about the request and response will help us understand/investigate better.Balaji

2 Answers

3
votes

What has been killing me was the "Host" header. when you forward all the headers,"Host" header also gets forwarded to API gateway from cloudfront and it causes API gateway to fail. Check this link https://docs.aws.amazon.com/apigateway/api-reference/making-http-requests/ . Looks like the only solution to this currently is to whitelist the headers that you want, and send the cache-control headers from your lambda function.

1
votes

I know my way is kinda hack but works on my side. Inspired by your finding that the "Host" header break API GW, I modify the request object using a Lambda@edge function to change the host header to API Gateway's host name. Lambda@edge is lambda function that can be triggered by CloudFront before it sends origin requests.