Restrict S3 object access using CloudFront - amazon-web-services

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

Related

Give access to specific user to files in private s3 bucket

I have a s3 bucket that is private and I want specific user to have access to some objects in this bucket. What is the correct way to do that?
For individuals objects, you should use Pre-signed URL.
It allows the user who access the URL to issue a request as the person who pre-signed the URL (inheriting the permissions of the IAM user that generated the URL). It can be generated with SDK or CLI. It is valid for 3600s by default, but you can change this duration.
https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html
For multiple objetcs (if you want a path with wildcard), you can use Signed cookies. It need you to first implements a CloudFront distribution in front of you s3 bucket.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-cookies.html
CloudFront also allow to provide Signed URLs, which are different from S3 Presigned-URL: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html

Prevent anyone from accessing my bucket unless a certain condition

I have an ec2 instance with a load balancer and cloudfront attached and I want to prevent my s3 bucket files from being viewed unless the files are being requested on my website. How would I be able to do this? I've tried "referrer" (which doesn't work sometimes, and apprently not the best option) and I've tried using the "source ip" condition which just doesn't work, I've put in my website ip, my vpc ip from my load balancer, etc, just doesn't work (unless there's another way I have to do it, I would appreciate it if anyone told me). I just want a bucket policty that has a condition like so:
"Condition": {
** person is on my website **
}
If anyone has any ideas, that would be nice, thanks.
I can immediately think of 2 options:
Make your bucket private and instead reverse-proxy the images through your own website.
Make your bucket use Query String Authentication and have your website generate a short-lived QSA token (5 minutes?) for each visitor.
If your content is being served from Amazon S3 or Amazon CloudFront, you can use pre-signed URLs to grant time-limited access to private content.
For example, let's say that you have a photo-sharing website and all photos are private by default. Access can be provided as follows:
Users authenticate to your application
The user then requests access to a private object, or your application wishes to generate an HTML page that includes a link to a private object (eg in an <img> tag).
The application checks whether the user is permitted to access the object. If they are, the application generates a pre-signed URL and provides it in the HTML page or as a link.
The user's browser then uses the URL to request the private object, which sends the request to CloudFront or S3
CloudFront or S3 then checks whether the pre-signed URL is correctly signed and is still within the validity period. If so, it provides access to the object. If not, it returns Access Denied.
For more information, see:
Amazon S3 pre-signed URLs
Using Amazon CloudFront Signed URLs

Protect Private Data in Amazon S3

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.

Relationship between Origin Access Identities (OAIs) and CloudFront Signed URLs

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

How to prevent brute force file downloading on S3?

I'm storing user images on S3 which are readable by default.
I need to access the images directly from the web as well.
However, I'd like to prevent hackers from brute forcing the URL and downloading my images.
For example, my S3 image url is at http://s3.aws.com/test.png
They can brute force test and download all the contents?
I cannot set the items inside my buckets to be private because I need to access directly from the web.
Any idea how to prevent it?
Using good security does not impact your ability to "access directly from the web". All content in Amazon S3 can be accessed from the web if appropriate permissions are used.
By default, all content in Amazon S3 is private.
Permissions to access content can then be assigned in several ways:
Directly on the object (eg make an object 'public')
Via a Bucket Policy (eg permit access to a subdirectory if accessed from a specific range of IP addresses, during a particular time of day, but only via HTTPS)
Via a policy assigned to an IAM User (which requires the user to authenticate when accessing Amazon S3)
Via a time-limited Pre-signed URL
The most interesting is the Pre-Signed URL. This is a calculated URL that permits access to an Amazon S3 object for a limited period of time. Applications can generate a Pre-signed URL and include the link in a web page (eg as part of a <img> tag). That way, your application determines whether a user is permitted to access an object and can limit the time duration that the link will work.
You should keep your content secure, and use Pre-signed URLs to allow access only for authorized visitors to your web site. You do have to write some code to make it work, but it's secure.