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.
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.
Item | OAI | Referer header |
Static Website Hosting | Not Required | Required |
Endpoint as Origin | REST API Endpoint | Website Endpoint |
Document Root Object | Required | Not Required |
Bucket Policy | Set OAI user as principal | Set Condition to check Referer header |
Environment
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.
Item | REST API Endpoint | Website Endpoint |
Format | DOC-EXAMPLE-BUCKET.s3.region.amazonaws.comDOC-EXAMPLE-BUCKET.s3.amazonaws.com | DOC-EXAMPLE-BUCKET.s3-website-region.amazonaws.com |
HTTP/HTTPS | HTTPS | HTTP |
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.
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
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
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.
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.
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.
The ID of OAI is specified as before.
The policy says that access to the object is allowed when accessing from this OAI.
Note that the static website hosting function is not enabled.
Confirmation of Operation
Now that everything is ready, access the CloudFront distribution.
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.
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.