Skip to content

Instantly share code, notes, and snippets.

@jranson
Created February 8, 2022 21:37
Show Gist options
  • Save jranson/9d71d22b0e956d8e5fb8092b7f9e4fbe to your computer and use it in GitHub Desktop.
Save jranson/9d71d22b0e956d8e5fb8092b7f9e4fbe to your computer and use it in GitHub Desktop.
Terraform - Create S3 Bucket + Certs + DNS + CloudFront
variable "app_domain" {
type = string
}
variable "app_hostname" {
type = string
}
variable "app_bucket" {
type = string
}
locals {
app_fqdn = "${var.app_hostname}.${var.app_domain}"
}
# this is a reference to your pre-existing r53 hosted zone
data "aws_route53_zone" "hosted_zone" {
name = var.app_domain
private_zone = false
}
# this creates the DNS record for your app so it's available at https://${app_fqdn}/
resource "aws_route53_record" "app" {
zone_id = data.aws_route53_zone.hosted_zone.zone_id
name = local.app_fqdn
type = "A"
alias {
name = module.app_cdn.cloudfront_distribution_domain_name
zone_id = module.app_cdn.cloudfront_distribution_hosted_zone_id
evaluate_target_health = false
}
}
# this creates the TLS certificate for the app
resource "aws_acm_certificate" "app" {
domain_name = local.app_fqdn
validation_method = "DNS"
}
# this validates that the certificate is working in practice
resource "aws_route53_record" "app_validation" {
for_each = {
for dvo in aws_acm_certificate.app.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = data.aws_route53_zone.hosted_zone.zone_id
}
# this record allows the certificate to be validated by checking the record contents
resource "aws_acm_certificate_validation" "app" {
certificate_arn = aws_acm_certificate.app.arn
validation_record_fqdns = [for record in aws_route53_record.app_validation : record.fqdn]
timeouts {
create = "45m"
}
}
# this creates the s3 bucket for the app, which is fronted by cloudfront
resource "aws_s3_bucket" "app" {
bucket = var.app_bucket
acl = "private"
policy = <<POLICY
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${module.app_cdn.cloudfront_origin_access_identities["s3_bucket_one"].id}"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::${var.app_bucket}/*"
}
]
}
POLICY
website {
index_document = "index.html"
}
}
# this creates the cloudfront distribution
module "app_cdn" {
source = "terraform-aws-modules/cloudfront/aws"
aliases = [local.app_fqdn]
comment = "CloudFront Distribution for App"
enabled = true
is_ipv6_enabled = true
price_class = "PriceClass_100"
retain_on_delete = false
wait_for_deployment = false
default_root_object = "index.html"
create_origin_access_identity = true
origin_access_identities = {
s3_bucket_one = "CloudFront OAI for App"
}
origin = {
s3_one = {
domain_name = "${var.app_bucket}.s3.amazonaws.com"
s3_origin_config = {
origin_access_identity = "s3_bucket_one"
}
}
}
default_cache_behavior = {
target_origin_id = "s3_one"
viewer_protocol_policy = "allow-all"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
compress = true
query_string = true
}
viewer_certificate = {
acm_certificate_arn = aws_acm_certificate.app.arn
ssl_support_method = "sni-only"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment