CloudFront Site (S3 + ACM + Route53)
Complete HTTPS site/CDN: CloudFront distribution, OAC-locked S3 origin, ACM cert, and Route53 alias records.
Verification
Static-verifiedPassed: validated and lint-clean (provider-schema-validated for AWS/Azure/GCP; Terraform-language lint elsewhere).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan: findings disclosed (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-06-28 · how we verify
Documentation
aws-cloudfront-site
Complete HTTPS site/CDN: CloudFront distribution, OAC-locked S3 origin, ACM
cert, and Route53 alias records. Works with Terraform and OpenTofu
(>= 1.6), AWS provider >= 6.0, < 7.0.
Secure defaults:
- Origin bucket is private (full public-access block), encrypted, versioned,
and readable only by this distribution (Origin Access Control, SigV4,
AWS:SourceArncondition) — plus a non-TLS deny policy - ACM certificate issued in us-east-1 with fully automated Route 53 DNS validation (the classic cross-region footgun, handled)
- HTTPS enforced (
redirect-to-https), TLS 1.2 (2021 policy) minimum, HTTP/2 + HTTP/3, compression on - Security response headers (HSTS 2y, nosniff, SAMEORIGIN, strict referrer) attached by default
- A + AAAA alias records created for the apex/primary domain and every SAN
Dual provider requirement
CloudFront only accepts certificates from us-east-1, so the module takes a
second provider configuration via configuration_aliases. Wire it like this:
provider "aws" {
region = "eu-west-1" # bucket + Route 53 live here
}
provider "aws" {
alias = "us_east_1"
region = "us-east-1" # certificate must live here
}
module "site" {
source = "./aws-cloudfront-site"
providers = {
aws = aws
aws.us_east_1 = aws.us_east_1
}
domain_name = "example.com"
subject_alternative_names = ["www.example.com"]
route53_zone_id = "Z0123456789ABCDEFGHIJ"
single_page_application = true
tags = { Environment = "prod" }
}
Deploy content with aws s3 sync ./dist s3://<bucket_id> and invalidate with
aws cloudfront create-invalidation --distribution-id <distribution_id> --paths "/*".
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
domain_name | string | — | Primary site domain (required) |
subject_alternative_names | list(string) | [] | Extra domains (cert SANs + aliases + DNS) |
route53_zone_id | string | — | Hosted zone for validation + alias records (required) |
bucket_name | string | null | Origin bucket name; null = domain_name |
force_destroy | bool | false | Allow destroying a non-empty bucket |
versioning_enabled | bool | true | Origin bucket versioning |
default_root_object | string | "index.html" | Root object |
single_page_application | bool | false | Rewrite 403/404 to the root object (HTTP 200) |
custom_error_responses | list(object) | [] | Extra error responses |
price_class | string | "PriceClass_100" | Edge footprint |
minimum_protocol_version | string | "TLSv1.2_2021" | Viewer TLS floor |
ipv6_enabled | bool | true | IPv6 + AAAA records |
security_headers_enabled | bool | true | HSTS/nosniff/frame/referrer policy |
geo_restriction | object | none | none/whitelist/blacklist + locations |
web_acl_id | string | null | WAFv2 ACL ARN (CLOUDFRONT scope) |
logging | object | null | Standard access logs { bucket, prefix? } |
tags | map(string) | {} | Tags applied to all resources |
Outputs
distribution_id, distribution_arn, distribution_domain_name,
distribution_hosted_zone_id, bucket_id, bucket_arn,
bucket_regional_domain_name, certificate_arn, site_urls.
Requirements
- Terraform or OpenTofu
>= 1.6 - AWS provider
>= 6.0, < 7.0, two configurations (default +aws.us_east_1) - A registered domain with a Route 53 public hosted zone you control
Notes
- Uses the AWS managed
CachingOptimizedcache policy — right for static assets; fingerprint your filenames for cache busting. - Distribution create takes ~5-10 min; destroy disables first, then deletes (15-30 min total). That is CloudFront, not the module.
logginguses CloudFront standard (v1) logs and requires a log bucket with ACLs enabled.
Verification
Static-validated (fmt, validate, tflint). Live apply/destroy testing pending cloud sandbox availability — see catalog status.
License
Commercial — IaC Bazaar EULA. © IaC Bazaar. Original work (not derived from a third-party module).