S3 content delivery via CloudFront – OAI ver

TOC

Restricting access to origin with OAI when delivering S3 content from CloudFront

The following page shows how to restrict access to origin by using the Referer header when delivering S3 bucket content from CloudFront.

あわせて読みたい
S3 content delivery via CloudFront – Referer hreader ver 【Restricting access to origin with Referer header when delivering S3 content from CloudFront】 The following page shows how to deliver content from an S3 bu...

However, there is one issue with the above configuration.
If the appropriate value is set in the Referer header, it is possible to access the origin directly.

To solve this problem, we will use an Origin Access Identity (OAI).

Create a special CloudFront user called an origin access identity (OAI) and associate it with your distribution.

Configure your S3 bucket permissions so that CloudFront can use the OAI to access the files in your bucket and serve them to your users.

Restricting access to Amazon S3 content by using an origin access identity (OAI)

A quick comparison of how to use OAI vs. using a Referer header.

ItemOAIReferer header
Static Website HostingNot RequiredRequired
Endpoint as OriginREST API EndpointWebsite Endpoint
Document Root ObjectRequiredNot Required
Bucket PolicySet OAI user as principalSet Condition to check Referer header

Environment

Diagram of S3 content delivery via CloudFront - OAI ver

The overall configuration is the same as before.
Create an OAI for CloudFront and set the S3 bucket policy to allow access from OAI users.

CloudFormation template files

The above configuration is built using CloudFormation.
The CloudFormation templates are located at the following URL

https://github.com/awstut-an-r/awstut-fa/tree/main/050

Explanation of key points of template files

This page focuses on how to restrict access to the origin using OAI.
For other contents, please refer to the page mentioned at the beginning of this document.

Static website hosting is not required

Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref Prefix
      AccessControl: Private
      #WebsiteConfiguration:
      #  IndexDocument: index.html
Code language: YAML (yaml)

Static Website Hosting does not need to be enabled in order to use OAI.

You don’t need to enable static website hosting on your bucket for this configuration.

How do I use CloudFront to serve a static website hosted on Amazon S3?

So I have commented out the relevant code.

Organizing S3 bucket endpoint

Let’s review the characteristics of the two endpoints of the S3 bucket.

ItemREST API EndpointWebsite Endpoint
FormatDOC-EXAMPLE-BUCKET.s3.region.amazonaws.comDOC-EXAMPLE-BUCKET.s3.amazonaws.comDOC-EXAMPLE-BUCKET.s3-website-region.amazonaws.com
HTTP/HTTPSHTTPSHTTP
How to get value with CFN!GetAtt Bucket.RegionalDomainName!GetAtt Bucket.DomainName!GetAtt Bucket.WebsiteURL

As mentioned at the beginning of this section, when using OAI, specify a REST API endpoint as the CloudFront origin.

This configuration uses the REST API endpoint of the bucket instead of the website endpoint from the static website hosting feature.

How do I use CloudFront to serve a static website hosted on Amazon S3?

Next, we turn our attention to the REST API endpoint.
There are two formats available for REST API endpoints, but the one that includes region information is preferred.

When you specify an Amazon S3 bucket as an origin for CloudFront, we recommend that you use the following format:

bucket-name.s3.region.amazonaws.com

Using various origins with CloudFront distributions

Following the above, we will use this format in this case.

Let’s see how to get the value for this format.
This value can be obtained using CloudFormation’s built-in function Fn::GetAtt with “!GetAtt Bucket.RegionalDomainName”.

OAI

Resources:
  OAI:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: !Ref Prefix
Code language: YAML (yaml)

Define OAI.
Configuration items are limited and only the Comment property is available.

Let us review the concept of OAI.
OAI can be regarded as a kind of IAM user.
It is a special user associated with the CloudFront distribution, and when a request is received from an end user, OAI accesses the S3 bucket on behalf of the user.

Diagram of users accessing S3 buckets when using OAI.

CloudFront requires configuration of document root object

Resources:
  Distribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        DefaultCacheBehavior:
          AllowedMethods:
            - GET
            - HEAD
          CachedMethods:
            - GET
            - HEAD
          Compress: true
          ForwardedValues:
            Cookies:
              Forward: none
            QueryString: false
          TargetOriginId: !Ref BucketName
          ViewerProtocolPolicy: allow-all
        DefaultRootObject: index.html
        Enabled: true
        Origins:
          - DomainName: !Ref BucketRegionalDomainName
            Id: !Ref BucketName
            S3OriginConfig:
              OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${OAI}"
            #CustomOriginConfig:
        PriceClass: PriceClass_All
Code language: YAML (yaml)

There are two points.

The first is the default route object.
This setting is mandatory.

If your distribution doesn’t have a default root object defined, and a requester doesn’t have s3:ListBucket access, then the requester receives an Access Denied error. The requester gets this error instead of a 404 Not Found error when they request the root of your distribution.

I’m using an S3 REST API endpoint as the origin of my CloudFront distribution. Why am I getting 403 Access Denied errors?

Follow the above instructions to set up a file named index.html as the root object.
This file is automatically generated by executing the Lambda function in the CloudFormation custom resource.
For more details, please refer to the following page

あわせて読みたい
Create and Delete S3 Object by CFN Custom Resource 【How to create/delete S3 objects during stack creation/deletion with CloudFormation custom resources】 CloudFormation custom resources can perform any actio...

The second point is to set the origin.
First, the origin is specified inside the Origins property.
In the DomainName property, specify a REST API endpoint in a format that includes the region information described above.
Next, configure the S3OriginConfig property for origin details.
When using the Referer header, we set the CustomOriginConfig property, but not this time.

Use S3OriginConfig to specify an Amazon S3 bucket that is not configured with static website hosting.

Use CustomOriginConfig to specify all other kinds of origins

AWS::CloudFront::Distribution Origin

Select the S3OriginConfig property as described above.
This property provides a property to set the OAI called OriginAccessIdentity property.
The description is as follows

The format of the value is:

origin-access-identity/cloudfront/ID-of-origin-access-identity

AWS::CloudFront::Distribution S3OriginConfig

Follow the above and use the built-in function Fn::Sub to create the string.

Specify OAI as the bucket policy principal

Resources:
  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref BucketName
      PolicyDocument:
        Statement:
          Action:
            - s3:GetObject
          Effect: Allow
          Principal:
            AWS: !Sub "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${OAI}"
          Resource: !Sub "arn:aws:s3:::${BucketName}/*"
          #Condition:
Code language: YAML (yaml)

Restrict users who can access the bucket with a bucket policy.
This time, use the Principal property instead of Condition.
This time, we will use the Principal property instead of Condition, and set OAI as the user for this property.
Specifically, configure as follows

arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity [OAI-id]

Restricting access to Amazon S3 content by using an origin access identity (OAI)

Architecting

Use CloudFormation to build this environment and verify actual behavior.

Create CloudFormation stacks and check resources in stacks

Create a CloudFormation stacks.
For information on how to create stacks and check each stack, please refer to the following page

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

After checking the resources in each stack, information on the main resources created this time is as follows

  • S3 bucket: fa-050
  • CloudFront distribution domain: https://d38ixdp3esygfv.cloudfront.net/
  • Name of OAI: fa-050
  • ID of OAI: E3A4FYJVN7KUC8

The resources are also checked from the AWS Management Console.
First is CloudFront.

CloudFront settings.

An S3 bucket is set as the origin.
A REST API endpoint of the type including the region is specified.
You can also see that the bucket is configured to use OAI (fa-050) when accessing it.

Specify index.html as Default root object.

The default route object is set to index.html.
This means that accessing “https://d38ixdp3esygfv.cloudfront.net/” will act as if you accessed “https://d38ixdp3esygfv.cloudfront.net/index.html”.

Next, check the S3 bucket policy.

Specify OAI as the principal of the bucket policy.

The ID of OAI is specified as before.
The policy says that access to the object is allowed when accessing from this OAI.

Static website hosting functionality is disabled.

Note that the static website hosting function is not enabled.

Confirmation of Operation

Now that everything is ready, access the CloudFront distribution.

Result when accessing S via CloudFront.

The contents of the S3 bucket are now displayed.
It means that you are accessing the REST API endpoint of the origin S3 bucket via CloudFront.

Of course, you cannot access the S3 bucket directly.

Result of direct S3 bucket access.

This method of using OAI is more secure because it does not rely on header information.

Summary

We have shown how to use OAI to force access via CloudFront when delivering content in S3 buckets.

TOC