Files
ShieldAI/infra/modules/vpc/main.tf
Michael Freno 7b925c89bd Fix 3 Code Review findings on FRE-4574
- P2: Replace wget with curl for ECS health check (Alpine lacks wget)
- P2: Add AWS credentials step to CI terraform-plan job for S3 backend auth
- P3: Remove unused GitHub provider from infra/main.tf

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-10 07:09:39 -04:00

339 lines
7.4 KiB
HCL

variable "environment" {
description = "Deployment environment"
type = string
}
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
}
variable "az_count" {
description = "Number of availability zones"
type = number
}
variable "project_name" {
description = "Project name"
type = string
}
variable "kms_key_arn" {
description = "KMS key ARN for log encryption"
type = string
default = ""
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.project_name}-${var.environment}-vpc"
}
}
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_subnet" "public" {
count = var.az_count
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = false
tags = {
Name = "${var.project_name}-${var.environment}-public-${data.aws_availability_zones.available.names[count.index]}"
"kubernetes.io/role/elb" = "1"
}
}
resource "aws_subnet" "private" {
count = var.az_count
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, var.az_count + count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.project_name}-${var.environment}-private-${data.aws_availability_zones.available.names[count.index]}"
"kubernetes.io/role/internal-elb" = "1"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-${var.environment}-igw"
}
}
resource "aws_eip" "nat" {
count = var.az_count
domain = "vpc"
tags = {
Name = "${var.project_name}-${var.environment}-nat-${count.index}"
}
}
resource "aws_nat_gateway" "main" {
count = var.az_count
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = {
Name = "${var.project_name}-${var.environment}-nat-${count.index}"
}
depends_on = [aws_internet_gateway.main]
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${var.project_name}-${var.environment}-public-rt"
}
}
resource "aws_route_table" "private" {
count = var.az_count
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main[count.index].id
}
tags = {
Name = "${var.project_name}-${var.environment}-private-rt-${count.index}"
}
}
resource "aws_route_table_association" "public" {
count = var.az_count
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private" {
count = var.az_count
subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private[count.index].id
}
resource "aws_security_group" "alb" {
name_prefix = "${var.project_name}-${var.environment}-alb"
vpc_id = aws_vpc.main.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS from internet"
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP from internet (redirect)"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-alb-sg"
}
}
resource "aws_security_group" "ecs" {
name_prefix = "${var.project_name}-${var.environment}-ecs"
vpc_id = aws_vpc.main.id
ingress {
from_port = 3000
to_port = 3003
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
description = "Service ports from ALB only"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-ecs-sg"
}
}
resource "aws_security_group" "rds" {
name_prefix = "${var.project_name}-${var.environment}-rds"
vpc_id = aws_vpc.main.id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.ecs.id]
description = "PostgreSQL from ECS"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-rds-sg"
}
}
resource "aws_security_group" "elasticache" {
name_prefix = "${var.project_name}-${var.environment}-elasticache"
vpc_id = aws_vpc.main.id
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
security_groups = [aws_security_group.ecs.id]
description = "Redis from ECS"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.environment}-elasticache-sg"
}
}
resource "aws_flow_log" "main" {
iam_role_arn = aws_iam_role.flow_log.arn
log_destination = aws_cloudwatch_log_group.flow_log.arn
vpc_id = aws_vpc.main.id
traffic_type = "ALL"
tags = {
Name = "${var.project_name}-${var.environment}-flow-log"
}
}
resource "aws_iam_role" "flow_log" {
name = "${var.project_name}-${var.environment}-flow-log-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy" "flow_log" {
name = "${var.project_name}-${var.environment}-flow-log-policy"
role = aws_iam_role.flow_log.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Effect = "Allow"
Resource = [aws_cloudwatch_log_group.flow_log.arn]
}
]
})
}
resource "aws_cloudwatch_log_group" "flow_log" {
name = "/${var.project_name}/${var.environment}/vpc-flow-log"
retention_in_days = var.environment == "production" ? 30 : 7
kms_key_id = var.kms_key_arn != "" ? var.kms_key_arn : null
tags = {
Name = "${var.project_name}-${var.environment}-flow-log"
}
}
output "vpc_id" {
description = "VPC ID"
value = aws_vpc.main.id
}
output "private_subnet_ids" {
description = "Private subnet IDs"
value = aws_subnet.private[*].id
}
output "public_subnet_ids" {
description = "Public subnet IDs"
value = aws_subnet.public[*].id
}
output "alb_security_group_id" {
description = "ALB security group ID"
value = aws_security_group.alb.id
}
output "ecs_security_group_id" {
description = "ECS security group ID"
value = aws_security_group.ecs.id
}
output "rds_security_group_id" {
description = "RDS security group ID"
value = aws_security_group.rds.id
}
output "elasticache_security_group_id" {
description = "ElastiCache security group ID"
value = aws_security_group.elasticache.id
}