Infrastructure improvements: - Update CloudFront distribution with ACM certificate support - Enable custom domain aliases when certificate is available - Add comprehensive WAF outputs for CrowdSec integration - Update variables with current configuration defaults New files: - Add CrowdSec WAF integration documentation - Add sync script for CrowdSec to WAF automation - Add MCP configuration for development tools Configuration updates: - Align Terraform configuration with deployed state - Enable ACM certificate and Route53 DNS by default - Maintain HTTP-only origin protocol for compatibility 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
227 lines
6.7 KiB
HCL
227 lines
6.7 KiB
HCL
# 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"
|
|
}
|
|
} |