Architecture Diagram

AWS CloudFormation Template Example



        {
            "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"
                        ]
                    }
                }
            }
            
        }