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 }