Skip to content

Instantly share code, notes, and snippets.

@chris
Last active February 17, 2024 21:33
Show Gist options
  • Save chris/bf8997c954ca6a7eef97a0ceb5b1085e to your computer and use it in GitHub Desktop.
Save chris/bf8997c954ca6a7eef97a0ceb5b1085e to your computer and use it in GitHub Desktop.
S3 CloudFront Custom Domain CloudFormation example
#
# 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