Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cookies set, but not sent to Cloudfront

I'm attempting to use signed cookies to access private content on AWS Cloudfront.

  • Rails 4.2.1 app running in development on Puma server - http://localhost:3000
  • Using latest Chrome (and can reproduce same in Firefox and Safari)

My app successfully sets the correct cookies required by cloudfront, and each cookie has the correct value. For reference, the three cookies that need to be set are:

  • CloudFront-Policy
  • CloudFront-Signature
  • CloudFront-Key-Pair-Id

I know that the values are correct as if I grab those cookies and perform a curl request using them, it is successful (values replaced with ... for the sake of brevity):

curl -v -b "CloudFront-Signature=...; CloudFront-Policy==...; CloudFront-Key-Pair-Id==...;" http://mydistribution.cloudfront.net/myfile.jpg

The fault

When I use the browser, whilst I can see the cookies have been set in my original request to the server http://localhost:3000/, my requests to Cloudfront urls (for example, in my image tags) do not pass on any of these cookies. This results in

<Error><Code>MissingKey</Code><Message>Missing Key-Pair-Id query parameter or cookie value</Message></Error>

Any ideas why my cookies are not being sent to cloudfront? Advice and support appreciated :)

like image 904
j10io Avatar asked Apr 25 '15 12:04

j10io


People also ask

How do I enable cookies in CloudFront?

If you want to receive cookies at your origin but you don't want CloudFront to cache the Set-Cookie headers in your origin's responses, configure your origin to add a Cache-Control header with a no-cache directive that specifies Set-Cookie as a field name. For example: Cache-Control: no-cache="Set-Cookie" .

Why is CloudFront not caching?

If your CloudFront distribution isn't caching based on the custom values that you set on cache behaviors, then check the origin. Verify whether the origin has any conflicting caching headers.

How do I force CloudFront to refresh?

Right click your distribution. Select "Get Cloudfront invalidation list" Then select "Create" to create a new invalidation list. Select the files to invalidate, and click "Invalidate." Wait 5-15 minutes.

How do I fix miss from CloudFront?

After a request returns the "X-Cache:Miss from CloudFront" response, the browser might serve the same response to subsequent requests because it's stored in the browser cache. To verify if the response is stored in the browser cache, clear the browser cache and make a new request for the same object.


2 Answers

This is normal: each cookie has an associated domain and for each request the browser will only send cookies that match the URL the request is being made for.

Furthermore you cannot set cookies for arbitrary domains - if your application was on example.com then it can set cookies for example.com and any subdomains, but not for other domains (eg other-domain.com)

Therefore if your app is being accessed by the browser as localhost then it can't set cookies sent to foo.cloudfront.net. The signed cookies function in cloudfront is pretty new so I'm not sure what the recommended approach is here, however you can configure cloudfront to pass certain paths through to your app (check the cloudfront documentation on behaviour and origins) at this point the browser thinks it is talking to cloudfront so it will let you set cookies that will be sent in subsequent requests to your cloudfront distribution.

Your app does need to be reachable from cloudfront for this to work though, so I don't think this will work in development.

Alternatively use a CNAME so that your cloudfront distribution and your app are served from the same domain. This will however mean that you can't use the default cloudfront ssl certificate, and unless SNI is acceptable, you'll need to pay extra to use your own certificate.

like image 171
Frederick Cheung Avatar answered Sep 18 '22 16:09

Frederick Cheung


Yes, this is the way we are setting up, using CNAME alias and set the cookies on the base domain, then you will be able to pass your cookie.

Let's put more detail to it in case people want to know what would be the next step is, let's use the above example :-

  1. You are developing on my.fancy.site.mydomain.com
  2. Your Cloudfront CNAME alias is content.mydomain.com
  3. Make sure you set your cloudfront signed cookies to .mydomain.com from your fancy app
  4. From this point on, you are able to pass the cookie for the CF.
  5. One quick way to test if your cookie is set appropriately, try to get your assets URL, and put the url in the browser directly. If the cookie set correctly, you will be able to access the file directly.

If you are using javascript to get the cdn assets, make sure in your JS code, you need to pass withCredentials option, or it won't work. For example, if you are using jQuery, you will need something like the following :-

$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
       withCredentials: true
   }
});

And if the request is successful, you should get a response header from CloudFront with "Access-Control-blah-blah".

Hope it helps people if they search this answer.

like image 33
R.R Avatar answered Sep 18 '22 16:09

R.R