Restrict access to s3 static website behind a cloudfront distribution - amazon-web-services

I want to temporarily restrict users from being able to access my static website hosted in s3 which sits behind a cloudfront distribution.
Is this possible and if so what methods could i use to implement this?
I've been able to restrict specific access to my s3 bucket by using a condition in the bucket policy which looks something like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "12.34.56.73/32"
}
}
}
]
}
which works and restricts my s3 bucket to my ip, however this means that the cloudfront url gets 403 forbidden: access denied.
When reading the AWS docs, it suggests that to restrict specific access to s3 resources, use an Origin Access Identity. However they specify the following:
If you don't see the Restrict Bucket Access option, your Amazon S3 origin might be configured as a website endpoint. In that configuration, S3 buckets must be set up with CloudFront as custom origins and you can't use an origin access identity with them.
which suggests to me that i can't use it in this instance. Ideally i'd like to force my distribution or bucket policy to use a specific security group and control it that way so i can easily add/remove approved ip.

You can allow CloudFront IP addresses on CloudFront because static website endpoint doesn't support Origin access identity.
Here is the list of CloudFront IP addresses:
http://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips

This link also explains how you can limit access via referral headers
https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-serve-static-website/
You can tell CloudFront to add a header to every request and then modify your S3 bucket policy to require that header.
E.g.
{
"Version":"2012-10-17",
"Id":"http referer policy example",
"Statement":[
{
"Sid":"Allow get requests originating from www.example.com and example.com.",
"Effect":"Allow",
"Principal":"*",
"Action":"s3:GetObject",
"Resource":"arn:aws:s3:::examplebucket/*",
"Condition":{
"StringLike":{"aws:Referer":"mysecretvalue"}
}
}
]
}

Related

Restrict Amazon CloudFront and http referrer [duplicate]

I have this settings on my s3 bucket policy, where I allow only my cloudfront and referer to access the files on the bucket. I also used Signed URL.
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ABCD1234"
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-files/*",
"Condition":{
"StringLike":{"aws:Referer":[
"https://example.com/*"
]}
}
}
]
}
And on the cloudfront behavior, I added the Referer here
Then, invalidate the cache.
Before setting the referer on s3 bucket policy, I can still access my files with signed url. But after setting up the aws:Referer Condition and invalidate the cache, I cannot access my files. It shows 403 Forbidden status.
What settings did I missed? Or is it possible to use Cloudfront OAI with Referer?
What settings did I missed? Or is it possible to use Cloudfront OAI with Referer?
You shouldn't use referrer, as you use OAI. This means that CF will use AWS API to get your objects, not regular HTTP(s) requests. In that case aws:Referer is not used:
This key is included in the request context only if the request to the AWS resource was invoked by linking from a web page URL in the browser. This key is not included for programmatic requests because it doesn't use a browser link to access the AWS resource.

Is there any way to host a static wesbite on AWS S3 without giving public access?

I wish to host a static website on Amazon S3 without actually giving the public access to the bucket. I am using a client AWS account in which all the buckets have public accessed blocked, when I try to configure my bucket as public, it redirects me to a page where I have to grant public access to all the buckets.
You can front your static site with an Amazon CloudFront distribution. In addition to providing the benefits of an integrated CDN, you can configure an Origin Access Identity that ensures that the bucket can only be accessed through CloudFront, not through public S3.
Similar to what #PaulG said, you can also include a bucket policy that includes a sourceVpc condition, which allows you to set up a vpc endpoint to the bucket and only access the bucket from that VPC. I remember testing this setup a few months back and it worked to only access the website from a vpc.
Speaking about just 1 S3 bucket that is hosting a static site, you can add a bucket policy under the Permissions tab, allowing or disallowing IP Addresses. There are some great examples here & I've added a simplified example allowing certain IPs. In this case granting access to the other account's VPC NAT Gateway IP address should work. https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html
{
"Id":"PolicyId54",
"Version":"2012-10-17",
"Statement":[
{
"Sid":"AllowIPmix",
"Effect":"Allow",
"Principal":"*",
"Action":"s3:*",
"Resource": [
"arn:aws:s3:::DOC-EXAMPLE-BUCKET",
"arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"54.240.143.0/24",
"2001:DB8:1234:5678::/64"
]
}
}
}
]
}
Note, you still turn "Block public access" off along with the above policy.
Yes it is possible, All you need to do is serve s3 through cloudfront.
Client -> Route53 -> Cloudfront -> S3 (blocked public access)
In Cloudfront
Create cloudfront function (from left menu), this will redirect any
request with index.html appended. For ex: example.com/home to
example.com/home/index.html
'use strict';
function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
Create the origin access (from left menu), this will be used in
distribution's origin
In Distributions
In origin tab
Create origin as S3 type, by choosing the s3 bucket
Click on origin access control settings that create at first step
Edit general settings and put index.html in default root object.
Edit Behaviours, In Function associations, select cloudfront function
in viewer request. Don’t need to go with lambda function
In S3
In properties, disable static s3 website hosting
In permissions
Block all public access
Edit the bucket policy with below:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::BUCKET_NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::ACC_NUMBER:distribution/DISTRIBUTION_ID"
}
}
}
]
}
In Route53
Create A record by selecting cloudfront distribution

AWS Cloudfront - S3 with CloudFront Origin Access and Referer bucket policy

I have this settings on my s3 bucket policy, where I allow only my cloudfront and referer to access the files on the bucket. I also used Signed URL.
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ABCD1234"
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-files/*",
"Condition":{
"StringLike":{"aws:Referer":[
"https://example.com/*"
]}
}
}
]
}
And on the cloudfront behavior, I added the Referer here
Then, invalidate the cache.
Before setting the referer on s3 bucket policy, I can still access my files with signed url. But after setting up the aws:Referer Condition and invalidate the cache, I cannot access my files. It shows 403 Forbidden status.
What settings did I missed? Or is it possible to use Cloudfront OAI with Referer?
What settings did I missed? Or is it possible to use Cloudfront OAI with Referer?
You shouldn't use referrer, as you use OAI. This means that CF will use AWS API to get your objects, not regular HTTP(s) requests. In that case aws:Referer is not used:
This key is included in the request context only if the request to the AWS resource was invoked by linking from a web page URL in the browser. This key is not included for programmatic requests because it doesn't use a browser link to access the AWS resource.

How do I restrict S3 + Cloudfront staging server to specific IP?

I am trying to setup my staging server to be served via S3 and cloudfront. Here is my bucket policy below.
a) If I access the S3 url directly, everything works fine.
b) If I access the cloudfront root domain, www.staging.example.com, everything works fine.
However, once I go to www.staging.example.com/login (or any non-root url), I get a 403 Forbidden AccessDenied error. How do I fix this?
{
"Version": "2012-10-17",
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::staging-server/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"XXX",
"XXX",
]
}
}
}
]
}
If your intention is to serve the site via CloudFront only, then you should reconfigure the S3 bucket policy to allow access to the CloudFront Origin Access Identity of your CloudFront distribution, and remove all IP address conditions from the bucket policy.
To restrict access to the distribution to an IP whitelist, configure AWS WAF and an IPSet. Use WAF v2, not the original WAF.
On the non-root url question, do you actually have a document named login?

Restrict Amazon S3 access to single HTTPS host

I want to proxy an Amazon S3 bucket through our reverse proxy (Nginx).
For higher security, I want to forbid the read access to the bucket to anything except of the HTTPS host at which I ran the proxy.
Is there a way to configure Amazon S3 for this task?
Please provide the configuration.
I considered to add a password in S3 bucket name, but it is not a solution, because we need also signed uploads to the bucket and so the bucket name will be publicly available.
If your reverse proxy has a Public IP address, then you would add this policy to the Amazon S3 bucket:
{
"Version": "2012-10-17",
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::examplebucket/*",
"Condition": {
"IpAddress": {"aws:SourceIp": "54.240.143.22/32"}
}
}
]
}
This grants permissions to GetObject if the request is coming from the specific IP address. Amazon S3 is private by default, so this is granting access only in that particular situation. You will also want to grant access to IAM Users/Groups (via IAM, not a Bucket Policy) so that bucket content can be updated.
See: Bucket Policy Examples - Amazon Simple Storage Service