Showing posts with label amazon-cloudfront. Show all posts
Showing posts with label amazon-cloudfront. Show all posts

Thursday, July 19, 2018

Issues generating CloudFront signed URLs—always Access Denied

Leave a Comment

I’m having issues generating signed URLs with CloudFront. Whatever I try, I just get an “Access Denied” response.

I’ve created a distribution in CloudFront, and a CloudFront key pair ID. I’ve downloaded the private and public keys for that key pair ID.

In a simple PHP script, I’m trying the following:

use Aws\CloudFront\CloudFrontClient;  $cloudfront = new CloudFrontClient([     'credentials' => [         'key' => '[redacted]', // Access key ID of IAM user with Administrator policy         'secret' => '[redacted]', // Secret access key of same IAM user     ],     'debug' => true,     'region' => 'eu-west-1',     'version' => 'latest', ]);  $expires = strtotime('+6 hours');  $resource = 'https://[redacted].cloudfront.net/mp4/bunny-trailer.mp4';  $url = $cloudfront->getSignedUrl([     'url' => $resource,     'policy' => json_encode([         'Statement' => [             [                 'Resource' => $resource,                 'Condition' => [                     'DateLessThan' => [                         'AWS:EpochTime' => $expires,                     ],                 ],             ],         ],     ]),     'expires' => $expires,     'key_pair_id' => '[redacted]', // Access key ID of CloudFront key pair     'private_key' => '[redacted]', // Relative path to pk-[redacted].pem file ]); 

But when visiting the generated URL, it just always gives me an error in the browser with a code of “AccessDenied”.

What am I doing wrong?

1 Answers

Answers 1

Discovered what the issue was. The objects in my S3 bucket weren’t publicly-accessible, and I hadn’t added an Origin Access Identity, so CloudFront couldn’t pull the objects from my origin (my S3 bucket) to cache them.

As soon as I added an Origin Access Identity and added it to my S3 bucket’s policy, my objects immediately became accessible through my CloudFront distribution via signed URLs.

Relevant documentation: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#private-content-creating-oai

Read More

Tuesday, July 17, 2018

CloudFront rate limit rule doesn't work

Leave a Comment

I have a CloudFront distribution for an EC2 HTTP server. I created a rate limit for my CloudFront distribution using WAF. In theory no IP address should be able to send more than 2,000 requests in any 5 minute period. But this just doesn't seem to work. I fired off 10,000 concurrent requests from my laptop (using a Go program) in <1 minute and all of them got through. I know they are reaching the EC2 origin because my HTTP server keeps a counter for requests.

Strangely, the WAF dashboard even recognizes that traffic exceeded the 5 minute limit:

enter image description here

Yet no IP blocking took place: enter image description here

And my EC2 server registered all 10,000 hits.

Am I missing some configuration subtlety? Or is there meant to be a long delay between when CloudFront registers the traffic spike and when it implements the IP block?

EDIT: A config picture: enter image description here

0 Answers

Read More

Sunday, April 30, 2017

Why is my s3 hosted website that I set up SSL for via cloudfront only working sporadically?

Leave a Comment

So I have a static website hosted on s3. I set it up to work with AWS certificate manager, route 53, and cloud front so that the site can be accessed with https.

It seems to be sort of working after a lot of fiddling but it then breaks super weirdly.

For example I can go to the following no problem:

www.myurl.com https://www.myurl.com/ https://myurl.com/ http://myurl.com/ 

Great! But then I click a link on this homepage to take me to another page named login.html but this ONLY works for a few of the above links. For example if I go to https://myurl.com and click the link I successfully navigate to https://myurl.com/login.html.

However if I go to https://www.myurl.com/ and click the same link it just keeps loading and never brings up the page.

There are some other weird things going on with other pages but I imagine they are related to this issue and I can't figure it out at all. Why is it working but only sort of and sporadically and only with certain url structures?

Edit: So the login.html started actually loading from https://www.myurl.com when the button was clicked but the display of the login.html is all fucked up and looks all over the place/messed up. Still works fine from https://myurl.com though.

Another clue: I just realized when i go to my site via the cloud front url/domain it is all messed up layout wise as well - interesting...

Update: I messed around with a few things - seems I fixed some of the linking issues and the remaining problem is almost certainly to do with angularJS and its interactions with cloud front. The following error message is in my console and I suspect it may be a clue as to the problem.

angular.min.js:107 ReferenceError: people is not defined     at eval (eval at <anonymous> (jquery.js:2), <anonymous>:4:29)     at eval (<anonymous>)     at jquery.js:2     at Function.globalEval (jquery.js:2)     at m.fn.init.domManip (jquery.js:3)     at m.fn.init.after (jquery.js:3)     at b (angular.min.js:188)     at Object.enter (angular.min.js:189)     at angular.min.js:283     at angular.min.js:54 

1 Answers

Answers 1

It seems like your issue is directly tied to the explicit www prefix in your domain, and is something you can reproduce easily.

To me your problem is coming from the fact there is a restriction/csp policy over your api or another ressource (seems like the people is somethings that is fetched) and only the domaine without www is allowed to access it, thus the error only being present on the www version.

You could try to find the blocking rule, but my advice would be instead to "get rid" of the www domain. The general convention is that you don't want your users to browse your website on different urls, rather put a redirect from the prefixed domain to the non-prefixed one. This way users will always use the same links, it prevent duplication of content which is bad for SEO and is less painful for SSL certificates.

There is a good article about how to put a redirect in place with a static S3 website, basically you need to create a new bucket with the same name of your www origin, go the bucket Properties, Static Website Hosting section and redirect all requests to another hostname. The article explains more deeply how to configure it for https domains that I won't expand here, but I invite you to consult it.

Read More

Sunday, March 27, 2016

How to provision a CloudFront distribution with an ACM Certificate using Cloud Formation

Leave a Comment
This summary is not available. Please click here to view the post.
Read More

Monday, March 14, 2016

Restrict cloudfront signed url (GET Request) to be accessed by my mobile application

Leave a Comment

I am trying to serve video files using Amazon cloudfront to my app users using signed urls. I have created the signed urls using the documentation and it works perfectly well. The url generated has the signature, expires and keypair_id.

issues

What I am trying to achieve is to serve the video files to the user only when the request is coming in from my particular mobile application. I am looking for a solution to authorize the request (on a signed url) on the cloudfront side.

So if a user tries to access the signed url using our mobile app, we would want to serve the content but if the url is accessed from either web or any other mobile client we would like to raise an authorization error or 404.

I have went through the documentation and a couple blogs looking to achieve the above and everyone has pointed me in the direction to use signed urls which I already am. But the urls are still accessible directly via the browser.

Also I would like to know, why does a signed url has signature as a GET parameter, as if the signature is removed the content is still accessible using the url without the get query params.

Signed Url: http://d2z7g8y6l5f1j0.cloudfront.net/test_upload.mp4?Expires=1456828601&Signature=R3tljkRxGM9se2S4IJT908sT2BBGNJkpWE9IE-v1GAt-QY0WcaEVEY-OYvSSlhFK1ueNcWhgAscJQ7J~qUKZUt3XS5raKU3kj9STKYYzCemRRm1j5DE8XfhjRKRggSSw138F0lr~tDt~TLoJ7Pj9NNvoGl42jNNLaET7~d9pkAGAh-sNpoS1gz~d0CZTo41ZTFMIzshgZNxrWpCOR0PrLHfRALy2H9-Z9w4XfU4v66WEseVQ3FWyeXFyV0UO2S-KIXbe1ODiHFC6Ae6AJlWzoFfIGAxiLymmtUMJgeQHnu80u97ysMbbNYvek-S0tQBkkID3zC~tDQH~EjXPYcNUbA__&Key-Pair-Id=APKAINPV56WSGDECRTPQ  ^^^ Serves the content  Original Url: http://d2z7g8y6l5f1j0.cloudfront.net/test_upload.mp4  ^^^ Still serves the content 

What's the difference in the above urls ?

Further Issue

The signed url that I have generated is still serving the content so what is the point of the expires GET query parameter, or the issue is that I have made the url correctly or not.

I followed the following method to generate my signed url:

from boto.cloudfront import CloudFrontConnection from boto.cloudfront.distribution import Distribution  # establish cloudfront connection cloudfront_connection = CloudFrontConnection('AWS_KEY', 'AWS_SECRET') expiry_time = int(time.time() + 3000)  #get the distribution distribution = Distribution(connection = cloudfront_connection, domain_name = '<specified_domain_name>', 'id' = '<specified distribution id>')  #create signed url signed_url = distribution.create_signed_url(url = '<cloudfront_url>', keypair_id = '<cloudfront keypair_id>', expire_time = expiry_time, private_key_file = open('<location>', 'r')) 

1 Answers

Answers 1

I have went through the documentation and a couple blogs looking to achieve the above and everyone has pointed me in the direction to use signed urls which I already am. But the urls are still accessible directly via the browser.

Perhaps you have a misunderstanding of the signed URL feature. Any client that has the URL can access the content - there's nothing limiting it to a specific mobile browser or desktop browser or anything else. So long as the URL is valid (e.g. is within the validity period/has not expired, and is within the IP range that you specified, etc), any client will be allowed access.

Your application should generate the signed URL in real time when the user requests it, and it should expire within a time frame that is acceptable to you. This is explained in the docs under How Signed URLs work.

Also I would like to know, why does a signed url has signature as a GET parameter, as if the signature is removed the content is still accessible using the url without the get query params.

You need to use set up a cache behavior that restricts access to requestors that have valid signed URLs. To summarize, when you set up the distribution, you can configure various cache behaviors based on the path that the user is requesting.

This topic is a bit buried in the documentation. See the docs on Cache Behavior Settings, and in particular the Path Pattern and Restrict Viewer Access subsections.

Read More

Monday, March 7, 2016

React Router + AWS Backend, how to SEO

Leave a Comment

I am using React and React Router in my single page web application. Since I'm doing client side rendering, I'd like to serve all of my static files (HTML, CSS, JS) with a CDN. I'm using Amazon S3 to host the files and Amazon CloudFront as the CDN.

When the user requests /css/styles.css, the file exists so S3 serves it. When the user requests /foo/bar, this is a dynamic URL so S3 adds a hashbang: /#!/foo/bar. This will serve index.html. On my client side I remove the hashbang so my URLs are pretty.

This all works great for 100% of my users.

  • All static files are served through a CDN
  • A dynamic URL will be routed to /#!/{...} which serves index.html (my single page application)
  • My client side removes the hashbang so the URLs are pretty again

The problem

The problem is that Google won't crawl my website. Here's why:

  • Google requests /
  • They see a bunch of links, e.g. to /foo/bar
  • Google requests /foo/bar
  • They get redirected to /#!/foo/bar (302 Found)
  • They remove the hashbang and request /

Why is the hashbang being removed? My app works great for 100% of my users so why do I need to redesign it in such a way just to get Google to crawl it properly? It's 2016, just follow the hashbang...

</rant>

Am I doing something wrong? Is there a better way to get S3 to serve index.html when it doesn't recognize the path?

Setting up a node server to handle these paths isn't the correct solution because that defeats the entire purpose of having a CDN.

In this thread Michael Jackson, top contributor to React Router, says "Thankfully hashbang is no longer in widespread use." How would you change my set up to not use the hashbang?

2 Answers

Answers 1

The Hash bang is not recommended when you want to make SEO friendly website, even if its indexed in Google, the page will display only a little and thin content.

The best way to do your website is by using the latest trend and techniques which is "Progressive web enhancement" search for it on Google and you will find many articles about it.

Mainly you should do a separate link for each page, and when the user clicks on any page he will be redirected to this page using any effect you want or even if it single page website.

In this case, Google will have a unique link for each page and the user will have the fancy effect and the great UX.

EX:

<a href="http://www.example.com/contact-us" onclick="fancyEffects();">Contact Us</a> 

Answers 2

The solution you're looking for is prerender.io

This will make a crawlable SEO friendly version by pre-rendering your site and integrating it with your link structure. It's very easy to install and follow.

Installation is easy and it should work fine with React. It's free for up to 250 pages.

Read More