Terraform module to create a static site in AWS using CloudFront, S3, ACM, Route53, etc...
An opinionated Terraform module to create a static site:
- Separate S3 buckets for site files (e.g., HTML, CSS, etc...) and logging
- S3 buckets are private
- Logs move to Standard IA after 30 days and are expired after 365
- Site files (e.g., HTML, CSS, etc...) can only be accessed through CloudFront (i.e., no direct access to files in S3)
- Creates an ACM certificate for
domain_name.tld
and*.domain_name.tld
(i.e., for subdomains likewww.domain_name.tld
) - Validates the ACM certificate using Route53 DNS
- Creates A and AAAA records for
domain_name.tld
andwww.domain_name.tld
- CloudFront distribution using Origin Access Control to S3
- CloudFront options for IPv6, TLS, HTTP versions, and more
- Sane defaults for CloudFront HTTP headers
- You MUST already have a Route53 hosted zone and accompanying NS records created (this module does NOT do this for you) because ACM uses DNS for certficate validation. Below is an example of how to do this with Terraform.
resource "aws_route53_zone" "mydomain_com" {
name = "domain.com"
}
resource "aws_route53_record" "mydomain_com_nameservers" {
zone_id = aws_route53_zone.mydomain_com.zone_id
name = aws_route53_zone.mydomain_com.name
type = "NS"
ttl = "3600"
allow_overwrite = true
records = aws_route53_zone.mydomain_com.name_servers
}
- The
domain_name
input into the module MUST match the Route53 hosted zone name (e.g.,domain.com
). - CloudFront can only use ACM certs generated in
us-east-1
. Some people (i.e., me) don't want their resources inus-east-1
, except the ACM certificate and validation. Because of this, I had to add an extraprovider
configuration ofaws.us-east-1
to those two resources. You NEED to add this extra provider to your root module and again when calling the module itself (below is an example).
# Default
provider "aws" {
region = "us-east-2"
shared_credentials_files = ["~/.aws/credentials"]
}
# Needed because CloudFront can only use ACM certs generated in us-east-1
provider "aws" {
alias = "us-east-1"
region = "us-east-1"
shared_credentials_files = ["~/.aws/credentials"]
}
module "static_site_domain_com" {
source = "github.com/loganmarchione/terraform-aws-static-site?ref=x.y.z"
providers = {
aws.us-east-1 = aws.us-east-1
}
# The domain name of the site (**MUST** match the Route53 hosted zone name (e.g., `domain.com`)
domain_name = "domain.com"
# Since this is a static site, we probably don't need versioning, since our source files are stored in git
bucket_versioning_logs = false
bucket_versioning_site = false
# CloudFront settings
cloudfront_compress = true
cloudfront_default_root_object = "index.html"
cloudfront_enabled = true
cloudfront_function_create = true
cloudfront_function_filename = "function.js"
cloudfront_function_name = "ReWrites"
cloudfront_http_version = "http2and3"
cloudfront_ipv6 = true
cloudfront_price_class = "PriceClass_100"
cloudfront_ssl_minimum_protocol_version = "TLSv1.2_2021"
cloudfront_ttl_min = 3600
cloudfront_ttl_default = 86400
cloudfront_ttl_max = 31536000
cloudfront_viewer_protocol_policy = "redirect-to-https"
# IAM
iam_policy_site_updating = false
# Upload default files
upload_index = true
upload_robots = true
upload_404 = true
}
This documentation was generated automatically with terraform-docs
Name | Version |
---|---|
terraform | >= 1.0.2 |
aws | >= 5.15.0 |
Name | Version |
---|---|
aws | >= 5.15.0 |
aws.us-east-1 | >= 5.15.0 |
No modules.
Name | Description | Type | Default | Required |
---|---|---|---|---|
bucket_versioning_logs | State of bucket versioning for logs bucket | bool |
false |
no |
bucket_versioning_site | State of bucket versioning for site bucket | bool |
false |
no |
cloudfront_compress | To enable CloudFront compression or not | bool |
true |
no |
cloudfront_custom_error_responses | The CloudFront custom error responses | list(object({ |
[ |
no |
cloudfront_default_root_object | The CloudFront default root object to display (this is null by default, so nothing will display at https://domain.com unless you set something here) |
string |
null |
no |
cloudfront_enabled | To enable CloudFront or not | bool |
true |
no |
cloudfront_function_create | To create and associate a CloudFront function (this doesn't test the function, so make sure it works!) | bool |
false |
no |
cloudfront_function_filename | The filename of the CloudFront function (the default is this AWS-provided function that appends index.html to requests that don't include a file name or extension (e.g., domain.com/foo) |
string |
"function.js" |
no |
cloudfront_function_name | The name of the CloudFront function | string |
"MyFunction" |
no |
cloudfront_http_version | The CloudFront HTTP version | string |
"http2" |
no |
cloudfront_ipv6 | To enable CloudFront IPv6 or not (also controls creation of two AAAA Route53 records) | bool |
true |
no |
cloudfront_price_class | The CloudFront price class | string |
"PriceClass_100" |
no |
cloudfront_ssl_minimum_protocol_version | The CloudFront minimum SSL protocol to use | string |
"TLSv1.2_2021" |
no |
cloudfront_ttl_default | The CloudFront default cache time (seconds) | number |
86400 |
no |
cloudfront_ttl_max | The CloudFront maximum cache time (seconds) | number |
31536000 |
no |
cloudfront_ttl_min | The CloudFront minimum cache time (seconds) | number |
3600 |
no |
cloudfront_viewer_protocol_policy | The CloudFront viewer protocol policy to enforce (e.g., redirect HTTP to HTTPS) | string |
"redirect-to-https" |
no |
domain_name | Domain name of the site and MUST match the Route53 hosted zone name (e.g., domain.com ) |
string |
n/a | yes |
iam_policy_site_updating | Optional IAM policy that provides permissions needed to update a static site (e.g., create CloudFront cache invalidation, update objects in S3, etc...) | bool |
false |
no |
upload_404 | To push a 404.html page (useful if you want to test your custom error responses) or not |
bool |
false |
no |
upload_index | To push a test index.html page or not |
bool |
true |
no |
upload_robots | To push a restrictive robots.txt file (useful if you don't want a site to be indexed) or not |
bool |
false |
no |
Name | Description |
---|---|
site_updating_iam_policy_arn | Value of site_updating IAM policy ARN |