Restrict S3 Bucket Access by Referer (domain) - Static Website Hosting - Cloudfront - amazon-web-services

I have a website hosted on S3 and Cloudfront as distribution.
I would like the bucket to be only accessed by selected domains. I followed multiple AWS documentation files that point that I should forward Referer header, but I can't get it working since I always get 403 error.
The bucket is configured to be public:
FrontendBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.frontendBucketName}
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: 404.html
RoutingRules: ${file(./redirects.json)}
CorsConfiguration:
CorsRules:
- AllowedHeaders: ["*"]
AllowedMethods: ["GET"]
AllowedOrigins: ["*"]
Id: "OpenCors"
MaxAge: "3600"
Then, in order to forward the Referer header, I have created Cloudfront Cache Policy and Cloudfront Origin Request Policy:
CloudfrontCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: cache-policy
Comment: Cache Optimized Policy (forward referer and query string)
DefaultTTL: 86400
MaxTTL: 31536000
MinTTL: 1
ParametersInCacheKeyAndForwardedToOrigin:
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Referer
QueryStringsConfig:
QueryStringBehavior: all
CloudfronOriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
Name: origin-request-policy
Comment: Origin Request Policy (forward referer query string)
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Referer
QueryStringsConfig:
QueryStringBehavior: all
Then this is my Cloudfront distribution:
CloudfrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn: [FrontendBucket]
Properties:
DistributionConfig:
Enabled: true
Comment: "(${self:provider.stage}-${opt:lang})"
Aliases: ${self:custom.domainCondition.${self:provider.stage}.${opt:lang}, self:custom.domainCondition.other}
ViewerCertificate:
AcmCertificateArn: "${self:custom.certificateCondition.${self:provider.stage}.${opt:lang}, self:custom.certificateCondition.other.${opt:lang}}"
MinimumProtocolVersion: TLSv1.2_2018
SslSupportMethod: sni-only
Origins:
- Id:
Ref: FrontendBucket
DomainName: "${self:custom.frontendBucketName}.s3-website-${self:provider.region}.amazonaws.com"
CustomOriginConfig:
OriginProtocolPolicy: http-only
HTTPPort: 80
HTTPSPort: 443
DefaultCacheBehavior:
TargetOriginId:
Ref: FrontendBucket
ViewerProtocolPolicy: redirect-to-https
Compress: true
CachePolicyId:
Ref: CloudfrontCachePolicy
OriginRequestPolicyId:
Ref: CloudfronOriginRequestPolicy
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
LambdaFunctionAssociations:
- EventType: "origin-request"
LambdaFunctionARN: ${cf.us-east-1:my-website-cle-${self:provider.stage}.RequestCLELambdaFunctionQualifiedArn}
- EventType: "origin-response"
LambdaFunctionARN: ${cf.us-east-1:my-website-cle-${self:provider.stage}.ResponseCLELambdaFunctionQualifiedArn}
As you can see, there is Origin Request Lambda#Edge assigned. I am trying to log event.Records[0].cf.request.headers there, but I can't find the referer header.
And finally this the Bucket Policy:
OnlyDomainAccessPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: FrontendBucket
PolicyDocument:
Statement:
- Sid: "Allow access to the bucket only from MiracleMill website"
Effect: Deny
Action: ["s3:GetObject", "s3:GetObjectVersion"]
Resource: "arn:aws:s3:::${self:custom.frontendBucketName}/*"
Principal: "*"
Condition:
StringNotLike:
aws:Referer:
[
"http://www.example.com/*",
"https://example.com/*",
]
//at this point this should work since the bucket is public but I have also added specific Allow
- Sid: "Allow access to the bucket only from MiracleMill website"
Effect: Allow
Action: ["s3:GetObject", "s3:GetObjectVersion"]
Resource: "arn:aws:s3:::${self:custom.frontendBucketName}/*"
Principal: "*"
Condition:
StringLike:
aws:Referer:
[
"http://www.www.example.com/*",
"https://www.example.com/*",
]

Related

CloudFront distribution can't access S3 bucket for website static assets

This question follow a previous one, i decided to close that since the code changed a bit and the question did not reflect my actual situation any more.
The problem
I'm trying to deploy an S3 bucket hosting my static website asset and a cloudfront distribution to access it, but the distribution still return a bare csv file for an 'access denied' error:
As this docs page states in the blue Notice alert, I've not made the bucket a website endpoint, this way I can use an OAC to restrict access to its content.
A strange thing is that checking the distribution origin from the web console I see this blue alert, but the copyable policy is the same I found in the bucket permission at the given link.
I have no error during deploy, so it must be a silly configuration error, but it keeps giving me headaches since a week now and I can't figure out what is wrong.
Bucket and object owners corresponds
Since mi website assets are uploaded to the bucket from a different project/pipeline i followed this guide to check if the bucket and the object owners were different but actually corresponds:
> aws s3api list-buckets --query Owner.ID
"3fdbd1e5cad4dd2bbf4c66a3dbaded6b888fdb67ff6aa6e66203a4107fe17b72"
> aws s3api list-objects --bucket my-test-bucket --prefix index.html
{
"Contents": [
{
"Key": "index.html",
"LastModified": "2023-01-20T11:05:38+00:00",
"ETag": "\"52f2df5ddf8c35391f3f15a7614def58\"",
"Size": 325,
"StorageClass": "STANDARD",
"Owner": {
"ID": "3fdbd1e5cad4dd2bbf4c66a3dbaded6b888fdb67ff6aa6e66203a4107fe17b72"
}
}
]
}
CloudFormation template
Resources:
BucketPolicy:
Type: 'AWS::S3::BucketPolicy'
DependsOn:
- AppBucket
- CloudFrontDistribution
Properties:
Bucket: !Ref AppBucket
PolicyDocument:
Id: MyPolicy
Version: '2012-10-17'
Statement:
Sid: PolicyForCloudFrontPrivateContent
Action: s3:GetObject
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
Resource: !Sub arn:aws:s3:::${AppBucket}/*
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn:
- AppBucket
- DefaultCachePolicy
- DistributionOAC
Properties:
DistributionConfig:
Enabled: true
Origins:
- Id: AppBucket
DomainName: !GetAtt AppBucket.DomainName
OriginPath: /*
S3OriginConfig: {}
OriginAccessControlId: !Ref DistributionOAC
DefaultRootObject: index.html
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
TargetOriginId: AppBucket
CachePolicyId: !Ref DefaultCachePolicy
DistributionOAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: ExampleOAC
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
AppBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: 'test-spa-stack-bucket-app'
PublicAccessBlockConfiguration:
BlockPublicAcls : false
BlockPublicPolicy : false
IgnorePublicAcls : false
RestrictPublicBuckets : false
DefaultCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: test-cache-policy
DefaultTTL: 10
MaxTTL: 10
MinTTL: 1
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: none
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: none
You aren't to have much luck without using legacy OAI (for no reason).
So, here's a policy you can use for target S3 bucket after you create the OAI right there in Cloudfront:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity INSERT_OAI_NUMBER_HERE"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::BUCKET_NAME_HERE/*"
}
]
}
After you do that, it should return expected content.
If it does work for you and you start asking why, you'd better find something better to do.
Ok, I found a YT video that worked from cloud console, then I replicated it via CloudFormation stack template.
I think that my problem could be caused from either of these configurations:
bucket encription: I read somewhere (sorry I can't find the exact page) that CloudFront distribution cannot (directly) read bucket objects if encripted with anything different from SSE-S3, and since I omitted that configuration it probably did fallback on a non-compatible configuration
objects ownership: here too I forgot to add the cuket owner enforced policy
distribution accepted http version: here I accepted v.2
working template
Resources:
BucketPolicy:
Type: 'AWS::S3::BucketPolicy'
DependsOn:
- AppBucket
- CloudFrontDistribution
Properties:
Bucket: !Ref AppBucket
PolicyDocument:
Id: PolicyForCloudFrontPrivateContent
Version: '2008-10-17'
Statement:
Sid: AllowCloudFrontServicePrincipal
Action: s3:GetObject
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
Resource: !Sub arn:aws:s3:::${AppBucket}/*
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn:
- AppBucket
- DistributionOAC
- LogsBucket
Properties:
DistributionConfig:
Enabled: true
HttpVersion: http2
Origins:
- Id: AppBucket
DomainName: !GetAtt AppBucket.DomainName
S3OriginConfig: {}
OriginAccessControlId: !Ref DistributionOAC
DefaultRootObject: index.html
DefaultCacheBehavior:
Compress: true
ViewerProtocolPolicy: allow-all
TargetOriginId: AppBucket
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # default CachingOptimized
Logging:
Bucket: !GetAtt LogsBucket.DomainName
IncludeCookies: true
Prefix: distribution/
AppBucket:
Type: 'AWS::S3::Bucket'
DependsOn:
- LogsBucket
Properties:
BucketName: 'test-spa-stack-bucket-app'
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced
PublicAccessBlockConfiguration:
BlockPublicAcls : true
BlockPublicPolicy : true
IgnorePublicAcls : true
RestrictPublicBuckets : true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
LoggingConfiguration:
DestinationBucketName: !Ref LogsBucket
LogFilePrefix: app/
DistributionOAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: test-spa-distribution-oac
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
LogsBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: 'test-spa-stack-bucket-logs'
PublicAccessBlockConfiguration:
BlockPublicAcls : true
BlockPublicPolicy : true
IgnorePublicAcls : true
RestrictPublicBuckets : true
AccessControl: LogDeliveryWrite
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'

Cloudformation template - S3 bucket website with cloudfront distribution - distribution can't access origin

I'm just trying to get a static site on a S3 bucket and have it being accessible only trough a CloudFront distribution, but something is missing and I cannot figure out what.
Currently my stack have
an S3 bucket for site hosting
a cloudfront distribution for serving the site
a bucket policy to let only the distribution accessing the bucket
a default cache policy for the distribution
When trying to access the website directly from the bucket website url I get a 403 (forbidden, access denied) and that's ok.
When trying to access it from the distribution domain I get a generic error page with the message Failed to contact the origin.
When trying to access it from my registered domain I get a 403 error page with the message The request could not be satisfied. followed by generics tips on how to fix it (login later, contact website owner, check documentation, etc)
Since I'm using CloudFormation template from my cli every resource is in the same region, and everything else too looks right to me, but obviously something is wrong.
CloudFormation template
Resources:
BucketPolicy:
Type: 'AWS::S3::BucketPolicy'
DependsOn:
- AppBucket
- CloudFrontDistribution
Properties:
Bucket: !Ref AppBucket
PolicyDocument:
Id: MyPolicy
Version: '2012-10-17'
Statement:
- Sid: PolicyForCloudFrontPrivateContent
Action: s3:GetObject
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Condition:
StringLike:
aws:Referer: !Sub 'https://*.${CloudFrontDistribution}.cloudfront.net/*'
Resource: !Sub arn:aws:s3:::${AppBucket}/*
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn:
- AppBucket
- DefaultCachePolicy
Properties:
DistributionConfig:
Enabled: true
Origins:
- Id: AppBucket
DomainName: !GetAtt AppBucket.DomainName
OriginPath: /*
S3OriginConfig: {}
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
TargetOriginId: AppBucket
CachePolicyId: !Ref DefaultCachePolicy
AppBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: 'test-spa-stack-bucket-app'
PublicAccessBlockConfiguration:
BlockPublicAcls : false
BlockPublicPolicy : false
IgnorePublicAcls : false
RestrictPublicBuckets : false
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
WebsiteConfiguration:
IndexDocument: index.html
DefaultCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: test-cache-policy
DefaultTTL: 10
MaxTTL: 10
MinTTL: 1
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: none
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: none
Your bucket policy seems wrong.
You need to allow Origin access control of your CloudFront distribution to access the S3 bucket.
{
"Version": "2012-10-17",
"Statement": {
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
}
}
}
}
You also need to provide the same origin access control id in your CloudFront distribution definition:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn:
- AppBucket
- DefaultCachePolicy
Properties:
DistributionConfig:
Enabled: true
Origins:
- Id: AppBucket
DomainName: !GetAtt AppBucket.DomainName
OriginPath: /*
OriginAccessControlId: "EDFDVBD6EXAMPLE" <- PROVIDE ID HERE
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
TargetOriginId: AppBucket
CachePolicyId: !Ref DefaultCachePolicy
See Restricting access to an Amazon S3 origin

How to get the CloudFront distribution ARN in a CloudFormation stack for WebACLAssociation?

I've setup a CloudFront distribution in CloudFormation and I'm building an AWS WAF ACL to act as a firewall for it. To associate the ACL to the CloudFront distribution, I've added a AWS::WAFv2::WebACLAssociation entry which requires the ARN of the CloudFront distribution for the ResourceArn entry. However, I can't seem to find out how to get the CloudFront distribution ARN from the official documentation. I thought I could use !Ref however it used the CloudFront ID as per the documentation instead of the ARN.
How do I reference the CloudFront distribution ARN from the WebACLAssociation entry?
Example below (other resources omitted for brevity):
---
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront
Parameters:
# ...
CloudFront:
Type: AWS::CloudFront::Distribution
DependsOn:
- IssuedCertificate
- S3Bucket
Properties:
DistributionConfig:
Origins:
- DomainName: !Sub
- ${S3Bucket}.${S3WebEndpoint}
- {
S3Bucket: !Ref S3Bucket,
S3WebEndpoint:
!FindInMap [RegionMap, !Ref "AWS::Region", websiteendpoint],
}
Id: S3origin
CustomOriginConfig:
OriginProtocolPolicy: http-only
Enabled: "true"
Comment: !Sub Distribution for ${DomainName}
HttpVersion: http2
Aliases:
- !Ref DomainName
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
TargetOriginId: S3origin
Compress: True
DefaultTTL: 604800
ForwardedValues:
QueryString: "false"
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_100
ViewerCertificate:
AcmCertificateArn: !Ref Certificate
SslSupportMethod: sni-only
# ...
AWSWAF:
Type: AWS::WAFv2::WebACL
Properties:
Name: allowlist
Description: Allowlist
Scope: CLOUDFRONT
DefaultAction:
Block: {}
Rules:
- Name: ipset-rule
Priority: 0
Action:
Allow: {}
Statement:
IPSetReferenceStatement:
Arn: # <ARN>
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: ipset-metrics
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: allowlist-metrics
AWSWAFAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
ResourceArn: !Ref CloudFront
WebACLArn: !Ref AWSWAF
There is no direct Attribute for the same but you can construct it:
arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFront}
Turns out I had been approaching the problem wrong all along. Diving into the docs, I found that AWS details how to deploy an ACL for a CloudFront distribution here under the ResouceArn entry.
To fix this issue, all I had to do was add the following to the CloudFront distribution DistributionConfig and remove the WebACLAssociation entry:
WebACLId: !GetAtt AWSWAF.Arn
So the final CloudFront entry looked like this:
CloudFront:
Type: AWS::CloudFront::Distribution
DependsOn:
- IssuedCertificate
- S3Bucket
Properties:
DistributionConfig:
Origins:
- DomainName: !Sub
- ${S3Bucket}.${S3WebEndpoint}
- {
S3Bucket: !Ref S3Bucket,
S3WebEndpoint:
!FindInMap [RegionMap, !Ref "AWS::Region", websiteendpoint],
}
Id: S3origin
CustomOriginConfig:
OriginProtocolPolicy: http-only
Enabled: "true"
Comment: !Sub Distribution for ${DomainName}
HttpVersion: http2
Aliases:
- !Ref DomainName
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
TargetOriginId: S3origin
Compress: True
DefaultTTL: 604800
ForwardedValues:
QueryString: "false"
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_100
ViewerCertificate:
AcmCertificateArn: !Ref Certificate
SslSupportMethod: sni-only
WebACLId: !GetAtt AWSWAF.Arn

Access Denied error on s3 with cloudfront

I'm starting to build a infrastructure on AWS, the first step is to make a Cloud Front service work with two different S3 buckets (I'm uploading a simple index.html to each bucket). For that I've made the following yaml to deploy via Cloud Formation.
AWSTemplateFormatVersion: "2010-09-09"
Resources:
UserBucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: my-user-bucket
Tags:
- Key: description
Value: "User page files"
AdminBucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: my-admin-bucket
Tags:
- Key: description
Value: "Admin page files"
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: 'origin identity'
UserBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: my-user-bucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- 's3:GetObject'
Effect: Allow
Principal:
AWS:
Fn::Join:
- " "
-
- "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity"
-
!Ref CloudFrontOriginAccessIdentity
Resource:
- !Sub arn:aws:s3:::my-user-bucket/*
DependsOn:
- UserBucket
AdminBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: my-admin-bucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- 's3:GetObject'
Effect: Allow
Principal:
AWS:
Fn::Join:
- " "
-
- "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity"
-
!Ref CloudFrontOriginAccessIdentity
Resource:
- !Sub arn:aws:s3:::my-admin-bucket/*
DependsOn:
- AdminBucket
PublicDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: my-user-bucket.s3.sa-east-1.amazonaws.com
Id: S3-my-user-bucket
S3OriginConfig:
OriginAccessIdentity:
'Fn::Join':
- ''
- - origin-access-identity/cloudfront/
- Ref: CloudFrontOriginAccessIdentity
- DomainName: my-admin-bucket.s3.sa-east-1.amazonaws.com
Id: S3-my-admin-bucket
S3OriginConfig:
OriginAccessIdentity:
'Fn::Join':
- ''
- - origin-access-identity/cloudfront/
- Ref: CloudFrontOriginAccessIdentity
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
TargetOriginId: S3-my-user-bucket
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: allow-all
CacheBehaviors:
- PathPattern: user/*
AllowedMethods:
- GET
- HEAD
TargetOriginId: S3-my-user-bucket
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: allow-all
- PathPattern: admin/*
AllowedMethods:
- GET
- HEAD
TargetOriginId: S3-my-admin-bucket
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: allow-all
Enabled: 'true'
Comment: Some comment
DefaultRootObject: index.html
ViewerCertificate:
CloudFrontDefaultCertificate: 'true'
DependsOn:
- UserBucketPolicy
- AdminBucketPolicy
As you can see I'm trying to redirect the requests for user and admin using the Cloud Front Distribution behavior configuration.
I'm able to access the index.html file at foobar.cloudfront.net, for me that means that the OAI is working fine. But both foobar.cloudfront.net/admin/index.html and foobar.cloudfront.net/user/index.html returns the error bellow, so I'm thinking that theres something wrong with the behavior and/or path:
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>YRCKS4PAV9C11CR9</RequestId>
<HostId>N9d3NJLrwZY1bECeTmXoQqRuDljsgFQk3C9pt5AX2pZyI4BEhTMCvJDB1uUAaQ4zUlppbvQbyOs=</HostId>
</Error>
Any ideas of what is wrong?
I believe you need to update your BucketPolicies to include both:
Action:
- 's3:GetObject'
- 's3:ListObjects'
and
Resource to be both:
"arn:aws:s3:::my-user-bucket/",
"arn:aws:s3:::my-user-bucket/*"

AWS Cloudfront does not render S3 bucket on the domain alias

I have my static website content put on S3, it has been given public permission and if I visit
http://subdomain.mydomain.com.s3-website-us-east-1.amazonaws.com I see the HTML.
In the Certificate Manager, I have a valid certificate generated for subdomain.mydomain.com
Now is the turn of CloudFront,
picked the correct AWS S3 bucket folder.
bucked hosted in North Virginia
Associated the subdomian certificate
in document root filled the index.html
other settings in place.
Once the site is deployed, I open <cloudfront-random-string>.cloudfront.net
This renders the Static Website as is.
Finally, I head to route53, in the A record I create an alias and insert the <cloudfront-random-string>.cloudfront.net
When I open the subdomain.mydomain.com it renders no response.
What could go wrong?
Not sure if you are getting a 403, but this article may help.
https://aws.amazon.com/premiumsupport/knowledge-center/s3-website-cloudfront-error-403/
Alternatively, you could try creating a Cloudfront Origin Access Identity & give it permission to access your S3 bucket. This way you can keep your S3 bucket private too.
WebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${DomainName}
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
Tags:
- Key: Domain
Value: !Ref DomainName
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub CloudFront OAI for ${DomainName}
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref WebsiteBucket
PolicyDocument:
Statement:
- Action:
- s3:GetObject
Effect: Allow
Resource: !Join [ "", [ "arn:aws:s3:::", !Ref WebsiteBucket, "/*" ] ]
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
WebsiteCloudFront:
Type: AWS::CloudFront::Distribution
DependsOn:
- WebsiteBucketPolicy
Properties:
DistributionConfig:
Comment: Cloudfront Distribution pointing to S3 bucket
Origins:
- DomainName: !GetAtt WebsiteBucket.DomainName
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity:
!Join [ "", [ "origin-access-identity/cloudfront/", !Ref CloudFrontOriginAccessIdentity ] ]
Enabled: true
HttpVersion: 'http2'
DefaultRootObject: index.html
Aliases:
- !Ref DomainName
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
Compress: true
TargetOriginId: S3Origin
ForwardedValues:
QueryString: true
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_100
ViewerCertificate:
AcmCertificateArn: !Ref AcmCertificateArn
SslSupportMethod: sni-only