# Application Infrastructure - Uses remote state backend # This contains your ECS cluster, VPC, and application resources terraform { backend "s3" { # These values will be provided via backend-config during terraform init # bucket = "nvhi-atsila-tf-state" # key = "ecs/terraform.tfstate" # region = "us-east-2" # dynamodb_table = "nvhi-atsila-locks" } required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { region = var.aws_region } data "aws_availability_zones" "azs" {} # VPC resource "aws_vpc" "main" { cidr_block = var.vpc_cidr enable_dns_hostnames = true enable_dns_support = true tags = { Name = "${var.cluster_name}-vpc" } } # Internet Gateway resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id tags = { Name = "${var.cluster_name}-igw" } } # Public Subnets resource "aws_subnet" "public" { count = length(split(",", var.public_subnets)) vpc_id = aws_vpc.main.id cidr_block = element(split(",", var.public_subnets), count.index) availability_zone = data.aws_availability_zones.azs.names[count.index] map_public_ip_on_launch = true tags = { Name = "${var.cluster_name}-public-${count.index}" } } # Route Table for public subnets 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.cluster_name}-public-rt" } } # Route Table Associations resource "aws_route_table_association" "public" { count = length(aws_subnet.public) subnet_id = aws_subnet.public[count.index].id route_table_id = aws_route_table.public.id } # Security Group resource "aws_security_group" "ecs_sg" { name = "${var.cluster_name}-sg" description = "Allow SSH & HTTP to ECS" vpc_id = aws_vpc.main.id ingress { description = "SSH from Jenkins" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = [var.jenkins_ip_cidr] } ingress { description = "HTTP from anywhere" from_port = 8080 to_port = 8080 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { description = "All outbound traffic" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "${var.cluster_name}-sg" } } # Key Pair - Using hardcoded public key from your original config resource "aws_key_pair" "deployer" { key_name = var.key_pair_name public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDDFBAOogBj/GHKXQs6FLROGQfXkZe2uKbRron0We7ZOLgt6e1bI7U8IMe+DIH250CHSi4R5DBYFQF5Bk1TkS5cgMtPIAb87vRUGI3sLs29DQA/kllYiZlQi9ejxcEz2+TRWn10Q/Kltlb6ESNLnnnTsIUUxKUeY3MKFFd+V13FleSVLGYondwPWYwD/XJ6a3VwSTJ1wFKO+lpKknSjDl2ZOgYpWFALPH+EwMlRGVMrUXAB604zqR1XOzYXAAWnhmmC9IGgCzU/5JnEgFyhfZbR3kpEH8SmSXahvdFZERp+3j9d3ROjchqnf0Z0zZ7vzX+G+jvzT/jGOkzH9tx0/OqIO9f47OFF8iUfZgUtJU1QGbepdsmQqognhxfJQfMZbVtKUw7zt+mzJz3A0XcRp7IwVHaqJ2QW2dpXi4UbWtejtZqROg6byWq2FpvFGNIT3eiKTf+EpCoOec6YGSrRQlj73Ob0+FhmsyQ6e8KKncaRYx38PqtnWsI3UnLtdKmEJmDBPI0ipxJzmKJKtb0vtJPVYvFEpgiXSwnDX883rAUQrXR/EhOMmbMwk7JSes6/GXH9rWN10JHh1/i1LLpl+rg6VyktFgVBHzVw++y29QSfFixeTvFkkTS5kl//CpKd1GDQb9ZBH6SPgkgOjmASPUo+p5e/NiN/SIBSpYpMjOKs7Q== jacques@Xochiquetzal" tags = { Name = var.key_pair_name } } # Get Amazon Linux 2 AMI (better for ECS) data "aws_ami" "amazon_linux" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["amzn2-ami-ecs-hvm-*-x86_64-ebs"] } filter { name = "virtualization-type" values = ["hvm"] } } # IAM Role for ECS Instance resource "aws_iam_role" "ecs_instance_role" { name = "${var.cluster_name}-ecs-instance-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } } ] }) tags = { Name = "${var.cluster_name}-ecs-instance-role" } } # IAM Role Policy Attachment resource "aws_iam_role_policy_attachment" "ecs_instance_role_policy" { role = aws_iam_role.ecs_instance_role.name policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" } # IAM Instance Profile resource "aws_iam_instance_profile" "ecs_instance_profile" { name = "${var.cluster_name}-ecs-instance-profile" role = aws_iam_role.ecs_instance_role.name tags = { Name = "${var.cluster_name}-ecs-instance-profile" } } # ECS Cluster resource "aws_ecs_cluster" "main" { name = var.cluster_name setting { name = "containerInsights" value = "enabled" } tags = { Name = var.cluster_name } } # User data script for ECS instance locals { user_data = base64encode(<<-EOF #!/bin/bash yum update -y yum install -y ecs-init echo ECS_CLUSTER=${var.cluster_name} >> /etc/ecs/ecs.config service docker start start ecs EOF ) } # EC2 Instance for ECS resource "aws_instance" "ecs_instance" { ami = data.aws_ami.amazon_linux.id instance_type = var.instance_type subnet_id = aws_subnet.public[0].id vpc_security_group_ids = [aws_security_group.ecs_sg.id] key_name = aws_key_pair.deployer.key_name iam_instance_profile = aws_iam_instance_profile.ecs_instance_profile.name user_data_base64 = local.user_data root_block_device { volume_type = "gp3" volume_size = 20 encrypted = true } tags = { Name = "${var.cluster_name}-instance" } } # ECS Service (placeholder - you may want to manage this separately) resource "aws_ecs_service" "main" { name = "${var.cluster_name}-service" cluster = aws_ecs_cluster.main.id desired_count = 1 launch_type = "EC2" # This will be updated by your Jenkins pipeline task_definition = "${var.cluster_name}:1" depends_on = [aws_instance.ecs_instance] lifecycle { ignore_changes = [task_definition] } tags = { Name = "${var.cluster_name}-service" } } # CloudWatch Log Group for ECS resource "aws_cloudwatch_log_group" "ecs_logs" { name = "/ecs/${var.cluster_name}" retention_in_days = 7 tags = { Name = "${var.cluster_name}-logs" } } # Outputs output "ecs_instance_public_ip" { description = "Public IP of the ECS instance" value = aws_instance.ecs_instance.public_ip } output "ecs_cluster_name" { description = "Name of the ECS cluster" value = aws_ecs_cluster.main.name } output "vpc_id" { description = "ID of the VPC" value = aws_vpc.main.id } output "public_subnet_ids" { description = "IDs of the public subnets" value = aws_subnet.public[*].id }