AWS S3 static site w/ cloudfront - without making the bucket public - amazon-web-services

I'm trying to host a static site from S3. I had it previously set up where Route 53 was configured to redirect traffic to CloudFront, which has my public S3 bucket cached. When I make the bucket private, my whole site goes down. I had set ACLs to allow traffic from CloudFront but even with that going to my website will provide a 403 Forbidden Error.
What am I missing here? Is there a good tutorial to follow for my use case?
Thank you!

i think this would help you, https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-serve-static-website/ (the Using a website endpoint as the origin, with access restricted by a Referer header the part) to summarise it you need to give a specific header from your cloudfront to your s3 and change the bucket policy to accept get requests only that have only this header.

The standard way to solve this is via an Origin Access Identity, which allows CloudFront to access a private S3 bucket.

Related

How to make aws s3 bucket public but strict it to specific domain and localhost (testing)

How to make aws s3 bucket public but restrict it to specific domain and localhost:3000 (for testing purpose).
Basically the s3 files will be accessed by the react.js website and we don't want the s3 files to be accessed outside the wwww.example.com domain and localhost:3000
Tried couple of things but doesn't seem to work.
Bucket policy - Not configured and not sure what to specify
Let me know the changes to be done to make it work.
How to make aws s3 bucket public but strict it to specific domain
Its not possible. At best you could Restricting access to a specific HTTP referer, but its not bullet proof. AWS writes:
Therefore, do not use aws:Referer to prevent unauthorized parties from making direct AWS requests.
You need proper authoritative mechanism and place your website behind some login screen, if you want to control access to it.

How to prevent direct access to cloudfront domain name and instead only via custom domain

I've set up a static site on AWS with route 53, ACM, cloudfront and s3. However although I can prevent direct access to the bucket's generated domain name via a bucket policy so that access is only via my custom domain eg www.example.com I'm not sure how to do this for cloudfront and currently the website can be accessed via a cloudfront domain name eg 23324sdfff.cloudfront.net
Is there a way to prevent access to the website via the cloudfront domain name so that traffic can only access the site directly via www.example.com?
I think you could achieve that using Lambda#Edge.
Specifically you could create a function for viewer-request. The function would inspect the request and then decide if to allow or deny it.
Sadly, I don't have concrete example addressing your specific use-case. But AWS docs provide a number of examples that could be useful to you.
Maybe,there is an easier way not involving the lambda, but at present I'm not aware of such a possibility.

How to generate an S3 pre-signed URL for a custom domain without exposing bucket name

I have a bucket my-bucket-name and I want to grant temporary access to some file.pdf in folder-name. As for default I get next link using boto3:
https://my-bucket-name.s3.amazonaws.com/folder-name/file.pdf?AWSAccessKeyId=<key>&Signature=<signature>&x-amz-security-token=<toke>&Expires=<time>
But also I've got a DNS alias, my.address.com is mapped to my-bucket-name.s3.amazonaws.com. Of course, if I'm using it directly I got SignatureDoesNotMatch from amazon. So I'm using next code to generate pre-signed link:
from botocore.client import Config
kwargs = {}
kwargs['endpoint_url'] = f'https://my.address.com'
kwargs['config'] = Config(s3={'addressing_style': 'path'})
s3_client = boto3.client('s3', **kwargs)
url = s3_client.generate_presigned_url(ClientMethod='get_object',
Params={
'Bucket': 'my-bucket-name',
'Key': 'folder-name/file.pdf'
},
ExpiresIn=URL_EXPIRATION_TIME)
As a result it returns me next link:
https://my.address.com/my-bucket-name/folder-name/file.pdf?AWSAccessKeyId=<key>&Signature=<signature>&x-amz-security-token=<toke>&Expires=<time>
There are two problems with this:
I don't want to expose my bucket name, so my-bucket-name/ should be ommited
This link doesn't work, I'm getting
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
Those these are the questions:
Is it possible to achieve a workable link without exposing bucket name?
I've already read something about that custom domains are only possible for HTTP, not HTTPS access, is it true? What should I do in this case?
The DNS alias wasn't made by me, so I'm not sure if it works or is set up correctly, what should I check/ask to verify that it will be working for s3?
Currently I'm a bit lost in Amazon docs. Also I'm new to all this AWS stuff.
It is not possible to hide the bucket name in an Amazon S3 pre-signed URL. This is because the request is being made to the bucket. The signature simply authorizes the request.
One way you could do it is to use Amazon CloudFront, with the bucket as the Origin. You can associate a domain name with the CloudFront distribution, which is unrelated to the Origin where CloudFront obtains its content.
Amazon CloudFront supports pre-signed URLs. You could give CloudFront access to the S3 bucket via an Origin Access Identity (OAI), then configure the distribution to be private. Then, access content via CloudFront pre-signed URLs. Please note that the whole content of the distribution would be private, so you would either need two CloudFront distributions (one public, one private), or only use CloudFront for the private portion (and continue using direct-to-S3 for the public portion).
If the whole website is private, then you could use a cookie with CloudFront instead of having to generate pre-signed URLs for every URL.
As far as I know, you cannot have a pre-signed URL without exposing the bucket name. Yes, you cannot access a custom domain name mapped to the S3 bucket URL via https. Because when you access https://example.com and example.com is mapped to my-bucket-name.s3.amazonaws.com, it is not possible for S3 to decrypt the SSL traffic. See this AWS docs page, Limitation section.

How to hide AWS S3 Bucket URL with custom CNAME

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.

How to disable Amazon S3 raw endpoint access

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