So I've been following guides on CloudFront and S3 and I feel like I am still missing a core piece of information in the relationship between Origin Access Identities (OAIs) and CloudFront Signed URLs.
What I want: a private CDN to host audio snippets (of a few seconds in length) and low-resolution images. I only want these files to be accessible when requested from a specific domain (i.e. the domain the web app will live on) and maybe a testing server, so that my web app can get the files but anyone else just can't access them without going through the web app.
What I'm confused about: I'm fuzzy on the relationship (if there is any) between CloudFront Origin Access Identities (OAIs) and Signed CloudFront URLs.
I have currently created a private S3 bucket, an OAI for my CloudFront distribution, and have generated a signed URL to an image through CloudFront. But I don't see how these things are related and how they prevent someone else from accessing CDN files (e.g. if they were able to inspect an element and get the signed URL).
Is the whole point to make sure the signed URLs expire quickly? And if so, how does the OAI play a role in it? Is this something set in CORS?
An origin access identity is an entity inside CloudFront that
can be authorized by bucket policy to access objects in a bucket. When CloudFront uses an origin access identity to access content in a bucket, CloudFront uses the OAI's credentials to generate a signed request that it sends to the bucket to fetch the content. This signature is not accessible to the viewer.
The meaning of the word "origin" as used here should not be confused with the word "origin" as used in other contexts, such as CORS, where "origin" refers to the site that is allowed to access the content.
The origin access identity has nothing to do with access being restricted to requests containing a specific Origin or Referer header.
Once a signed URL is validated by CloudFront as matching a CloudFront signing key associated with your AWS account (or another account that you designate as a trusted signer) the object is fetched from the bucket, using whatever permissions the origin access identity has been granted at the bucket.
Is the whole point to make sure the signed url's expire quickly?
Essentially, yes.
Authentication and Authorization of requests by trying to restrict access based on the site where the link was found is not a viable security measure. It prevents hot-linking from other sites, but does nothing to protect against anyone who can forge request headers. Defeating a measure like that is trivial.
Signed URLs, by contrast, are extremely tamper resistant to the point of computational infeasibility.
A signed URL is not only valid only until it expires, but can optionally also restrict access to a person having the same IP address that's included in the policy document, if you use a custom policy. Once signed, any change to the URL, including the policy statement, makes the entire URL unusable.
The OAI is only indirectly connected with CloudFront signed URLs -- they can be used individually, or together -- but without an OAI, CloudFront has no way to prove that it is authorized to request objects from your bucket, so the bucket would need to be public, which would defeat much of the purpose of signed URLs on CloudFront.
Add a new CNAME entry that points to your CloudFront domain. This entry should match that entered in the ‘Alternate Domain Names’ from within the CloudFront console.
By default CloudFront generate Domain name automatically (eg d3i29vunzqzxrt.cloudfront.net) but you can define your alternative domain name.
Also you can secure Cloudfront
Serving Private Content through CloudFront
Related
How do I serve restricted video content to the clientside and make sure the video link can not be used to download the video. If I use cloudfront signed url is there a chance that user can download the video before the expiration time.
You have 2 choices to restrict CloudFront content:
Signed URLs as you said, these are for accessing a particular file. The generated URL will be accessible for the duration it has been signed for.
Signed cookies, similar to signed URLs but allows all content from the CloudFront distribution to be accessible within signing every time. When this expires the user will lose all access to the content from the CloudFront distribution.
When you grant either of these the user will have unlimited access during that time.
If you want to add additional layers of validation you would need to run an application on top, validating before generating a signed URL and returning the content.
You are also free to attach an AWS WAF to your CloudFront distribution to help protect against exploits of your distribution.
I need to restrict access to S3 objects using cloudfront. Hence the users will be hitting the cloudfront url instead of S3.
How do I specify which users can access the cloudfront URL.
I am aware of OAI and related bucket access but that does not allow me to restrict the user group.
I would use Signed URLs for this purpose. You can generate the URL for your specific user, share it with them, and limit access to that URL with the constraints available.
In one case I generated a very short-lived Signed URL and redirected the user to that URL, so it essentially only worked for the user who made the request. Limiting the lifetime to a few seconds and access to the client's IP address was sufficient for my case.
AWS docs here on Private Content: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html
Is it possible to PUT to S3 using a presigned key-starts-with policy to allow upload of multiple or arbitrarily named files?
This is easy using the browser-based PresignedPost technique, but I've been unable to find a way to use a normal simple PUT for uploading arbitrary files starting with the same key.
This isn't possible... not directly.
POST uploads are unique in their support for an embedded policy document, which allows logic like starts-with.
PUT and all other requests require the signature to precisely match the request, because the signature is derived entirely from observable attributes of the request itself.
One possible workaround would be to connect the bucket to CloudFront and use a CloudFront pre-signed URL with an appropriate wildcard. The CloudFront origin access identity, after validating the CloudFront URL, would actually handle signing the request in the background on its way to S3 to match the exact request. Giving the origin access identity the s3:PutObject permission in bucket policy then should allow the action.
I suggest this should work, though I have not tried it, because the CloudFront docs indicate that the client needs to add the x-amz-content-sha256 header to PUT requests for full compatibility with all S3 regions. The same page warns that any permissions you assign to the origin access identity will work (such as DELETE), so, setting the bucket policy too permissive will allow any operation to be performed via the signed URL -- CloudFront signed URLs don't restrict to a specific REST verb.
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html
Note that there's no such concept as uploading "to" CloudFront. Uploads go through CloudFront to the origin server, S3 in this case.
I want to upload some images on Amazon S3 and based on the user's subscription give them the access of viewing some portions of these images. After reading Amazon S3 documentation I have come up with these solutions:
Assigning each user in my application to one IAM user in Amazon S3 and then defining user policy or bucket policy to manage who has access to what. But there is two drawbacks: First, the user or bucket policies have limit on their size and since the number of users and images are very large it is very likely that I need to exceed that limit. Second, the number of IAM users per AWS account is bounded to 5000 and I would have more users in my application.
Amazon S3 makes it possible to define some temporary security credentials that act the same as IAM users. It's possible for me to require the client side to make a request to my server and I create a temporary IAM user for them with a special policy and pass them their credentials then they can directly send request to S3 using their credentials and have access to their resources. But the problem is that these users would last between 15 min to 1 hour and therefore the clients need to request my server at least every 1 hour to make a temporary IAM user for them.
Since I want to serve some images it is a good practice to use combination of Amazon Cloudfront and S3 to serve the content as quick as possible. I have also read the Cloudfront documentation for serving private content and I found out that their solution is using signed URLs or signed cookies. I will deny any access to S3 resources and the cloudfront would be the only one who has the access to read data from S3 and every time a user signs in to my application I would send them the credentials that they need to have to make a signed URL or I would send them the necessary cookies. They can request required resources with the information that they have and this information would last until they are signed in to my application. But I have some security concerns. Since almost all of the information about access control is sent to the client (e.g. in cookies) they can easily modify it and grant themselves more permissions. However it is a big concern but I think I have to use cloudfront for decreasing loading resource time.
I want to know you think which of these solutions is more reasonable and better than others and also if there are other solutions maybe using other Amazon web services.
My own approach to serve private content on S3 is by using CloudFront with either signed URLs or signed cookies (or sometimes, both). You should not use IAM users or temporary credentials for large number of users, as in your case.
You can read more about this topic here:
Serving Private Content through CloudFront
Your choice of whether to use signed URLs or signed cookies depends on the following.
Choosing Between Signed URLs and Signed Cookies
CloudFront signed URLs and signed cookies provide the same basic
functionality: they allow you to control who can access your content.
If you want to serve private content through CloudFront and you're
trying to decide whether to use signed URLs or signed cookies,
consider the following.
Use signed URLs in the following cases:
You want to use an RTMP distribution. Signed cookies aren't supported
for RTMP distributions.
You want to restrict access to individual files, for example, an installation download for your application.
Your users are using a client (for example, a custom HTTP client) that
doesn't support cookies.
Use signed cookies in the following cases:
You want to provide access to multiple restricted files, for example,
all of the files for a video in HLS format or all of the files in the
subscribers' area of a website.
You don't want to change your current
URLs.
As for your security concerns, CloudFront uses the public key to validate the signature in the signed cookie and to confirm that the cookie hasn't been tampered with. If the signature is invalid, the request is rejected.
You can also follow the guidelines at the end of this page to prevent misuse of signed cookies.
We are using cloudfront for serving s3 resource and it is restricted.
In c#, while creating the presigned url using the "AmazonCloudFrontUrlSigner.SignUrlCanned" it does ask only for the cloudfront private key generated using the root credentials and doesn't ask for IAM user credentials.
In the distribution behavior, I can see there is an option to specify the "Trusted Signers" but not able to understand where it is being used. Any info on this would be great. Also is there a way to generate presigned cloudfront url using the IAM user credentials?
CloudFront does not support the use IAM credentials for generating signed URLs, nor does it use the signing algorithms common to other AWS services.
The process is, however, fully documented. CloudFront has its own method for accessing private objects in S3 on behalf of your users -- the origin access identity -- and will use this mechanism transparently when presented with a signed URL or signed cookies, generated using a keypair associated with a trusted signer.
See Serving Private Content through CloudFront for descriptions of the mechanisms and configuration walk-throughs.
Cloudfront does use IAM to generate signed urls. In distribution there is configuration for Trusted Signers where you can add other accounts ID in order to allow those accounts to generate signed urls. It means trusted signer can use there own generated keypair to sign a url of the distribution.
Any trusted signer that you configure for your CloudFront distribution will need to set up their own CloudFront key pair for their account in order to sign requests for your CloudFront private content Reference
This keypair is associated with account and it can have only max one active keypair at any point of the time