feat(phase-2): workstream 8 — Multi-Region Terraform Deployment
AWS environment: - VPC (3-AZ, public + private subnets, NAT gateways, VPC endpoints for ECR/SM/CW) - ECS Fargate service (sentryagent/agentidp) — secrets from Secrets Manager - RDS PostgreSQL 14 (Multi-AZ, encrypted, VPC-internal, storage autoscaling) - ElastiCache Redis 7 (primary + replica, at-rest + in-transit encryption) - ALB with HTTPS/443, HTTP→HTTPS redirect, ACM certificate - Route 53 alias record GCP environment: - VPC + private services access + Serverless VPC connector - Cloud Run service — secrets from Secret Manager - Cloud SQL PostgreSQL 14 (private IP, no public endpoint) - Cloud Memorystore Redis 7 (VPC-internal, AUTH enabled) Shared: - 4 reusable modules: agentidp (dual AWS/GCP), rds, redis, lb - No hardcoded secrets; all sensitive vars marked sensitive=true - terraform.tfvars.example for both environments - docs/devops/deployment.md — AWS + GCP step-by-step walkthrough, rollback procedures Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
183
terraform/modules/lb/main.tf
Normal file
183
terraform/modules/lb/main.tf
Normal file
@@ -0,0 +1,183 @@
|
||||
################################################################################
|
||||
# Module: lb
|
||||
# Main — AWS Application Load Balancer
|
||||
#
|
||||
# - Internet-facing ALB in public subnets
|
||||
# - HTTPS listener (443) with ACM certificate, TLS 1.2+ enforced
|
||||
# - HTTP listener (80) redirects permanently to HTTPS — no plaintext traffic
|
||||
# - Target group pointing to ECS Fargate tasks on the app port
|
||||
# - Access logs optionally streamed to S3
|
||||
################################################################################
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.6.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.40.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
identifier = "${var.project}-${var.environment}"
|
||||
|
||||
common_tags = {
|
||||
environment = var.environment
|
||||
project = var.project
|
||||
managed_by = "terraform"
|
||||
}
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Security Group — ALB allows inbound 80 + 443 from the internet
|
||||
################################################################################
|
||||
|
||||
resource "aws_security_group" "alb" {
|
||||
name = "${local.identifier}-alb-sg"
|
||||
description = "ALB security group — inbound 80/443 from internet, outbound to app"
|
||||
vpc_id = var.vpc_id
|
||||
|
||||
ingress {
|
||||
description = "HTTP from internet (redirected to HTTPS)"
|
||||
from_port = 80
|
||||
to_port = 80
|
||||
protocol = "tcp"
|
||||
cidr_blocks = var.allowed_ingress_cidrs
|
||||
}
|
||||
|
||||
ingress {
|
||||
description = "HTTPS from internet"
|
||||
from_port = 443
|
||||
to_port = 443
|
||||
protocol = "tcp"
|
||||
cidr_blocks = var.allowed_ingress_cidrs
|
||||
}
|
||||
|
||||
egress {
|
||||
description = "Forward to ECS app tasks"
|
||||
from_port = var.target_group_port
|
||||
to_port = var.target_group_port
|
||||
protocol = "tcp"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
tags = merge(local.common_tags, {
|
||||
Name = "${local.identifier}-alb-sg"
|
||||
})
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Application Load Balancer
|
||||
################################################################################
|
||||
|
||||
resource "aws_lb" "main" {
|
||||
name = "${local.identifier}-alb"
|
||||
internal = false
|
||||
load_balancer_type = "application"
|
||||
security_groups = [aws_security_group.alb.id]
|
||||
subnets = var.subnet_ids
|
||||
|
||||
idle_timeout = var.idle_timeout
|
||||
enable_deletion_protection = var.enable_deletion_protection
|
||||
|
||||
# HTTP/2 is enabled by default on ALB; leave it on for performance.
|
||||
enable_http2 = true
|
||||
|
||||
# Drop invalid header fields to harden against request smuggling.
|
||||
drop_invalid_header_fields = true
|
||||
|
||||
dynamic "access_logs" {
|
||||
for_each = var.access_logs_bucket != "" ? [1] : []
|
||||
content {
|
||||
bucket = var.access_logs_bucket
|
||||
prefix = var.access_logs_prefix
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
tags = merge(local.common_tags, {
|
||||
Name = "${local.identifier}-alb"
|
||||
})
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Target Group — ECS Fargate tasks register here
|
||||
################################################################################
|
||||
|
||||
resource "aws_lb_target_group" "app" {
|
||||
name = "${local.identifier}-tg"
|
||||
port = var.target_group_port
|
||||
protocol = "HTTP"
|
||||
vpc_id = var.vpc_id
|
||||
target_type = "ip" # Required for Fargate (awsvpc network mode)
|
||||
|
||||
deregistration_delay = 30
|
||||
|
||||
health_check {
|
||||
enabled = true
|
||||
path = var.target_group_health_check_path
|
||||
port = "traffic-port"
|
||||
protocol = "HTTP"
|
||||
interval = var.target_group_health_check_interval
|
||||
timeout = var.target_group_health_check_timeout
|
||||
healthy_threshold = var.target_group_healthy_threshold
|
||||
unhealthy_threshold = var.target_group_unhealthy_threshold
|
||||
matcher = "200"
|
||||
}
|
||||
|
||||
stickiness {
|
||||
type = "lb_cookie"
|
||||
enabled = false # AgentIdP is stateless (JWT-based); no sticky sessions needed
|
||||
}
|
||||
|
||||
tags = merge(local.common_tags, {
|
||||
Name = "${local.identifier}-tg"
|
||||
})
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# HTTPS Listener (port 443) — primary listener
|
||||
################################################################################
|
||||
|
||||
resource "aws_lb_listener" "https" {
|
||||
load_balancer_arn = aws_lb.main.arn
|
||||
port = 443
|
||||
protocol = "HTTPS"
|
||||
ssl_policy = var.ssl_policy
|
||||
certificate_arn = var.certificate_arn
|
||||
|
||||
default_action {
|
||||
type = "forward"
|
||||
target_group_arn = aws_lb_target_group.app.arn
|
||||
}
|
||||
|
||||
tags = local.common_tags
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# HTTP Listener (port 80) — permanent redirect to HTTPS
|
||||
################################################################################
|
||||
|
||||
resource "aws_lb_listener" "http_redirect" {
|
||||
load_balancer_arn = aws_lb.main.arn
|
||||
port = 80
|
||||
protocol = "HTTP"
|
||||
|
||||
default_action {
|
||||
type = "redirect"
|
||||
|
||||
redirect {
|
||||
port = "443"
|
||||
protocol = "HTTPS"
|
||||
status_code = "HTTP_301"
|
||||
}
|
||||
}
|
||||
|
||||
tags = local.common_tags
|
||||
}
|
||||
Reference in New Issue
Block a user