6
votes

Using AWS I am quite comfortable with the following scenario:

  • Set up S3 bucket example.com as a static web site.
  • Create a distribution of example.com on CloudFront.
  • Use Route 53 and the certificate manager to allow browsing the S3 bucket content using HTTPS via CloudFront.

However as you know it would still possible to directly access the web site under its alternate URL directly from the S3 bucket using HTTP. I would like to prevent users from directly accessing the S3 bucket URL.

Several tutorials on the web, including the CloudFront documentation, say that I need to create an Origin Access Identity (OAI) and restrict access to the S3 bucket only to the CloudFront distribution using that OAI. However this documentation also says that I can't use OAI with an S3 bucket set up as a static website endpoint.

So that leaves me with a couple of questions that aren't clear to me from the documentation:

  • If I turn off static website access to my S3 bucket example.com, once I connect it to CloudFront using an OAI, will I still be able to access the S3 bucket content via CloudFront over HTTPS? That is, does CloudFront provide "static web site accesss" to my S3 bucket even though I've turned off static website hosting for the bucket?
  • When configuring an S3 bucket for static web site hosting, S3 allows me to set up "routing rules" to redirect foo.html to bar.html for example. If I turn off static web site hosting for my S3 bucket, how do I set up redirects? Does CloudFront provide similar routing rules that I can configure, or is there another way to accomplish this?
5

5 Answers

6
votes

The other ways to restrict access to S3 website endpoint from CloudFront are:

  1. S3 bucket policy to allow access only from CloudFront IP addresses. CloudFront IP addresses : CloudFront IP range

  2. Create S3 policy based on conditions such as Referer and Whitelist Referer header on CloudFront, this only works if you're serving assets from CloudFront, not the main index page as main index page won't have the Referer header in the request.

If you use S3 rest api endpoint instead of s3 website endpoint as an origin, your website will still work on HTTPS (SSL terminates on CloudFront) but there are couple of problem:

  1. Redirection/Routing rules won't work with REST API endpoint.
  2. REST API endpoint doesn't automatically server index page example: if you access abc.com/path --> S3 static endpoint will redirect it to abc.com/path/index.html (Exception for abc.com --> abc.com/index.html which can be done on CloudFront by defining Root document)

For your question of foo.html and bar.html, you need to use Lambda@edge function to change the URI with origin request function.

Lambda@edge examples

2
votes

will I still be able to access the S3 bucket content via CloudFront over HTTPS?

Yes, but cloudfront will access the origin bucket through authenticated S3 API requests instead of generic http requests.

When configuring an S3 bucket for static web site hosting, S3 allows me to set up "routing rules" to redirect foo.html to bar.html for example. If I turn off static web site hosting for my S3 bucket, how do I set up redirects?

I don't know of a way to do it in CloudFront. I continue to host my assets on an s3 website for that reason.

I would like to prevent users from directly accessing the S3 bucket URL.

I was willing to give that up to maintain some of the functionality I wanted from s3 bucket hosting. It's a tradeoff you'll have to decide for yourself which is more important.

0
votes

If I turn off static website access to my S3 bucket example.com, once I connect it to CloudFront using an OAI, will I still be able to access the S3 bucket content via CloudFront over HTTPS? That is, does CloudFront provide "static web site accesss" to my S3 bucket even though I've turned off static website hosting for the bucket?

You can use any bucket for hosting content delivered via Cloudfront, it does not need to be configured as public web hosting. If you have it configured to only allow the OAI to access the bucket, then users will be prevented from accessing content directly.

In cloudformation, this can look like this:

WebsiteContentBucket:
  Type: AWS::S3::Bucket
  DeletionPolicy: Delete
  Properties:
    BucketName: <bucketname here>

WebsiteContentBucketPolicy:
  Type: AWS::S3::BucketPolicy
  Properties:
    Bucket:
      Ref: WebsiteContentBucket
    PolicyDocument:
      Statement:
      - Action:
          - "s3:GetObject"
        Effect: "Allow"
        Resource:
          Fn::Sub: arn:aws:s3:::${WebsiteContentBucket}/*
        Principal:
          AWS:
            Fn::Sub: "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${WebsiteCloudFrontOAI}"

WebsiteCloudFrontOAI:
  Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
  Properties:
    CloudFrontOriginAccessIdentityConfig:
      Comment: your comment here

When configuring an S3 bucket for static web site hosting, S3 allows me to set up "routing rules" to redirect foo.html to bar.html for example. If I turn off static web site hosting for my S3 bucket, how do I set up redirects? Does CloudFront provide similar routing rules that I can configure, or is there another way to accomplish this?

You move the routing to Cloudfront instead of S3. So if you want /foo.html to return bar.html you create another origin in cloudfront. You can have multiple origins, pointing to different buckets, application servers, etc.

0
votes

"Static website hosting" feature of S3 bucket only affects redirect rules (see below). But it does not affect visibility of your website by alternative URL. So, if you are using CloudFront and OAI - you should make S3 bucket private, then it will be accessible only via CloudFront.

If you enable "Static website hosting" in S3 you will be able to:

  • forward "/" path to "/index.html". This is also possible with CloudFront.
  • forward not found pages to "/error.html". This is also possible with CloudFront.
  • have redirect rules. This is possible to achieve with Lambda @Edge in CloudFront.

Conclusion: enabling "Static website hosting" is not required when serving traffic via CloudFront.

0
votes

Hidden in the comments to my original question is an absolute gem of an idea by @Michael-sqlbot: use an IAM JSON condition policy element with the aws:UserAgent key to only allow access from CloudFront based upon the CloudFront User-Agent header:

User-Agent = Amazon CloudFront

This turns out to be pretty simple. Here is a basic IAM JSON policy restricting the example.com bucket to access only by CloudFront based upon the User-Agent header:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example.com/*",
      "Condition": {
        "StringEquals": {
          "aws:UserAgent": "Amazon CloudFront"
        }
      }
    }
  ]
}

Then if a user attempts to browser directly to the S3 bucket website URL, AWS returns an HTTP 403 Forbidden response code. This doesn't provide absolute security, but if the goal is to impede inadvertent direct access by users, and to prevent indexing by search engines, this approach fits the bill nicely.

(I put up a bounty hoping that @Michael-sqlbot would provide a separate answer here on Stack Overflow so that I could reward him, as this was completely his idea. I just researched and put together the actual example policy template.)