diff --git a/tofu/eks.tofu b/tofu/eks.tofu index 1185fa7..a06f5e3 100644 --- a/tofu/eks.tofu +++ b/tofu/eks.tofu @@ -136,13 +136,21 @@ resource "kubernetes_storage_class_v1" "efs" { volume_binding_mode = "Immediate" } -module "eks_managed_node_group" { +# ── Self-managed node groups ────────────────────────────────────────────────── +# Self-managed nodes give full control over the launch template and ASG. +# SPOT is configured via instance_market_options instead of capacity_type. +# The module creates its own IAM role + instance profile and registers an +# access entry so nodes can join the cluster automatically. + +# ── EKS managed node groups ─────────────────────────────────────────────────── + +module "eks_managed_node_group_application" { source = "terraform-aws-modules/eks/aws//modules/eks-managed-node-group" version = local.vars.versions.eks create = local.vars.eks.create - name = terraform.workspace + name = "${terraform.workspace}-application" cluster_name = terraform.workspace kubernetes_version = local.vars.eks.cluster_version cluster_service_cidr = module.eks.cluster_service_cidr @@ -161,7 +169,6 @@ module "eks_managed_node_group" { instance_types = ["t4g.small"] capacity_type = "SPOT" - block_device_mappings = { xvda = { device_name = "/dev/xvda" @@ -185,6 +192,103 @@ module "eks_managed_node_group" { } } +module "eks_managed_node_group_ingress_controller" { + source = "terraform-aws-modules/eks/aws//modules/eks-managed-node-group" + version = local.vars.versions.eks + + create = local.vars.eks.create + + name = "${terraform.workspace}-ingress" + cluster_name = terraform.workspace + kubernetes_version = local.vars.eks.cluster_version + cluster_service_cidr = module.eks.cluster_service_cidr + + subnet_ids = module.vpc.private_subnets + + cluster_primary_security_group_id = module.eks.cluster_primary_security_group_id + vpc_security_group_ids = [module.eks.node_security_group_id] + + ami_type = "AL2023_ARM_64_STANDARD" + + min_size = 1 + max_size = 1 + desired_size = 1 + + instance_types = ["t4g.small"] + capacity_type = "SPOT" + + block_device_mappings = { + xvda = { + device_name = "/dev/xvda" + ebs = { + volume_type = "gp3" + encrypted = true + } + } + } + + taints = { + dedicated = { + key = "ingress-controller" + value = "true" + effect = "NO_SCHEDULE" + } + } + + iam_role_additional_policies = { + AmazonEBSCSIDriverPolicy = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy" + } +} + +module "eks_managed_node_group_core_addons" { + source = "terraform-aws-modules/eks/aws//modules/eks-managed-node-group" + version = local.vars.versions.eks + + create = local.vars.eks.create + + name = "${terraform.workspace}-core-addons" + cluster_name = terraform.workspace + kubernetes_version = local.vars.eks.cluster_version + cluster_service_cidr = module.eks.cluster_service_cidr + + subnet_ids = module.vpc.private_subnets + + cluster_primary_security_group_id = module.eks.cluster_primary_security_group_id + vpc_security_group_ids = [module.eks.node_security_group_id] + + ami_type = "AL2023_ARM_64_STANDARD" + + min_size = 1 + max_size = 1 + desired_size = 1 + + instance_types = ["t4g.small"] + capacity_type = "SPOT" + + block_device_mappings = { + xvda = { + device_name = "/dev/xvda" + ebs = { + volume_type = "gp3" + encrypted = true + } + } + } + + taints = { + dedicated = { + key = "core-addons" + value = "true" + effect = "NO_SCHEDULE" + } + } + + iam_role_additional_policies = { + AmazonEBSCSIDriverPolicy = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy" + } +} + + module "irsa_efs_csi" { source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts" version = local.vars.versions.iam diff --git a/tofu/nlb.tofu b/tofu/nlb.tofu new file mode 100644 index 0000000..1c418a2 --- /dev/null +++ b/tofu/nlb.tofu @@ -0,0 +1,134 @@ +resource "aws_security_group" "nlb" { + count = local.vars.nlb.create ? 1 : 0 + + name_prefix = "${terraform.workspace}-nlb-" + description = "NLB fronting EKS ingress-controller nodes" + vpc_id = module.vpc.vpc_id + + ingress { + description = "HTTP" + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + description = "HTTPS/TLS" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + description = "Outbound to VPC" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [local.vars.vpc.cidr] + } + + lifecycle { + create_before_destroy = true + } +} + +# Allow the NLB to reach port 80 on the ingress-controller nodes. +resource "aws_security_group_rule" "nodes_allow_nlb_http" { + count = local.vars.nlb.create ? 1 : 0 + + description = "Allow NLB to reach port 80 on ingress-controller nodes" + type = "ingress" + from_port = 80 + to_port = 80 + protocol = "tcp" + security_group_id = module.eks.node_security_group_id + source_security_group_id = aws_security_group.nlb[0].id +} + +# NLB health check probes originate from the NLB node's private IP, not from +# the NLB security group — so source_security_group_id does not work here. +# Allow port 1042 from the VPC CIDR so health checks can reach HAProxy. +resource "aws_security_group_rule" "nodes_allow_nlb_healthcheck" { + count = local.vars.nlb.create ? 1 : 0 + + description = "Allow NLB health checks on port 1042 from VPC" + type = "ingress" + from_port = 1042 + to_port = 1042 + protocol = "tcp" + security_group_id = module.eks.node_security_group_id + cidr_blocks = [local.vars.vpc.cidr] +} + +module "nlb" { + source = "terraform-aws-modules/alb/aws" + version = local.vars.versions.alb + + create = local.vars.nlb.create + + name = "${terraform.workspace}-public" + load_balancer_type = "network" + vpc_id = module.vpc.vpc_id + subnets = module.vpc.public_subnets + security_groups = local.vars.nlb.create ? [aws_security_group.nlb[0].id] : [] + internal = local.vars.nlb.internal + + enable_cross_zone_load_balancing = true + + target_groups = { + http = { + name = "${terraform.workspace}-http" + protocol = "TCP" + port = 80 + target_type = "instance" + vpc_id = module.vpc.vpc_id + deregistration_delay = 30 + + # Targets are managed by aws_autoscaling_attachment below — + # do not let the module register static targets. + create_attachment = false + + health_check = { + enabled = true + healthy_threshold = 2 + unhealthy_threshold = 2 + interval = 10 + protocol = "HTTP" + port = "1042" + path = "/healthz" + success_codes = "200-299" + } + } + } + + listeners = { + tcp_80 = { + port = 80 + protocol = "TCP" + + forward = { + target_group_key = "http" + } + } + + tls_443 = { + port = 443 + protocol = "TLS" + certificate_arn = "arn:aws:acm:${var.aws_region}:${var.account_id}:certificate/e3edb543-521e-4592-a9aa-4b817dc2c2e9" + ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06" + + forward = { + target_group_key = "http" + } + } + } +} + +resource "aws_autoscaling_attachment" "ingress_to_nlb" { + count = local.vars.nlb.create ? 1 : 0 + + autoscaling_group_name = module.eks_managed_node_group_ingress_controller.node_group_resources[0].autoscaling_groups[0].name + lb_target_group_arn = module.nlb.target_groups["http"].arn +} diff --git a/tofu/outputs.tofu b/tofu/outputs.tofu index 495141b..7b7258f 100644 --- a/tofu/outputs.tofu +++ b/tofu/outputs.tofu @@ -1,3 +1,13 @@ # output "eks" { # value = module.eks -# } \ No newline at end of file +# } + +output "nlb_dns_name" { + description = "NLB DNS name — create a CNAME record pointing to this" + value = local.vars.nlb.create ? module.nlb.dns_name : null +} + +output "nlb_arn" { + description = "NLB ARN" + value = local.vars.nlb.create ? module.nlb.arn : null +} diff --git a/tofu/vars/vars.yaml b/tofu/vars/vars.yaml index 3f3cf73..8c1c3cc 100644 --- a/tofu/vars/vars.yaml +++ b/tofu/vars/vars.yaml @@ -1,5 +1,6 @@ --- versions: + alb: v9.13.0 cloudfront: v6.7.0 ec2: v6.4.0 ecs: v7.5.0 @@ -33,9 +34,17 @@ eks: - namespace: "kube-system" labels: "eks.amazonaws.com/component": "coredns" + - name: "gha-runners" + selectors: + - namespace: "gha-runner" + labels: + "app.kubernetes.io/name": "gha-runner" iam: github_oidc: repos: ["harik8/manalpetti:*","harik8/hariprasad.dev:*","harik8/awsing:*"] +nlb: + create: false + internal: false rds: psql: create: false