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'
Related
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
I have activated AWSSamples::S3BucketEncrypt::Hook with the following configuration but S3 bucket creation with encryption enabled seems to be failing because of the hook.
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
"minBuckets": "1",
"encryptionAlgorithm": "AES256"
}
}
}
}
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
"minBuckets": "1",
"encryptionAlgorithm": "aws:kms"
}
}
}
}
The following CloudFormation stacks are supposed to pass but they are failing. They only seem to work when I disable the hook. I have checked the trust policy, which seems fine for CloudFormation to access the hook and S3 bucket.
AWSTemplateFormatVersion: 2010-09-09
Description: S3 bucket with default encryption
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
DeletionPolicy: Delete
AWSTemplateFormatVersion: "2010-09-09"
Description: This CloudFormation template provisions an encrypted S3 Bucket
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'aws:kms'
KMSMasterKeyID: !Ref EncryptionKey
BucketKeyEnabled: true
Tags:
- Key: "keyname1"
Value: "value1"
EncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key used to encrypt the resource type artifacts
EnableKeyRotation: true
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: Enable full access for owning account
Effect: Allow
Principal:
AWS: !Ref "AWS::AccountId"
Action: kms:*
Resource: "*"
Outputs:
EncryptedBucketName:
Value: !Ref EncryptedS3Bucket
There were multiple issues
The role need to be created using https://github.com/aws-cloudformation/aws-cloudformation-samples/blob/main/hooks/python-hooks/s3-bucket-encryption/hook-role.yaml
CF Hook Configuration need to be the following
KMS
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
"minBuckets": "1",
"encryptionAlgorithm": "aws:kms"
}
}
}
}
3.1 Use the following CF to create SSE-S3 bucket for point no 3
AWSTemplateFormatVersion: "2010-09-09"
Description: This CloudFormation template provisions an encrypted S3 Bucket
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'aws:kms'
KMSMasterKeyID: !Ref EncryptionKey
BucketKeyEnabled: true
Tags:
- Key: "keyname1"
Value: "value1"
EncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key used to encrypt the resource type artifacts
EnableKeyRotation: true
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: Enable full access for owning account
Effect: Allow
Principal:
AWS: !Ref "AWS::AccountId"
Action: kms:*
Resource: "*"
Outputs:
EncryptedBucketName:
Value: !Ref EncryptedS3Bucket
OR
SSE-S3
AWSTemplateFormatVersion: 2010-09-09
Description: S3 bucket with default encryption
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'aesencryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
DeletionPolicy: Delete
4.1 Use the following CF to create SSE-S3 bucket for point no 4
AWSTemplateFormatVersion: "2010-09-09"
Description: This CloudFormation template provisions an encrypted S3 Bucket
Resources:
EncryptedS3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'encryptedbucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
BucketKeyEnabled: true
Tags:
- Key: "keyname1"
Value: "value1"
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/*",
]
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
I'm trying to create a Yaml template for cloudfront distribution on S3 bucket.
I'm stuck on how to add principal on BucketPolicy.
I want to know how to replace the XXXXXXXXXXX on CloudFront Origin Access Identity XXXXXXXXXXX in principal for a cloudfront that will be generate by deploying the template.
Also is there a way to add the html, css sync procedure (which I'm doing through aws cli now) on yaml template?
Please let me know.
TIA
AWSTemplateFormatVersion: 2010-09-09
Resources:
Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: pridesys.webbucket
AccessControl: Private
WebsiteConfiguration:
IndexDocument: index.html
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Bucket
PolicyDocument:
Id: ReportPolicy
Version: "2012-10-17"
Statement:
- Sid: "1"
Effect: Allow
Action: "s3:GetObject"
Principal:
AWS: "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
Resource: !Join ['', ['arn:aws:s3:::', !Ref Bucket, '/*']]
Distro:
Type: 'AWS::CloudFront::Distribution'
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt Bucket.DomainName
Id: foo
S3OriginConfig: {}
Enabled: True
DefaultRootObject: index.html
DefaultCacheBehavior:
ForwardedValues:
QueryString: False
TargetOriginId: foo
ViewerProtocolPolicy: allow-all
Here is a valid sample of an S3 origin identity configuration for CloudFront:
WebUIBucket:
Type: AWS::S3::Bucket
CloudFrontOriginIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: "origin identity"
WebUIPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WebUIBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
CanonicalUser:
Fn::GetAtt: [ CloudFrontOriginIdentity , S3CanonicalUserId ]
Action: "s3:GetObject"
Resource: !Sub "${WebUIBucket.Arn}/*"
WebpageCDN:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !Sub "${WebUIBucket}.s3.amazonaws.com"
Id: webpage
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginIdentity}"
As for the syncing your assets into the S3 bucket, that cannot be provided with CloudFormation functionality. You either have to implement a CustomResource or keep using the CLI.
Thanks a lot #Jens !!
Your solution was a big help. I was getting TargetOriginId & ForwarededValues error while trying to deploy your template.
This is what worked for me -
AWSTemplateFormatVersion: '2010-09-09'
Description: An AWS Serverless Specification template describing your function.
Resources:
WebUIBucket:
Type: AWS::S3::Bucket
CloudFrontOriginIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: "origin identity"
WebUIPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WebUIBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
CanonicalUser:
Fn::GetAtt: [ CloudFrontOriginIdentity , S3CanonicalUserId ]
Action: "s3:GetObject"
Resource: !Sub "${WebUIBucket.Arn}/*"
WebpageCDN:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !Sub "${WebUIBucket}.s3.amazonaws.com"
Id: webpage
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginIdentity}"
Enabled: True
DefaultRootObject: index.html
DefaultCacheBehavior:
ForwardedValues:
QueryString: False
TargetOriginId: webpage
ViewerProtocolPolicy: allow-all
Transform: AWS::Serverless-2016-10-31
So you will need to have S3 origin Access Identity setup, and use the !GetAtt S3CanonicalUserId
Here is my code and it works
S3CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: A comment to describe the origin access identity. The comment cannot be longer than 128 characters.
StagingCloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt myS3bucket.DomainName
Id: !Ref myS3bucket
S3OriginConfig:
OriginAccessIdentity: !Join ['', ['origin-access-identity/cloudfront/', !Ref S3CloudFrontOriginAccessIdentity]]
myS3BucketPolicy:
Type: 'AWS::S3::BucketPolicy'
Properties:
Bucket: !Ref myS3bucket
PolicyDocument:
Id: myS3bucketPolicy
Version: 2012-10-17
Statement:
- Sid: PutObjectAccess
Effect: Allow
Principal:
CanonicalUser:
Fn::GetAtt: [ S3CloudFrontOriginAccessIdentity, S3CanonicalUserId ]
Action:
- s3:GetObject
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref myS3bucket
- /*