# AWS Infrastructure Module # Creates EKS cluster, networking, and supporting resources for AWS environments locals { env = var.environment_config # Extract AWS-specific config aws_config = try(local.env.aws, {}) # Extract infrastructure config infra = try(local.env.infrastructure, {}) k8s_config = try(local.infra.kubernetes, {}) net_config = try(local.infra.networking, {}) # Naming name_prefix = "${local.env.name}-${var.environment}" # Node pools node_pools = try(local.k8s_config.node_pools, {}) } # VPC resource "aws_vpc" "main" { cidr_block = try(local.net_config.vpc_cidr, "10.0.0.0/16") enable_dns_hostnames = true enable_dns_support = true tags = merge(var.tags, { Name = "${local.name_prefix}-vpc" Type = "Multi-Cloud" }) } # Internet Gateway resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id tags = merge(var.tags, { Name = "${local.name_prefix}-igw" }) } # Subnets resource "aws_subnet" "eks" { for_each = { for idx, subnet in try(local.net_config.subnets, []) : subnet.name => subnet if subnet.name == "eks" || subnet.name == "gke" || subnet.name == "aks" } vpc_id = aws_vpc.main.id cidr_block = each.value.cidr availability_zone = try(each.value.availability_zone, data.aws_availability_zones.available.names[0]) map_public_ip_on_launch = true tags = merge(var.tags, { Name = "${local.name_prefix}-subnet-${each.key}" "kubernetes.io/role/elb" = "1" }) } resource "aws_subnet" "validators" { for_each = { for idx, subnet in try(local.net_config.subnets, []) : subnet.name => subnet if subnet.name == "validators" } vpc_id = aws_vpc.main.id cidr_block = each.value.cidr availability_zone = try(each.value.availability_zone, data.aws_availability_zones.available.names[1]) tags = merge(var.tags, { Name = "${local.name_prefix}-subnet-validators" }) } resource "aws_subnet" "rpc" { for_each = { for idx, subnet in try(local.net_config.subnets, []) : subnet.name => subnet if subnet.name == "rpc" } vpc_id = aws_vpc.main.id cidr_block = each.value.cidr availability_zone = try(each.value.availability_zone, data.aws_availability_zones.available.names[0]) map_public_ip_on_launch = true tags = merge(var.tags, { Name = "${local.name_prefix}-subnet-rpc" "kubernetes.io/role/elb" = "1" }) } # Route Table resource "aws_route_table" "main" { vpc_id = aws_vpc.main.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.main.id } tags = merge(var.tags, { Name = "${local.name_prefix}-rt" }) } resource "aws_route_table_association" "subnets" { for_each = merge( aws_subnet.eks, aws_subnet.validators, aws_subnet.rpc ) subnet_id = each.value.id route_table_id = aws_route_table.main.id } # Security Groups resource "aws_security_group" "eks_cluster" { name = "${local.name_prefix}-eks-cluster-sg" description = "Security group for EKS cluster" vpc_id = aws_vpc.main.id egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = merge(var.tags, { Name = "${local.name_prefix}-eks-cluster-sg" }) } resource "aws_security_group" "validators" { name = "${local.name_prefix}-validators-sg" description = "Security group for validator nodes (private)" vpc_id = aws_vpc.main.id ingress { from_port = 30303 to_port = 30303 protocol = "tcp" cidr_blocks = [aws_vpc.main.cidr_block] description = "P2P port from internal" } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = merge(var.tags, { Name = "${local.name_prefix}-validators-sg" }) } resource "aws_security_group" "rpc" { name = "${local.name_prefix}-rpc-sg" description = "Security group for RPC nodes" vpc_id = aws_vpc.main.id ingress { from_port = 8545 to_port = 8545 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] description = "RPC HTTP" } ingress { from_port = 8546 to_port = 8546 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] description = "RPC WebSocket" } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = merge(var.tags, { Name = "${local.name_prefix}-rpc-sg" }) } # EKS Cluster resource "aws_eks_cluster" "main" { name = "${local.name_prefix}-eks" role_arn = aws_iam_role.eks_cluster.arn version = try(local.k8s_config.version, "1.28") vpc_config { subnet_ids = [for s in aws_subnet.eks : s.id] security_group_ids = [aws_security_group.eks_cluster.id] endpoint_private_access = true endpoint_public_access = true } enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"] depends_on = [ aws_cloudwatch_log_group.eks, aws_iam_role_policy_attachment.eks_cluster_policy, ] tags = merge(var.tags, { Name = "${local.name_prefix}-eks" }) } # EKS Node Groups resource "aws_eks_node_group" "system" { count = try(local.node_pools.system.count, 0) > 0 ? 1 : 0 cluster_name = aws_eks_cluster.main.name node_group_name = "system" node_role_arn = aws_iam_role.eks_node.arn subnet_ids = [for s in aws_subnet.eks : s.id] instance_types = [try(local.node_pools.system.instance_type, "t3.medium")] capacity_type = "ON_DEMAND" scaling_config { desired_size = try(local.node_pools.system.count, 1) max_size = try(local.node_pools.system.count, 1) * 2 min_size = 1 } labels = { pool = "system" role = "system" } tags = merge(var.tags, { Name = "${local.name_prefix}-node-system" Pool = "system" }) } resource "aws_eks_node_group" "validators" { count = try(local.node_pools.validators.count, 0) > 0 ? 1 : 0 cluster_name = aws_eks_cluster.main.name node_group_name = "validators" node_role_arn = aws_iam_role.eks_node.arn subnet_ids = [for s in aws_subnet.validators : s.id] instance_types = [try(local.node_pools.validators.instance_type, "t3.medium")] capacity_type = "ON_DEMAND" scaling_config { desired_size = try(local.node_pools.validators.count, 1) max_size = try(local.node_pools.validators.count, 1) * 2 min_size = 1 } labels = { pool = "validators" role = "validator" } taint { key = "role" value = "validator" effect = "NO_SCHEDULE" } tags = merge(var.tags, { Name = "${local.name_prefix}-node-validators" Pool = "validators" }) } resource "aws_eks_node_group" "rpc" { count = try(local.node_pools.rpc.count, 0) > 0 ? 1 : 0 cluster_name = aws_eks_cluster.main.name node_group_name = "rpc" node_role_arn = aws_iam_role.eks_node.arn subnet_ids = [for s in aws_subnet.rpc : s.id] instance_types = [try(local.node_pools.rpc.instance_type, "t3.medium")] capacity_type = "ON_DEMAND" scaling_config { desired_size = try(local.node_pools.rpc.count, 1) max_size = try(local.node_pools.rpc.count, 1) * 2 min_size = 1 } labels = { pool = "rpc" role = "rpc" } tags = merge(var.tags, { Name = "${local.name_prefix}-node-rpc" Pool = "rpc" }) } # Data sources data "aws_availability_zones" "available" { state = "available" } data "aws_caller_identity" "current" {} # IAM Roles and Policies resource "aws_iam_role" "eks_cluster" { name = "${local.name_prefix}-eks-cluster-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "eks.amazonaws.com" } }] }) tags = var.tags } resource "aws_iam_role_policy_attachment" "eks_cluster_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" role = aws_iam_role.eks_cluster.name } resource "aws_iam_role" "eks_node" { name = "${local.name_prefix}-eks-node-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } }] }) tags = var.tags } resource "aws_iam_role_policy_attachment" "eks_worker_node_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" role = aws_iam_role.eks_node.name } resource "aws_iam_role_policy_attachment" "eks_cni_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" role = aws_iam_role.eks_node.name } resource "aws_iam_role_policy_attachment" "eks_container_registry_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" role = aws_iam_role.eks_node.name } # CloudWatch Log Group resource "aws_cloudwatch_log_group" "eks" { name = "/aws/eks/${local.name_prefix}-eks/cluster" retention_in_days = 7 tags = var.tags }