resource "random_password" "origin_verify" { length = 32 special = false } resource "aws_cloudfront_origin_access_control" "web" { name = "${local.project}-${var.environment}-oac" description = "OAC for ${local.web_bucket_name}" origin_access_control_origin_type = "s3" signing_behavior = "always" signing_protocol = "sigv4" } resource "aws_cloudfront_function" "spa_rewrite" { name = "${local.project}-${var.environment}-spa-rewrite" runtime = "cloudfront-js-1.0" comment = "SPA routing: rewrite extensionless paths to /index.html" publish = true code = local.spa_rewrite_code lifecycle { ignore_changes = [publish] } } resource "aws_cloudfront_function" "spa_security_headers" { name = "${local.project}-${var.environment}-spa-security-headers" runtime = "cloudfront-js-1.0" comment = "SPA CSP and Permissions-Policy" publish = true code = local.spa_security_headers_code lifecycle { ignore_changes = [publish] } } resource "aws_cloudfront_distribution" "web" { enabled = true is_ipv6_enabled = true http_version = "http2and3" comment = "${local.project} ${var.environment} SPA" default_root_object = "index.html" price_class = "PriceClass_100" web_acl_id = data.aws_ssm_parameter.app_web_acl_arn.value origin { origin_id = local.s3_origin_id domain_name = aws_s3_bucket.web.bucket_regional_domain_name origin_access_control_id = aws_cloudfront_origin_access_control.web.id } origin { origin_id = local.api_origin_id domain_name = aws_lb.api.dns_name custom_header { name = "X-Origin-Verify" value = random_password.origin_verify.result } custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = "http-only" origin_ssl_protocols = ["TLSv1.2"] } } ordered_cache_behavior { path_pattern = "/api/*" target_origin_id = local.api_origin_id viewer_protocol_policy = "redirect-to-https" allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"] cached_methods = ["GET", "HEAD"] compress = true cache_policy_id = local.cache_policy_caching_disabled origin_request_policy_id = local.origin_request_all_viewer_except_host response_headers_policy_id = local.response_headers_security_headers } default_cache_behavior { target_origin_id = local.s3_origin_id viewer_protocol_policy = "redirect-to-https" allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD"] compress = true cache_policy_id = local.cache_policy_caching_optimized response_headers_policy_id = local.response_headers_security_headers function_association { event_type = "viewer-request" function_arn = aws_cloudfront_function.spa_rewrite.arn } function_association { event_type = "viewer-response" function_arn = aws_cloudfront_function.spa_security_headers.arn } } restrictions { geo_restriction { restriction_type = "none" } } viewer_certificate { cloudfront_default_certificate = true } lifecycle { prevent_destroy = true } }