resource "aws_cloudfront_origin_access_control" "form" { name = "${local.project}-oac" description = "OAC for the meal-order-manager form origin bucket" origin_access_control_origin_type = "s3" signing_behavior = "always" signing_protocol = "sigv4" } resource "aws_cloudfront_distribution" "form" { enabled = true is_ipv6_enabled = true http_version = "http2and3" comment = "meal-order-manager form hosting" default_root_object = "index.html" price_class = "PriceClass_100" aliases = [var.domain_name] # Shared org CloudFront WAF (audit M-17), resolved from Parameter Store. web_acl_id = data.aws_ssm_parameter.app_web_acl_arn.value origin { origin_id = "S3FormOrigin" domain_name = aws_s3_bucket.form.bucket_regional_domain_name origin_access_control_id = aws_cloudfront_origin_access_control.form.id } default_cache_behavior { target_origin_id = "S3FormOrigin" viewer_protocol_policy = "redirect-to-https" allowed_methods = ["GET", "HEAD"] cached_methods = ["GET", "HEAD"] compress = true # AWS managed policy: CachingDisabled. The form HTML is republished weekly # and read through a signed API, so a stale edge copy is worse than an # origin fetch. cache_policy_id = "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" } # A request for an object the private origin does not hold returns 403, not # 404. Rewriting it to the form keeps deep links working, matching the SAM # template. custom_error_response { error_code = 403 response_code = 200 response_page_path = "/index.html" } restrictions { geo_restriction { restriction_type = "none" } } viewer_certificate { acm_certificate_arn = data.aws_acm_certificate.orders.arn ssl_support_method = "sni-only" minimum_protocol_version = "TLSv1.2_2021" } lifecycle { prevent_destroy = true } }