Last active
February 17, 2024 21:33
-
-
Save chris/bf8997c954ca6a7eef97a0ceb5b1085e to your computer and use it in GitHub Desktop.
S3 CloudFront Custom Domain CloudFormation example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# S3 bucket for a web files, with CloudFront and custom domain. | |
# | |
# The bucket is setup to be private, only accessible via CloudFront. | |
# This uses a CloudFront OAI to provide access to the bucket, and also restricts | |
# access to be SSL/HTTPS only. | |
# The SSL cert was created manually, as it has to be created in us-east-1 for | |
# use with CloudFront, and there is no way to specify a region in CloudFormation | |
# when creating a cert. | |
# Finally it does Route53 DNS setup for the subdomain pointed at/for use with | |
# the CloudFront distribution. | |
# | |
Mappings: | |
SSLCertsMap: | |
dev: | |
certArn: arn:aws:acm:us-east-1:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |
production: | |
certArn: arn:aws:acm:us-east-1:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |
Resources: | |
MyFilesBucket: | |
Type: AWS::S3::Bucket | |
DeletionPolicy: Retain | |
Properties: | |
BucketName: myfiles.${param:domainName} | |
WebsiteConfiguration: | |
IndexDocument: index.html | |
ErrorDocument: error.html | |
AccessControl: BucketOwnerFullControl | |
myfilesCloudFrontOAI: | |
Type: 'AWS::CloudFront::CloudFrontOriginAccessIdentity' | |
Properties: | |
CloudFrontOriginAccessIdentityConfig: | |
Comment: 'OAI for S3 origins' | |
MyFilesBucketPolicy: | |
Type: AWS::S3::BucketPolicy | |
Properties: | |
Bucket: | |
Ref: MyFilesBucket | |
PolicyDocument: | |
Statement: | |
- Action: 's3:GetObject' | |
Effect: Allow | |
Resource: !Sub '${MyFilesBucket.Arn}/*' | |
Principal: | |
CanonicalUser: !GetAtt myfilesCloudFrontOAI.S3CanonicalUserId | |
# deny access for non SSL/HTTPS access to the S3 bucket | |
- Sid: AllowSSLRequestsOnly | |
Effect: Deny | |
Principal: '*' | |
Action: 's3:*' | |
Resource: | |
- !Sub '${MyFilesBucket.Arn}' | |
- !Sub '${MyFilesBucket.Arn}/*' | |
Condition: | |
Bool: | |
'aws:SecureTransport': false | |
myfilesCloudFrontDistribution: | |
Type: 'AWS::CloudFront::Distribution' | |
Properties: | |
DistributionConfig: | |
Comment: CloudFront distribution for S3 bucket for myfiles | |
Origins: | |
- DomainName: !GetAtt MyFilesBucket.RegionalDomainName | |
Id: 'S3Origin-myfiles-${param:domainName}' | |
S3OriginConfig: | |
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${myfilesCloudFrontOAI}' | |
Aliases: | |
- myfiles.${param:domainName} | |
# Need CloudFront to replace HTTP status codes in the 4xx and 5xx range | |
# with custom error messages before returning the response to the viewer, | |
# due to difference in S3 error codes. | |
CustomErrorResponses: | |
- ErrorCode: 403 # 403 from S3 indicates that the file does not exists | |
ResponseCode: 404 # HTTP status code that CloudFront will return | |
ResponsePagePath: '/error.html' # you must upload/add this file to the bucket | |
ErrorCachingMinTTL: 60 # min cache time in seconds | |
DefaultCacheBehavior: | |
AllowedMethods: | |
- GET | |
- HEAD | |
- OPTIONS | |
CachedMethods: | |
- GET | |
- HEAD | |
- OPTIONS | |
Compress: true | |
DefaultTTL: 3600 # in seconds, 1 hour | |
ForwardedValues: | |
QueryString: false | |
Cookies: | |
Forward: none | |
MaxTTL: 86400 # in seconds, 24 hours | |
MinTTL: 60 # in seconds, 1 min | |
TargetOriginId: 'S3Origin-myfiles-${param:domainName}' | |
ViewerProtocolPolicy: 'redirect-to-https' | |
DefaultRootObject: 'index.html' | |
Enabled: true | |
HttpVersion: http2 | |
PriceClass: PriceClass_All | |
ViewerCertificate: | |
AcmCertificateArn: !FindInMap [ SSLCertsMap, '${self:provider.stage}', certArn] | |
SslSupportMethod: sni-only | |
myfilesBucketDNS: | |
Type: AWS::Route53::RecordSetGroup | |
Properties: | |
HostedZoneName: ${param:domainName}. | |
RecordSets: | |
- Name: myfiles.${param:domainName} | |
Type: A | |
AliasTarget: | |
DNSName: !GetAtt myfilesCloudFrontDistribution.DomainName | |
HostedZoneId: Z2FDTNDATAQYW2 # do not change! Special ID provided by AWS for CloudFront distribution. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment