{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Creates a serverless static website using S3, ACM, Route53, and CloudFront. The template requires the use of an existing Route 53 hosted zone to support ACM DNS Validation, and should be deployed in us-east-1 due to CloudFront's ACM integration or modified.",
"Parameters": {
"DomainName": {
"Type": "String",
"Description": "example: subdomain.example.com"
},
"HostedZone": {
"Type": "String",
"Description": "example: F11227681IL5LE0HY043"
}
},
"Metadata": {
"AWS::CloudFormation::Interface": {
"ParameterLabels": {
"DomainName": { "default" : "Fully Qualified Domain Name: " },
"HostedZone": { "default" : "Route53 Hosted Zone Id: " }
}
}
},
"Resources": {
"S3BucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"Properties": {
"Bucket": {
"Ref": "S3Bucket"
},
"PolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Condition": {
"StringEquals": {
"AWS:SourceArn": { "Fn::Sub": "arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}" }
}
},
"Resource": { "Fn::Join" : [ "", [ { "Fn::GetAtt": ["S3Bucket", "Arn"] }, "/*"] ] },
"Action": "s3:GetObject",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Sid": "AllowCloudFrontServicePrincipal"
}
],
"Id": "PolicyForCloudFrontPrivateContent"
}
}
},
"CloudFrontOriginAccessControl": {
"Type": "AWS::CloudFront::OriginAccessControl",
"Properties": {
"OriginAccessControlConfig": {
"Name": {"Fn::Sub": "${AWS::StackName}-OAC"},
"OriginAccessControlOriginType": "s3",
"SigningBehavior": "always",
"SigningProtocol": "sigv4"
}
}
},
"CloudFrontDistribution": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"Enabled": true,
"DefaultRootObject": "index.html",
"Aliases": [
{"Ref": "DomainName"}
],
"DefaultCacheBehavior": {
"AllowedMethods": ["GET", "HEAD", "OPTIONS"],
"CachedMethods": ["GET", "HEAD", "OPTIONS"],
"Compress": true,
"DefaultTTL": 3600,
"ForwardedValues": {
"QueryString": false
},
"MaxTTL": 86400,
"MinTTL": 0,
"SmoothStreaming": false,
"TargetOriginId": {"Fn::Sub": "${S3Bucket}-origin"},
"ViewerProtocolPolicy": "redirect-to-https"
},
"HttpVersion": "http2",
"IPV6Enabled": true,
"Origins": [
{
"DomainName": {"Fn::GetAtt": ["S3Bucket", "RegionalDomainName"]},
"Id": {"Fn::Sub": "${S3Bucket}-origin"},
"OriginAccessControlId": {"Ref": "CloudFrontOriginAccessControl"},
"S3OriginConfig": {}
}
],
"PriceClass": "PriceClass_100",
"ViewerCertificate": {
"AcmCertificateArn": { "Ref": "Certificate" },
"MinimumProtocolVersion": "TLSv1.2_2021",
"SslSupportMethod": "sni-only"
}
}
}
},
"S3Bucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": { "Ref": "DomainName" }
}
},
"aRecord": {
"Type": "AWS::Route53::RecordSet",
"Properties": {
"HostedZoneId": {
"Ref": "HostedZone"
},
"Name": {"Ref": "DomainName"},
"Type": "CNAME",
"TTL": "300",
"ResourceRecords": [
{ "Fn::GetAtt": ["CloudFrontDistribution", "DomainName"] }
]
}
},
"Certificate": {
"Type": "AWS::CertificateManager::Certificate",
"Properties": {
"DomainName": {
"Ref": "DomainName"
},
"ValidationMethod": "DNS",
"DomainValidationOptions": [
{
"DomainName": {
"Ref": "DomainName"
},
"HostedZoneId": {
"Ref": "HostedZone"
}
}
]
}
}
},
"Outputs": {
"CloudFrontDistributionDomain": {
"Description": "Domain name of the CloudFront distribution",
"Value": {
"Fn::GetAtt": [
"CloudFrontDistribution",
"DomainName"
]
}
}
}
}