172 lines
5 KiB
Terraform
172 lines
5 KiB
Terraform
|
locals {
|
||
|
origin_id = "s3-calculator-origin"
|
||
|
bucket_name = replace(var.primary_domain, ".", "-")
|
||
|
}
|
||
|
|
||
|
resource "aws_s3_bucket" "site" {
|
||
|
bucket = local.bucket_name
|
||
|
tags = var.tags
|
||
|
}
|
||
|
|
||
|
resource "aws_s3_bucket_ownership_controls" "site" {
|
||
|
bucket = aws_s3_bucket.site.id
|
||
|
rule { object_ownership = "BucketOwnerPreferred" }
|
||
|
}
|
||
|
|
||
|
resource "aws_s3_bucket_public_access_block" "site" {
|
||
|
bucket = aws_s3_bucket.site.id
|
||
|
block_public_acls = true
|
||
|
block_public_policy = true
|
||
|
ignore_public_acls = true
|
||
|
restrict_public_buckets = true
|
||
|
}
|
||
|
|
||
|
resource "aws_s3_bucket_policy" "site" {
|
||
|
bucket = aws_s3_bucket.site.id
|
||
|
policy = data.aws_iam_policy_document.s3_policy.json
|
||
|
}
|
||
|
|
||
|
data "aws_caller_identity" "current" {}
|
||
|
|
||
|
data "aws_iam_policy_document" "s3_policy" {
|
||
|
statement {
|
||
|
sid = "AllowCloudFrontRead"
|
||
|
effect = "Allow"
|
||
|
actions = ["s3:GetObject"]
|
||
|
resources = ["${aws_s3_bucket.site.arn}/*"]
|
||
|
principals {
|
||
|
type = "Service"
|
||
|
identifiers = ["cloudfront.amazonaws.com"]
|
||
|
}
|
||
|
condition {
|
||
|
test = "StringEquals"
|
||
|
variable = "AWS:SourceArn"
|
||
|
values = [aws_cloudfront_distribution.site.arn]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# CloudFront OAC (origin access control)
|
||
|
resource "aws_cloudfront_origin_access_control" "oac" {
|
||
|
name = "${local.bucket_name}-oac"
|
||
|
description = "OAC for ${local.bucket_name}"
|
||
|
origin_access_control_origin_type = "s3"
|
||
|
signing_behavior = "always"
|
||
|
signing_protocol = "sigv4"
|
||
|
}
|
||
|
|
||
|
# ACM certificate in us-east-1 for both domains
|
||
|
resource "aws_acm_certificate" "cert" {
|
||
|
provider = aws.us_east_1
|
||
|
domain_name = var.primary_domain
|
||
|
subject_alternative_names = [var.secondary_domain]
|
||
|
validation_method = "DNS"
|
||
|
tags = var.tags
|
||
|
}
|
||
|
|
||
|
resource "aws_route53_record" "cert_validation" {
|
||
|
for_each = { for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {
|
||
|
name = dvo.resource_record_name
|
||
|
type = dvo.resource_record_type
|
||
|
value = dvo.resource_record_value
|
||
|
} }
|
||
|
zone_id = data.aws_route53_zone.main.zone_id
|
||
|
name = each.value.name
|
||
|
type = each.value.type
|
||
|
ttl = 60
|
||
|
records = [each.value.value]
|
||
|
}
|
||
|
|
||
|
resource "aws_acm_certificate_validation" "cert" {
|
||
|
provider = aws.us_east_1
|
||
|
certificate_arn = aws_acm_certificate.cert.arn
|
||
|
validation_record_fqdns = [for r in aws_route53_record.cert_validation : r.fqdn]
|
||
|
}
|
||
|
|
||
|
# Get the hosted zone
|
||
|
data "aws_route53_zone" "main" {
|
||
|
name = var.hosted_zone
|
||
|
}
|
||
|
|
||
|
# CloudFront distribution
|
||
|
resource "aws_cloudfront_distribution" "site" {
|
||
|
enabled = true
|
||
|
is_ipv6_enabled = true
|
||
|
comment = "Calculator site for ${var.primary_domain} and ${var.secondary_domain}"
|
||
|
default_root_object = "index.html"
|
||
|
aliases = [var.primary_domain, var.secondary_domain]
|
||
|
|
||
|
origin {
|
||
|
domain_name = aws_s3_bucket.site.bucket_regional_domain_name
|
||
|
origin_id = local.origin_id
|
||
|
origin_access_control_id = aws_cloudfront_origin_access_control.oac.id
|
||
|
}
|
||
|
|
||
|
default_cache_behavior {
|
||
|
allowed_methods = ["GET", "HEAD"]
|
||
|
cached_methods = ["GET", "HEAD"]
|
||
|
target_origin_id = local.origin_id
|
||
|
viewer_protocol_policy = "redirect-to-https"
|
||
|
compress = true
|
||
|
min_ttl = 0
|
||
|
default_ttl = 3600
|
||
|
max_ttl = 86400
|
||
|
}
|
||
|
|
||
|
restrictions {
|
||
|
geo_restriction {
|
||
|
restriction_type = "none"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
viewer_certificate {
|
||
|
acm_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn
|
||
|
ssl_support_method = "sni-only"
|
||
|
minimum_protocol_version = "TLSv1.2_2021"
|
||
|
}
|
||
|
|
||
|
custom_error_response {
|
||
|
error_code = 403
|
||
|
response_code = 200
|
||
|
response_page_path = "/index.html"
|
||
|
}
|
||
|
custom_error_response {
|
||
|
error_code = 404
|
||
|
response_code = 200
|
||
|
response_page_path = "/index.html"
|
||
|
}
|
||
|
|
||
|
tags = var.tags
|
||
|
}
|
||
|
|
||
|
# Route53 alias for primary domain
|
||
|
resource "aws_route53_record" "primary_alias" {
|
||
|
zone_id = data.aws_route53_zone.main.zone_id
|
||
|
name = var.primary_domain
|
||
|
type = "A"
|
||
|
alias {
|
||
|
name = aws_cloudfront_distribution.site.domain_name
|
||
|
zone_id = aws_cloudfront_distribution.site.hosted_zone_id
|
||
|
evaluate_target_health = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Route53 alias for secondary domain
|
||
|
resource "aws_route53_record" "secondary_alias" {
|
||
|
zone_id = data.aws_route53_zone.main.zone_id
|
||
|
name = var.secondary_domain
|
||
|
type = "A"
|
||
|
alias {
|
||
|
name = aws_cloudfront_distribution.site.domain_name
|
||
|
zone_id = aws_cloudfront_distribution.site.hosted_zone_id
|
||
|
evaluate_target_health = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
output "bucket_name" { value = aws_s3_bucket.site.bucket }
|
||
|
output "distribution_id" { value = aws_cloudfront_distribution.site.id }
|
||
|
output "primary_domain" { value = var.primary_domain }
|
||
|
output "secondary_domain" { value = var.secondary_domain }
|
||
|
output "cloudfront_domain" { value = aws_cloudfront_distribution.site.domain_name }
|
||
|
|