6
votes

I have tried a lot of things and I admit defeat (I have read a lot of responses on here but none have helped me so far). I am trying to setup signed URLs for files held on Cloudfont. I am able to create signed URLs for S3 but I cannot get anything to work for Cloudfront. For cloudfront I am using the following from the AWS SDK:

var url = AmazonCloudFrontUrlSigner.GetCannedSignedURL(    AmazonCloudFrontUrlSigner.Protocol.http, "cdn.coffeebreakgrooves.com", privateKey, 
file, cloudFrontKeyPairID, DateTime.Now.AddDays(2));

I get a signed URL generated but I get access denied when following the link, which when I read about it suggested I setup Origin Access Identity. So I then went to my distribution settings and setup Origin Access Identity and chose:

  • Restrict Bucket Access: Yes
  • Origin Access Identity: Use an Existing Identity
  • Grant Read Permissions: Yes, Update Bucket Policy

Then all files become publicly available on Cloudfront, regardless of any settings I have for ACL in S3 (so even if file.txt has no permissions for anyone in S3 it can then be accessed via Cloudfront) and I can't tell if the signed URLs work or not because the download works with or without the querystring and the files have become publicly available. Essentially, how can I make my files private but downloadable with a signed URL (and is my signing method correct?). If I delete the generated bucket policy access is restricted again. I think I need to know how to set the bucket policy so that the origin access identity can only access the bucket with a signed URL... maybe.

Many thanks in advance for any help!

1

1 Answers

8
votes

After a bit of a break and a rethink here is where I was going wrong. It isn't possible to have some content secured and other not secured in the same distribution. Either a whole distribution is secured or not. Here is my solution.

  1. Setup a new bucket for your secure items in AWS
  2. Add a new distribution in Cloudfront pointing to the new bucket created in 1 and choose Yes for 'Restrict Viewer Access' and 'Yes' for 'Forward Query Strings' (this is only to add the ability to add content disposition to specific downloads) and choose 'Self' for 'Trusted Signers'
  3. At the top of AWS click on your name and choose 'Security Credentials' and choose 'Continue' as we chose 'Self' above.
  4. Click on 'CloudFront Key Pairs' and choose 'Create New Key Pair'. Download the key files when offered (they won't be offered again), you need the private key. Also copy the Access Key ID as you'll need that.
  5. Go to your distributions, click on the i next to the secure distribution, click on the origins tab, click 'create origin' or select the origin and choose Edit then choose 'Yes' for Restrict Bucket Access, Create a New Identity and Yes Update Bucket Policy. This essentially means that Cloudfront can authenticate against your bucket.
  6. In your project go to NuGet and search for 'AWS' and install the AWS SDK.
  7. Copy the private key file (pk***.pem) to a folder above your website root (or somewhere relatively private)
  8. Add some code as per the following to generate a secure URL with a Content Disposition header.

I have to say that I couldn't have solved this without the help of Torsten's post on https://forums.aws.amazon.com/thread.jspa?messageID=421768 which is in PHP but pointed me in the right direction:

string cloudFrontKeyPairID = "myaccesskeyidfrompoint4";
string pathtokey = HttpContext.Current.Request.MapPath("~/").Replace("wwwroot", "ssl") + "pk-mykeyidfilenamesavedin4.pem";
FileInfo privateKey = new FileInfo(pathtokey);
string file = "folder/mytrack.mp3?response-content-disposition=" + 
HttpContext.Current.Server.UrlEncode("attachment;filename='a_filename_with_no_spaces.mp3'"); 
//I can't figure out how to do spaces or odd characters.

url =   AmazonCloudFrontUrlSigner.GetCannedSignedURL(
    AmazonCloudFrontUrlSigner.Protocol.http, 
    "customcname.mydomain.com", 
    privateKey, 
    file, 
    cloudFrontKeyPairID, 
    DateTime.Now.AddDays(2));

I hope that helps someone, I will be using this as a personal resource anyway! Enabling the Origin Access Identity on an existing bucket which doesn't have 'Restrict Viewer Access' set it essentially opens up permissions for all items on your bucket. This may or may not be desirable! If I have anything wrong please let me know, this is all pretty new to me.