# Node IAM role ============================================================== resource "aws_iam_role" "node" { for_each = var.create_node_role && var.node_role_arn == null ? { role = true } : {} name = "${var.cluster_name}-node-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } Action = "sts:AssumeRole" }] }) tags = local.tags } resource "aws_iam_role_policy_attachment" "node" { for_each = var.create_node_role && var.node_role_arn == null ? toset([ "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKSWorkerNodePolicy", "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKS_CNI_Policy", "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonSSMManagedInstanceCore", ]) : toset([]) role = aws_iam_role.node["role"].name policy_arn = each.value } # Managed node groups ======================================================== resource "aws_eks_node_group" "this" { for_each = var.node_groups cluster_name = var.cluster_name node_group_name = each.value.name node_role_arn = local.effective_node_role_arn subnet_ids = each.value.subnet_ids instance_types = each.value.instance_types ami_type = each.value.ami_type capacity_type = each.value.capacity_type disk_size = each.value.disk_size scaling_config { min_size = each.value.min_size max_size = each.value.max_size desired_size = each.value.desired_size } update_config { max_unavailable = each.value.max_unavailable } labels = each.value.labels dynamic "taint" { for_each = each.value.taints content { key = taint.value.key value = taint.value.value effect = taint.value.effect } } # Custom launch template for KMS-encrypted node volumes dynamic "launch_template" { for_each = each.value.kms_key_arn != null ? [each.value.kms_key_arn] : [] content { id = aws_launch_template.node[each.key].id version = aws_launch_template.node[each.key].latest_version } } tags = merge(local.tags, { Name = each.value.name }) lifecycle { ignore_changes = [scaling_config[0].desired_size] } depends_on = [aws_iam_role_policy_attachment.node] } # Per-node-group launch template (only when KMS key is set) ------------------ resource "aws_launch_template" "node" { for_each = { for k, v in var.node_groups : k => v if v.kms_key_arn != null } name_prefix = "${each.value.name}-" metadata_options { http_endpoint = "enabled" http_tokens = "required" http_put_response_hop_limit = 2 } block_device_mappings { device_name = "/dev/xvda" ebs { volume_size = each.value.disk_size volume_type = "gp3" encrypted = true kms_key_id = each.value.kms_key_arn delete_on_termination = true } } lifecycle { create_before_destroy = true } tags = local.tags }