Terraform EKS Node Groups: Managed Workloads with CloudPosse and Terraform AWS Modules

Building a production Kubernetes platform on AWS with Terraform requires precise control over the EKS control plane, the VPC networking it lives in, and the worker capacity that actually runs workloads. EKS Managed Node Groups provide AWS-managed EC2 lifecycle handling for worker nodes, and Terraform modules codify the creation of those node groups alongside the cluster and supporting networking. This article covers how the CloudPosse terraform-aws-eks-node-group module and the community terraform-aws-modules/terraform-aws-eks module model managed node groups, how VPC design and launch template customization fit into the workflow, and the operational constraints that shape safe deployments.

What Managed Node Groups Provide in EKS

Running Kubernetes on AWS means running EKS. When worker nodes are managed by AWS and patched, updated, and drained gracefully during upgrades, managed node groups are the way to go. They handle the EC2 lifecycle so teams can focus on workloads instead of babysitting instances.

A managed node group is an AWS-managed EC2 Auto Scaling group for EKS. Terraform can provision it after, or in parallel with, an EKS cluster. The module terraform-aws-eks-node-group is designed to provision an EKS Managed Node Group for Elastic Kubernetes Service. It can be instantiated multiple times to create EKS Managed Node Groups with specific settings such as GPUs, EC2 instance types, or autoscale parameters.

The module creates an EKS Managed Node Group for an EKS cluster. It assumes you have already created an EKS cluster, but you can create the cluster and the node group in the same Terraform configuration. A full-featured root module, a.k.a. component, eks/cluster is provided as an example of doing that.

Module Architecture and Launch Template Behavior

The CloudPosse module always uses a launch template to create the node group. You can create your own launch template and pass in its ID, or else this module will create one for you.

A key AWS behavior is that the default for EKS is that if the launch template is updated, the existing nodes will not be affected. Only new instances added to the node group would get the changes specified in the new launch template. This means launch template versioning and node replacement must be managed explicitly when in-place updates are required.

Security posture is enforced explicitly. When SSH access is enabled without specifying a source security group, this module provisions EKS Node Group nodes that are globally accessible by SSH port 22. Normally, AWS recommends that no security group allows unrestricted ingress access to port 22. Safe configurations require a source security group or a restricted CIDR.

Typical VPC and Network Layout for EKS

In practice a post explaining how to deploy an EKS Cluster and EC2 node group using Terraform uses the following architecture:

The Architecture consists of a VPC with 2 public subnets and 2 private subnets in different Availability Zones. Each public subnet contains a nat gateway that allows private subnets to access the Internet.

The EKS nodes will be create in the private subnets.

This pattern aligns with the prerequisite that EKS needs subnets across at least two availability zones. Building the VPC as part of the setup is common when starting from scratch.

A representative variable definition for networking used by a custom VPC module is:

hcl variable "networking" { type = object({ cidr_block = string vpc_name = string azs = list(string) public_subnets = list(string) private_subnets = list(string) nat_gateways = bool }) default = { cidr_block = "10.0.0.0/16" vpc_name = "terraform-vpc" azs = ["us-east-1a", "us-east-1b"] public_subnets = ["10.0.1.0/24", "10.0.2.0/24"] private_subnets = ["10.0.3.0/24", "10.0.4.0/24"] nat_gateways = true } }

Security groups for the VPC may be defined with SSH ingress. An example default is:

hcl variable "security_groups" { type = list(object({ name = string description = string ingress = object({ description = string protocol = string from_port = number to_port = number cidr_blocks = list(string) ipv6_cidr_blocks = list(string) }) })) default = [{ name = "ssh" description = "Port 22" ingress = { description = "Allow SSH access" protocol = "tcp" from_port = 22 to_port = 22 cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = null } }] }

A module call for the VPC is shown as:

hcl module "aws_vpc" { source = "github.com/erozedguy/AWS-VPC-terraform-module.git" networking = var.networking security_groups = var.security_groups }

Kubernetes clusters managed by Amazon EKS make calls to other AWS services on your behalf to manage the resources that you use with the service. This underlines the need for IAM roles and networking that allow the control plane to reach worker nodes and AWS APIs.

Provider and Prerequisites for Managed Node Groups

A production-ready setup starts with provider constraints and region selection. A common baseline is:

```hcl
terraform {
requiredversion = ">= 1.5.0"
required
providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = "us-east-1"
}
```

Prerequisites include the AWS provider configured and a VPC with subnets ready. If starting from scratch, the VPC is built as part of this setup.

The guide walks through building a production-ready EKS cluster with managed node groups in Terraform. We will cover the VPC, IAM roles, the cluster itself, node groups with different instance types, and launch template customization.

Defining Managed Node Groups with Terraform AWS Modules

The Terraform AWS Modules repository provides a module which creates Amazon EKS resources. Documentation covers Frequently Asked Questions, Compute Resources, User Data, Network Connectivity, Upgrade Guides.

A minimal managed node group definition uses subnets and scaling parameters:

```hcl

["subnet-xyzde987", "subnet-slkjf456", "subnet-qeiru789"]

eksmanagednodegroups = {
example = {
# Starting on 1.30, AL2023 is the default AMI type for EKS managed node groups
ami
type = "AL2023x8664STANDARD"
instance
types = ["m5.xlarge"]
minsize = 2
max
size = 10
desired_size = 2
}
}

tags = {
Environment = "dev"
Terraform = "true"
}
```

When enabling authenticationmode = "APIANDCONFIGMAP", EKS will automatically create an access entry for the IAM role(s) used by managed node group(s) and Fargate profile(s).

The nodes in a sample deployment are EC2 t3-micro instances managed by EKS. Instance type selection is driven by workload requirements, cost, and GPU needs.

Configuration Options and Constraints

The following table summarizes key configuration dimensions drawn from the reference implementations:

Dimension Option Notes
AMI type AL2023x8664_STANDARD Default from EKS 1.30 onward
Instance types m5.xlarge, t3-micro Can be mixed across node groups
Scaling minsize, maxsize, desired_size Autoscale parameters for the node group
Launch template Provided or created by module Module always uses a launch template
Subnet placement Private subnets across >=2 AZs Nodes created in private subnets
SSH access Enabled with source SG or open Open 22 is discouraged by AWS

The VPC layout table illustrates the typical split:

Tier Subnets Purpose
Public 2 subnets in 2 AZs NAT gateways, internet access
Private 2 subnets in 2 AZs EKS worker nodes

Windows Managed Node Groups

Windows managed node-groups have a few pre-requisites.

  • Your cluster must contain at least one linux based worker node
  • Your EKS Cluster must have the AmazonEKSVPCResourceController and AmazonEKSClusterPolicy policies attached
  • Your cluster must have a config-map called amazon-vpc-cni with the following content

yaml apiVersion: v1 kind: ConfigMap metadata: name: amazon-vpc-cni namespace: kube-system data: enable-windows-ipam: "true"

  • Windows nodes will automatically be tainted

hcl kubernetes_taints = [{ key = "WINDOWS" value = "true" effect = "NO_SCHEDULE" }]

  • Any pods that target Windows will need to have the following attributes set in their manifest

yaml nodeSelector: kubernetes.io/os: windows kubernetes.io/arch: amd64

Related Terraform Modules and Ecosystem

Check out these related projects:

  • terraform-aws-eks-cluster - Terraform module to provision an EKS cluster on AWS
  • terraform-aws-eks-workers - Terraform module to provision an AWS AutoScaling Group, IAM Role, and Security Group for EKS Workers
  • terraform-aws-ec2-autoscale-group - Terraform module to provision Auto Scaling Group and Launch Template on AWS
  • terraform-aws-ecs-container-definition - Terraform module to generate well-formed JSON documents (container definitions) that are passed to the awsecstask_definition Terraform resource
  • terraform-aws-ecs-alb-service-task - Terraform module which implements an ECS service which exposes a web service via ALB
  • terraform-aws-ecs-web-app - Terraform module that implements a web app on ECS and supports

Operational Caveats and Auto Mode

Caution: Due to the current EKS Auto Mode API, to disable EKS Auto Mode you will have to explicitly set:

hcl compute_config = { enabled = false }

If you try to disable by simply removing the compute_config block, this will fail to disable EKS Auto Mode.

The module documentation notes that we strive to provide a comprehensive suite of documentation for configuring and utilizing the module(s) defined here, and that documentation regarding EKS (including EKS managed node group, self managed node group, and Fargate profile) and/or Kubernetes features, usage, etc. are better left up to their respective sources.

Conclusion

Terraform EKS node group automation centers on separating control plane creation from worker capacity provisioning while keeping networking, IAM, and launch configuration explicit. The CloudPosse terraform-aws-eks-node-group module provides a reusable construct for managed node groups with launch template driven node creation, multiple instantiation for GPU or autoscale variants, and a clear warning about unrestricted SSH exposure. The Terraform AWS Modules approach integrates node groups into a full EKS cluster definition with VPC prerequisites, AMI type selection such as AL2023x8664STANDARD, and scaling parameters minsize, maxsize, and desiredsize.

Production patterns consistently place nodes in private subnets across at least two availability zones, back those subnets with NAT gateways in public subnets, and define security groups that avoid open ingress on port 22. Launch template updates require awareness that existing nodes are not replaced automatically; new instances receive changes. Windows node groups add CNI configuration, policy attachments, and taint requirements.

Together these constraints and modules enable repeatable, auditable EKS worker provisioning that aligns with AWS recommendations for security, availability, and upgrade safety.

Sources

  1. terraform-aws-eks-node-group
  2. Creating an EKS Cluster and Node Group with Terraform
  3. Create EKS Cluster Managed Node Groups Terraform
  4. terraform-aws-modules/terraform-aws-eks

Related Posts