From 7646b12392e7e5608a3cceba74f8303cc4313f1c Mon Sep 17 00:00:00 2001 From: Conan Scott Date: Wed, 1 Jul 2026 04:52:49 +0000 Subject: [PATCH] Add ECS Fargate hosting for Fusion + Presidio (demo-simple, default VPC) --- terraform/ecs.tf | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 terraform/ecs.tf diff --git a/terraform/ecs.tf b/terraform/ecs.tf new file mode 100644 index 0000000..d6e3d6f --- /dev/null +++ b/terraform/ecs.tf @@ -0,0 +1,132 @@ +# --------------------------------------------------------------------------- +# Hosting for the two long-running containers: Fusion (the gateway) and the +# Presidio detector. Kept intentionally simple for a demo: default VPC, public +# subnets, Fargate. For a first pass you can also run both containers locally +# and skip this file entirely (see README "Lightweight path"). +# +# NOTE: var.fusion_image_uri and var.presidio_image_uri must be set first +# (scripts/deploy.sh builds+pushes Presidio; you supply the Axway image). +# --------------------------------------------------------------------------- + +data "aws_vpc" "default" { default = true } + +data "aws_subnets" "default" { + filter { + name = "vpc-id" + values = [data.aws_vpc.default.id] + } +} + +resource "aws_ecs_cluster" "this" { + name = "${local.name}-cluster" + tags = local.onprem_tag +} + +resource "aws_security_group" "svc" { + name = "${local.name}-svc-sg" + description = "Demo services SG" + vpc_id = data.aws_vpc.default.id + ingress { + description = "Fusion gateway" + from_port = 8080 + to_port = 8080 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] # DEMO ONLY - lock down for anything real + } + ingress { + description = "Presidio analyzer" + from_port = 5001 + to_port = 5001 + protocol = "tcp" + self = true + } + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + tags = local.onprem_tag +} + +resource "aws_iam_role" "ecs_exec" { + name = "${local.name}-ecs-exec" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { Service = "ecs-tasks.amazonaws.com" } + Action = "sts:AssumeRole" + }] + }) +} + +resource "aws_iam_role_policy_attachment" "ecs_exec" { + role = aws_iam_role.ecs_exec.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +# Task role for Fusion: it needs to invoke Bedrock/AgentCore and read/write the vault. +resource "aws_iam_role" "fusion_task" { + name = "${local.name}-fusion-task" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { Service = "ecs-tasks.amazonaws.com" } + Action = "sts:AssumeRole" + }] + }) +} + +resource "aws_iam_role_policy" "fusion_task" { + name = "${local.name}-fusion-task-policy" + role = aws_iam_role.fusion_task.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { Effect = "Allow", Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query"], Resource = [aws_dynamodb_table.vault.arn] }, + { Effect = "Allow", Action = ["bedrock:InvokeModel", "bedrock-agentcore:*"], Resource = "*" } + ] + }) +} + +locals { + services = { + fusion = { image = var.fusion_image_uri, port = 8080, task_role = aws_iam_role.fusion_task.arn, tag = local.onprem_tag } + presidio = { image = var.presidio_image_uri, port = 5001, task_role = aws_iam_role.ecs_exec.arn, tag = local.onprem_tag } + } +} + +resource "aws_ecs_task_definition" "svc" { + for_each = local.services + family = "${local.name}-${each.key}" + requires_compatibilities = ["FARGATE"] + network_mode = "awsvpc" + cpu = 512 + memory = 1024 + execution_role_arn = aws_iam_role.ecs_exec.arn + task_role_arn = each.value.task_role + container_definitions = jsonencode([{ + name = each.key + image = each.value.image + essential = true + portMappings = [{ containerPort = each.value.port }] + }]) + tags = each.value.tag +} + +resource "aws_ecs_service" "svc" { + for_each = local.services + name = "${local.name}-${each.key}" + cluster = aws_ecs_cluster.this.id + task_definition = aws_ecs_task_definition.svc[each.key].arn + desired_count = 1 + launch_type = "FARGATE" + network_configuration { + subnets = data.aws_subnets.default.ids + security_groups = [aws_security_group.svc.id] + assign_public_ip = true + } + tags = each.value.tag +}