aws / aws/aws-cdk

(@aws-cdk/cloudfront_origins): S3Origin synths an incorrect domain url and no OAI association for buckets with public access disabled, and static hosting enabled

Open
#19,539 7 comments 4 reactions 0 assignees View on GitHub
@aws-cdk/aws-cloudfront-origins bug effort/small p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
1d 19h
Merged PRs (30d)
71

Description

### What is the problem?

# TL;DR
Using @aws-cdk/cloudfront_origins S3Origin results in an origin that is unreachable (403 Forbidden) if the bucket has public access disabled and static hosting enabled. From the [code](https://github.com/aws/aws-cdk/blob/3c9ea5f31e3113fb0d2ba5c633fcd665294a70eb/packages/%40aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts#L34) there is a check to see if the bucket is a static hosted website and creating an HTTPOrigin if it is. The problem is that HTTPOrigin's don't allow for OAI's to access bucket contents... which is needed if the bucket has public access disabled.

# Background
I'm contributing an update to the aws-cdk-examples repo for static sites hosted on s3 here -> https://github.com/its-mirus-lu/aws-cdk-examples/tree/fix_static_site_distro/typescript/static-site using CDK v2

I noticed that when I deploy the app, I'm getting 403 errors when trying to hit the website both via the CNAME registered in Route53 and via the Cloudfront endpoint.

Digging into the synthesized Cloudformation, I discovered that the distribution definition is missing an OAI association even through the CDK code uses the S3Origin class with the OAI defined in the props.

I discovered through the AWS Console that the URL was incorrect (the static website url was used instead of the REST url) which also prevented the OAI from being associated.

### Reproduction Steps

1) Attempt to create a stack with an S3 bucket with static hosting enabled and with public access denied
2) Create an OAI and grant it getObject permission in the bucket policy
3) Create a Cloudfront distribution and define a defaultBehavior with an S3Origin as its props (using the bucket and OAI defined previously)
4) Attempt to deploy

All the above steps can be found here: https://github.com/its-mirus-lu/aws-cdk-examples/tree/fix_static_site_distro/typescript/static-site

### What did you expect to happen?

For s3 buckets that host static content that have public access disabled, the following must be configured:

1) the origin's domain should be the s3 rest url, not the s3 static website url
2) an OAI should be associated with the origin in Cloudfront
3) the website can be navigated to without error

Note: Here is a link to an article on AWS about debugging 403 errors in Cloudfront and S3... the specific excerpt is:

"If you don't want to allow public (anonymous) access to your S3 objects, then change your configuration to use the S3 REST API endpoint as the origin of your distribution. Then, configure your distribution and S3 bucket to restrict access using an origin access identity (OAI). For instructions, see Using a REST API endpoint as the origin with access restricted by an OAI"

This is the URL that is synthed .s3-website.us-east-1.amazonaws.com
This is the URL that should be synthed .s3.us-east-1.amazonaws.com

### What actually happened?

If I visit the Cloudfront section in the AWS console I see the following:

1) Navigate to the Cloudfront section of the AWS Console:
2) the origin's domain is the s3 static website url (it should be the s3 bucket's REST endpoint)
3) there is no option for OAI association (I only see the option when I change the origin domain to point to the s3 bucket's REST url)
4) The OriginConfig that is synthed is a CustomOriginConfig and not an S3OriginConfig as expected

Furthermore, looking at the synthesized Cloudformation, I do not see an OAI associated with the origin, and the domain used is the static website URL

```
"Origins": [
{
"CustomOriginConfig": {
"OriginProtocolPolicy": "http-only",
"OriginSSLProtocols": [
"TLSv1.2"
]
},
"DomainName": {
"Fn::Select": [
2,
{
"Fn::Split": [
"/",
{
"Fn::GetAtt": [
"StaticSiteSiteBucket1A888BC8",
"WebsiteURL"
]
}
]
}
]
},
"Id": "MyStaticSiteSiteDistributionOrigin1782C1326"
}
],
```

Looking at the actual code for [S3Origin](https://github.com/aws/aws-cdk/blob/3c9ea5f31e3113fb0d2ba5c633fcd665294a70eb/packages/%40aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts#L34) the constructor actually returns an HTTPOrigin (instead of an S3Origin) if the bucket has static hosting enabled. The solution for this would be to do an 'and' so the test condition becomes

`this.origin = bucket.isWebsite && bucket.?` where isPublicRead is a helper function to determine if public read is enabled.

### CDK CLI Version

2.13.0

### Framework Version

_No response_

### Node.js Version

16.14.0

### OS

12.2.1

### Language

Typescript

### Language Version

TS 3.9.7

### Other information

The workaround is that static hosting should be disabled for any s3 hosting static website content that has public read disabled.

Contributor guide

Open the contributing guide

Research direction

Start with packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts and compare the S3Origin behavior with the supplied static-site reproduction. Inspect the synthesized CloudFormation for the origin domain, origin type, and OAI association. Done means private, static-hosted buckets use the S3 REST endpoint with an OAI and the CloudFront site is reachable without 403 errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
cloud, infrastructure
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.