calculator.127local.net/infra/main.tf

172 lines
5 KiB
Terraform
Raw Normal View History

2025-08-16 17:54:12 -07:00
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 }