crazyCoder
crazyCoder

Reputation: 1582

How to use CloudFront signed cookies in the browser?

So I have a private CDN (can't access data through S3, only by signed URL & cookies) using CloudFront that holds some files for a web application.

One of the pages on my site displays an image whose source lives on the cdn.

<img src="cdn.example.com/images/file.jpg">

Now when I generate a signed URL on the server I can just pass it to the client and set it as source...Easy

But when I try to do the same thing using signed cookies I run into 2 problems:

  1. After generating the signed cookies server-side, I set them using res.cookie but I'm not sure how to find them in response on the client side.
  2. In the event of actually getting the cookie on the client side (in angular/javascript), how to I "set" it so that when the browser tries to grab the image in the above mentioned html it allows access?

I'm using node, express, and cookie-parser. I'm fairly new to this stuff so any help is appreciated

Upvotes: 12

Views: 16282

Answers (2)

Click Ahead
Click Ahead

Reputation: 2852

Have you checked that the domain for the cookie is the same or a subdomain of the CloudFront CDN?

The cookie will be included in the request to the CloudFront distribution only if it is coming from a related domain. For example, if you are testing locally using "localhost" that won't work as the cookie domain is "localhost" but the signed cookie domain is "cdn.example.com".

To ensure that the domain is correct:

  1. Set up a CNAME for the CloudFront Distribution e.g. http://cdn.example.com

  2. Make sure the signed cookie has the correct domain e.g. domain:'*.example.com' will match against the domain.

There's a good article here: https://www.spacevatican.org/2015/5/1/using-cloudfront-signed-cookies/

There's also a good node module for creating signed cookies: https://github.com/jasonsims/aws-cloudfront-sign

Using this module you would do something like:

const options = {
    keypairId: YOUR_ACCESS_ID,
    privateKeyPath: PATH_TO_PEM_FILE
};

const signedCookies = cf.getSignedCookies("http://cdn.example.com/*", options);

for (const cookieId in signedCookies) {
    res.cookie(cookieId, signedCookies[cookieId], {domain: ".example.com"});
}

Note the way I set the domain. If not explicitly set it will default to the one that made the request, which is probably not what you want.

Last thing, to test this locally, I set up port-forwarding on my home network and created a CNAME in GoDaddy to point to my home IP e.g. "test.example.com". I then used "http://test.example.com" instead of "http://localhost". This created a cookie with the subdomain "test.example.com". Finally, I created another CNAME in GoDaddy called "cdn.example.com", pointing it to the CloudFront URL. I used the wildcard domain in my signed cookie, ".example.com" and because I now have the signed cookie on the same domain "example.com" it's passed to CloudFront and boom we have liftoff!

Upvotes: 15

darbelaez
darbelaez

Reputation: 93

For those trying to access a protected resource in CloudFront from a different domain you can not set the cookies cross domain so you're limited to using Signed URLs instead. However you can use javascript on the CloudFront site to use the parameters in the Signed URL to create a Signed Cookie directly in CloudFront. I put together a simple JS script that does just that.

aws-signed-cookie-from-signed-url.js

  • build signed url in www.mysite.com that points to CloudFront url www.cloudfronturl.com/sample/index.html
  • included the JS in the CloudFront resource "sample/index.html"
  • upon the user using the signed URL, index.html will create the SignedCookie which will allow all additional navigation within www.cloudfronturl.com/sample to work based on the cookie

Upvotes: 6

Related Questions