Files
AI-upflux-docprocessor/infra/ecs_alb/main.tf
2026-02-04 13:29:15 -03:00

316 lines
7.3 KiB
HCL

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.27"
}
}
}
provider "aws" {
region = var.aws_region
}
# Get current AWS account
data "aws_caller_identity" "current" {}
# Reference existing VPC
data "aws_vpc" "existing" {
id = var.vpc_id
}
# Reference existing public subnets
data "aws_subnet" "public" {
count = length(var.public_subnet_ids)
id = var.public_subnet_ids[count.index]
}
# Reference existing private subnets (for ECS tasks)
data "aws_subnet" "private" {
count = length(var.private_subnet_ids)
id = var.private_subnet_ids[count.index]
}
# Security Group for ALB (in public subnets)
resource "aws_security_group" "alb" {
name = "${var.app_name}-alb-sg"
description = "Allow inbound traffic to ALB"
vpc_id = data.aws_vpc.existing.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["3.14.44.224/32"]
description = "Allow HTTP from internet"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound"
}
tags = {
Name = "${var.app_name}-alb-sg"
}
}
# Security Group for ECS Tasks (in private subnets)
resource "aws_security_group" "ecs_tasks" {
name = "${var.app_name}-ecs-tasks-sg"
description = "Allow inbound traffic from ALB"
vpc_id = data.aws_vpc.existing.id
ingress {
from_port = 8000
to_port = 8000
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
description = "Allow traffic from ALB"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound"
}
tags = {
Name = "${var.app_name}-ecs-tasks-sg"
}
}
# Application Load Balancer (in public subnets)
resource "aws_lb" "main" {
name = "${var.app_name}-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = var.public_subnet_ids
enable_deletion_protection = false
tags = {
Name = "${var.app_name}-alb"
}
}
# Target Group
resource "aws_lb_target_group" "app" {
name = "${var.app_name}-tg"
port = 8000
protocol = "HTTP"
vpc_id = data.aws_vpc.existing.id
target_type = "ip"
health_check {
enabled = true
healthy_threshold = 2
interval = 30
matcher = "200"
path = "/health"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
unhealthy_threshold = 3
}
deregistration_delay = 30
tags = {
Name = "${var.app_name}-tg"
}
}
# ALB Listener
resource "aws_lb_listener" "app" {
load_balancer_arn = aws_lb.main.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
}
# ECS Cluster
resource "aws_ecs_cluster" "main" {
name = "${var.app_name}-cluster"
tags = {
Name = "${var.app_name}-cluster"
}
}
# CloudWatch Log Group
resource "aws_cloudwatch_log_group" "app" {
name = "/ecs/${var.app_name}"
retention_in_days = 7
tags = {
Name = "${var.app_name}-logs"
}
}
# ECS Task Execution Role
resource "aws_iam_role" "ecs_task_execution_role" {
name = "${var.app_name}-ecs-task-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
resource "aws_iam_role_policy" "bedrock_policy" {
name = "${var.app_name}-bedrock-policy"
role = aws_iam_role.ecs_task_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
"bedrock:GetInferenceProfile"
]
Resource = "*"
}]
})
}
resource "aws_iam_role_policy" "s3_policy" {
name = "${var.app_name}-s3-policy"
role = aws_iam_role.ecs_task_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"s3:GetObject"
]
Resource = "arn:aws:s3:::upflux-doc-analyzer/*"
}]
})
}
resource "aws_iam_role_policy" "textract_policy" {
name = "${var.app_name}-textract-policy"
role = aws_iam_role.ecs_task_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"textract:DetectDocumentText",
"textract:StartDocumentTextDetection",
"textract:GetDocumentTextDetection"
]
Resource = "*"
}]
})
}
# ECS Task Definition
resource "aws_ecs_task_definition" "app" {
family = var.app_name
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = var.fargate_cpu
memory = var.fargate_memory
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn
container_definitions = jsonencode([{
name = var.app_name
image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/${var.ecr_repository_name}:${var.image_tag}"
portMappings = [{
containerPort = 8000
hostPort = 8000
protocol = "tcp"
}]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = aws_cloudwatch_log_group.app.name
"awslogs-region" = var.aws_region
"awslogs-stream-prefix" = "ecs"
}
}
healthCheck = {
command = ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
interval = 30
timeout = 5
retries = 3
startPeriod = 60
}
}])
tags = {
Name = "${var.app_name}-task"
}
}
# ECS Service (tasks in private subnets)
resource "aws_ecs_service" "app" {
name = "${var.app_name}-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = var.app_count
launch_type = "FARGATE"
network_configuration {
security_groups = [aws_security_group.ecs_tasks.id]
subnets = var.private_subnet_ids # ECS tasks in private subnets
assign_public_ip = false # No public IP needed with NAT gateway
}
load_balancer {
target_group_arn = aws_lb_target_group.app.arn
container_name = var.app_name
container_port = 8000
}
depends_on = [aws_lb_listener.app]
tags = {
Name = "${var.app_name}-service"
}
}
#ECS Task Role (for application to call AWS services)
resource "aws_iam_role" "ecs_task_role" {
name = "${var.app_name}-ecs-task-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}]
})
}