This is more of a theoretical question for AWS S3 website hosting.
Say I have a website hosted in S3. Obviously I want the content to be public, but I don't want people to be able to download the backend scripts, images, css by simply changing the domain url. I want to hide those folders, but if I deny GetObject access in the bucket policy for the folders the application "breaks" because it can't reach those folders.
How can I secure my content to ensure the most security for my backend when it sits in an S3 bucket?
You need to access the website via cloudfront with restricted access, better known as Origin Access Identity. This will allow cloudfront distribution access to s3 bucket.
More details can be found in the AWS Docs or https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#private-content-creating-oai
Related
I have a static React App I have deployed using Cloudfront - hosted within an S3 Bucket. I would like the user to have the option to upload files in the future, through this app, to the bucket but I am a little confused on the permissions side.
I have created the Bucket with the CDK like so...
val siteBucket = Bucket(
this, "SiteBucket",
BucketProps.builder()
.bucketName(SITE_DOMAIN_NAME)
.websiteIndexDocument("index.html")
.publicReadAccess(true)
.removalPolicy(DESTROY)
.build()
)
I have additional config using the CDK to hook up the CloudFrontWebDistribution and to route the traffic to my domain.
My understanding of the above is that .publicReadAccess(true) allows my Bucket to be accessible to the wider internet - but that it doesn't grant any rights to upload to the bucket.
However, how do I use the CDK to grant permissions for only my static webapp to upload to the Bucket - but not for anyone else to upload?
(I've been reviewing this https://docs.aws.amazon.com/cdk/v2/guide/permissions.html but unsure of the best practise e.g. can my app have a role or permissions assigned to when the app itself is just the contents of a bucket. Do I need to create an Access Point? But again, how do I limit my app to have permissions - is this even possible with a static app or do I need a backend/Lambda to invoke first?)
Thanks!
For one, you don't need publicReadAccess. You can just grant access to the OAI.
https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-access-to-amazon-s3/
This is a pretty good starting point for the page though:
https://aws.amazon.com/blogs/storage/allowing-external-users-to-securely-and-directly-upload-files-to-amazon-s3/
Not sure you necessarily want to use the same bucket to upload to and host your site.
I'm new to AWS tools and although I have tried to search thoroughly for an answer I wasn't able to fixate on a solution.
My usecase is this:
I have a bucket where I need to store images, upload them via my server however I need to display them on my website.
Should my bucket be public?
If not, what should I do to allow everyone to read those images but not be able to mass upload on it from origins who are not my server?
If you want the images to be publicly accessible for your website, then the objects need to be public.
This can be done by creating a Bucket Policy that makes the whole bucket, or part of the bucket, publicly accessible.
Alternatively, when uploading the images, you can use ACL='public-read', which makes the individual objects public even if the bucket isn't public. This way, you can have more fine-grained control over what content in the bucket is public.
Both of these options require you to turn off portions of S3 Block Public Access to allow the Bucket Policy or ACLs.
When your server uploads to S3, it should be using Amazon S3 API calls using a set of AWS credentials (Access Key, Secret Key) from an IAM User. Grant the IAM User permission to put objects in the bucket. This way, that software can upload to the bucket totally independently to whether the bucket is public. (Never make a bucket publicly writable/uploadable, otherwise people can store anything in there without your control.)
upload them via my server however I need to display them on my website.
In that case only your server can upload the images. So if you are hosting your web app on EC2 or ECS, then you use instance role and task role to provide S3 write access.
Should my bucket be public?
It does not have to. Often CloudFront is used to host images or files from S3 using OAI. This way your bucket remains fully private.
Is it possible to protect data embedded on my website via Amazon CloudFront from hotlinking or other downloads? I am mainly interested in protecting webfonts from being downloaded.
Amazon CloudFront is connected to a S3 Bucket
S3 Bucket Policy controls allowed domains for files via CloudFront
You think that could work?
Since you have cloudfront setup connected to your s3 bucket, you can use Cloudfront Signed Urls to prevent download by anyone from the public.
You can put your fonts in a folder called fonts for example, and setup a separate behaviour in cloudfront for any path that contains /fonts/ and in there you can activate Restrict Viewer Access.
In your website, you will need to add some way to generate the presigned url for this only when your webpage is loaded and you can put a short expiry time for this URL.
I want to connect CDN to an AWS S3 Bucket, but the AWS Document indicates that the bucket name must be the same as the CNAME. Therefore, it is very easy to guess the real s3 bucket url by others.
For example,
- My domain: example.com
- My S3 Bucket name: image.example.com
- My CDN CNAME(image.example.com) will point to image.example.com.s3.amazonaws.com
After that, people can access the CDN URL -> http://image.example.com to obtain the resources from my S3 Bucket. However, under this restriction, people can guess my real S3 bucket url from the CNAME (CNAME + s3.amazonaws.com) easily.
So, my question is that how can I hide my real s3 bucket url? Because I don't want to expose my real S3 url to anyone for preventing any attacks.
I am not sure I understand what you are asking for or what you are trying to do [hiding your bucket does not really help anything], however I will attempt to answer your question regarding "hiding" your bucket name. Before I answer, I would like to ask these two questions:
Why do you want to hide your S3 bucket url?
What kind of attacks are you trying to prevent?
You are correct that the S3 bucket name had to be the same as your URL. This is no longer a requirement as you can mask the S3 bucket using cloudfront. CloudFront as you know is a CDN from AWS. Thus the bucket name could be anything (randomstring).
You can restrict access to the bucket, such that only CloudFront can access it. Data in the bucket is then replicated to edge locations and served from there. Even if one knows the S3 URL, it will not do anything as access to the s3 bucket is restricted, an IAM rule grants CloudFront access and no one else.
Access restriction is done via origin access and while you can manually configure this using a bucket policy, you can also set a flag in CloudFront to do this on your behalf. More information is available here.
Use the CloudFront name in Route53. Do not use CNAME, but rather use A type, and set it up as an Alias. For more information see this document.
If you are using a different DNS provider, AWS aliases will naturally not be available. I suggest moving the zone file from your other provider to AWS. If you cannot do this, then you can still use a CNAME. Again see here for more information.
I suggest using your own domain name for CloudFront and setting up HTTPS. AWS offers certificates at no additional cost for services within AWS. You can register a certificate for your domain name which is either validated by a DNS entry or an Email. To set this up please see this document.
If you want to restrict access to specific files within AWS, you can use signed URLs. More information about that is provided here.
Say you want to host a static web site on S3 :
You create a bucket with name your-website.com and set it up for web hosting;
You add a CNAME in your domain's zone file to point to your S3 bucket.
Great. Everything works fine when you visit http://your-website.com. But you don't want the raw/"naked" endpoint to be accessible.
Is there any setting in the bucket to disable direct access to http://your-website.com.s3-website.your-region.amazonaws.com ?
The reason is that if your web site is accessible both through http://your-website.com and http://your-website.com.s3-website.your-region.amazonaws.com would hurt your SEO (duplicate content)
You mention your major concern is SEO. For that purpose, you could use a other techniques, that are probably easier to implement than the one you initially asked about.
One of the main techniques to deal with duplicate content is to use rel=canonical, which is probably fairly easy to implement. For more information, see http://googlewebmastercentral.blogspot.com.br/2013/04/5-common-mistakes-with-relcanonical.html
If you insist on the need to disable access to the bucket unless the client connects through your CNAME, your best bet is to use CloudFront. You disable the S3 website hosting option on your bucket, make your S3 bucket private (i.e., remove bucket policies or ACLs allowing public read), create a CloudFront distribution, define your bucket as the origin, configure a CNAME on your distribution, change your DNS records to point to your distribution instead of bucket, create an Origin Access Identity (OAI) on your distribution and grant access to your bucket for that OAI. Phew.
By doing all this, there's no way for a user to access the content on your S3 bucket (unless they have an AK/SK with permissions to read the bucket, and send a signed request, obviously). The only way will be through your domain.
For more detail on Origin Access Identity, see http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html