# CloudFront Origin Access Control resource "aws_cloudfront_origin_access_control" "oac" { name = "${var.project_name}-${var.environment}-oac" description = "OAC for ${var.project_name}" origin_access_control_origin_type = "s3" signing_behavior = "always" signing_protocol = "sigv4" } # CloudFront Distribution resource "aws_cloudfront_distribution" "main" { # Origin configuration for custom domain origin { domain_name = var.origin_domain origin_id = "${var.project_name}-${var.environment}-origin" custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = var.origin_protocol_policy origin_ssl_protocols = ["TLSv1.2"] origin_read_timeout = 30 origin_keepalive_timeout = 5 } # Custom headers (optional) # custom_header { # name = "User-Agent" # value = "CloudFront-${var.project_name}" # } } enabled = true is_ipv6_enabled = true comment = "CloudFront distribution for ${var.project_name} - ${var.environment}" default_root_object = "index.html" # Aliases (custom domain names) - Enable when ACM certificate is available aliases = var.create_acm_certificate ? var.cloudfront_aliases : null # Default cache behavior default_cache_behavior { allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] cached_methods = ["GET", "HEAD"] target_origin_id = "${var.project_name}-${var.environment}-origin" cache_policy_id = var.cache_policy_id origin_request_policy_id = var.origin_request_policy_id viewer_protocol_policy = var.viewer_protocol_policy compress = true # Forward headers, query strings, and cookies # Use cache policies instead for better performance } # Ordered cache behaviors (optional) ordered_cache_behavior { path_pattern = "/api/*" allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] cached_methods = ["GET", "HEAD"] target_origin_id = "${var.project_name}-${var.environment}-origin" cache_policy_id = "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # CachingDisabled viewer_protocol_policy = "https-only" compress = true } # Price class price_class = var.price_class # Geographic restrictions restrictions { geo_restriction { restriction_type = "none" # locations = [] } } # SSL/TLS certificate - Use ACM certificate when available viewer_certificate { acm_certificate_arn = var.create_acm_certificate ? aws_acm_certificate.main[0].arn : null ssl_support_method = var.create_acm_certificate ? "sni-only" : null minimum_protocol_version = var.create_acm_certificate ? "TLSv1.2_2021" : null cloudfront_default_certificate = var.create_acm_certificate ? false : true } # Custom error responses custom_error_response { error_code = 404 response_code = 200 response_page_path = "/index.html" error_caching_min_ttl = 300 } custom_error_response { error_code = 403 response_code = 200 response_page_path = "/index.html" error_caching_min_ttl = 300 } # Web Application Firewall (optional) web_acl_id = var.enable_waf ? aws_wafv2_web_acl.cloudfront[0].arn : null # Logging configuration dynamic "logging_config" { for_each = var.enable_cloudfront_logging ? [1] : [] content { bucket = "${var.cloudfront_logs_bucket}.s3.amazonaws.com" prefix = var.cloudfront_logs_prefix include_cookies = false } } tags = { Name = "${var.project_name}-${var.environment}-distribution" Origin = var.origin_domain } } # CloudFormation Stack (optional - for additional AWS resources) resource "aws_cloudformation_stack" "network" { count = var.enable_cloudformation_stack ? 1 : 0 name = "${var.project_name}-${var.environment}-network-stack" parameters = { VPCCidr = "10.0.0.0/16" Environment = var.environment ProjectName = var.project_name } template_body = jsonencode({ AWSTemplateFormatVersion = "2010-09-09" Description = "Network resources for ${var.project_name}" Parameters = { VPCCidr = { Type = "String" Default = "10.0.0.0/16" Description = "CIDR block for the VPC" } Environment = { Type = "String" Description = "Environment name" } ProjectName = { Type = "String" Description = "Project name" } } Resources = { VPC = { Type = "AWS::EC2::VPC" Properties = { CidrBlock = { Ref = "VPCCidr" } EnableDnsHostnames = true EnableDnsSupport = true Tags = [ { Key = "Name" Value = { "Fn::Sub" = "$${ProjectName}-$${Environment}-vpc" } } ] } } InternetGateway = { Type = "AWS::EC2::InternetGateway" Properties = { Tags = [ { Key = "Name" Value = { "Fn::Sub" = "$${ProjectName}-$${Environment}-igw" } } ] } } AttachGateway = { Type = "AWS::EC2::VPCGatewayAttachment" Properties = { VpcId = { Ref = "VPC" } InternetGatewayId = { Ref = "InternetGateway" } } } PublicSubnet = { Type = "AWS::EC2::Subnet" Properties = { VpcId = { Ref = "VPC" } CidrBlock = "10.0.1.0/24" AvailabilityZone = { "Fn::Select" = [0, { "Fn::GetAZs" = "" }] } MapPublicIpOnLaunch = true Tags = [ { Key = "Name" Value = { "Fn::Sub" = "$${ProjectName}-$${Environment}-public-subnet" } } ] } } } Outputs = { VPCId = { Description = "VPC ID" Value = { Ref = "VPC" } Export = { Name = { "Fn::Sub" = "$${ProjectName}-$${Environment}-VPC-ID" } } } PublicSubnetId = { Description = "Public Subnet ID" Value = { Ref = "PublicSubnet" } Export = { Name = { "Fn::Sub" = "$${ProjectName}-$${Environment}-PublicSubnet-ID" } } } } }) capabilities = ["CAPABILITY_IAM"] tags = { Name = "${var.project_name}-${var.environment}-network" ManagedBy = "OpenTofu" } }