EKS
Terraform
Node-Group
Deployment Error
Cloud Infrastructure

Error deploying EKS node-group with terraform

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Managed node groups in Amazon EKS are straightforward once the cluster, IAM role, and subnets are aligned, but Terraform failures can be frustrating because the first error often appears far from the real cause. The reliable way to debug them is to verify dependency order, required IAM policies, and network settings before assuming Terraform itself is broken.

Start with the Actual Failure Signal

When terraform apply reports that an aws_eks_node_group resource failed, collect the AWS-side status first. Terraform usually shows only that creation timed out or entered CREATE_FAILED, while AWS keeps the reason.

bash
1aws eks describe-nodegroup \
2  --cluster-name my-cluster \
3  --nodegroup-name app-nodes \
4  --query 'nodegroup.[status,health.issues]'

That command often reveals specific health issues such as missing permissions, unsupported subnets, or instance launch problems. It is also worth checking the EKS cluster itself:

bash
aws eks describe-cluster \
  --name my-cluster \
  --query 'cluster.status'

If the cluster is not fully ACTIVE, the node group may fail even though the Terraform configuration looks syntactically correct.

A Minimal Working Terraform Shape

The node group needs three things to be in place before creation starts: an active cluster, a node IAM role with the required managed policies, and subnets that can actually host worker nodes. The following configuration shows the essential dependencies:

hcl
1resource "aws_iam_role" "node_group" {
2  name = "eks-node-group-role"
3
4  assume_role_policy = jsonencode({
5    Version = "2012-10-17"
6    Statement = [
7      {
8        Action = "sts:AssumeRole"
9        Effect = "Allow"
10        Principal = {
11          Service = "ec2.amazonaws.com"
12        }
13      }
14    ]
15  })
16}
17
18resource "aws_iam_role_policy_attachment" "worker_node" {
19  role       = aws_iam_role.node_group.name
20  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
21}
22
23resource "aws_iam_role_policy_attachment" "cni" {
24  role       = aws_iam_role.node_group.name
25  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
26}
27
28resource "aws_iam_role_policy_attachment" "ecr_readonly" {
29  role       = aws_iam_role.node_group.name
30  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
31}
32
33resource "aws_eks_node_group" "app" {
34  cluster_name    = aws_eks_cluster.main.name
35  node_group_name = "app-nodes"
36  node_role_arn   = aws_iam_role.node_group.arn
37  subnet_ids      = var.private_subnet_ids
38  instance_types  = ["t3.medium"]
39
40  scaling_config {
41    desired_size = 2
42    min_size     = 1
43    max_size     = 4
44  }
45
46  depends_on = [
47    aws_iam_role_policy_attachment.worker_node,
48    aws_iam_role_policy_attachment.cni,
49    aws_iam_role_policy_attachment.ecr_readonly,
50  ]
51}

The explicit depends_on is important. Terraform can infer some relationships, but policy attachments are a classic place where AWS reads the role before the last attachment finishes propagating.

The Most Common Root Causes

IAM is the first thing to verify. A managed node group typically needs AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, and AmazonEC2ContainerRegistryReadOnly. If one is missing, instances may launch and still fail to join the cluster.

Networking is next. The subnets supplied to the node group must belong to the same VPC as the cluster, have enough available IP addresses, and provide a path to the EKS control plane and image registries. In private subnet setups, this usually means working NAT or VPC endpoints for the services your bootstrap process touches.

Capacity and instance type problems also matter. A valid Terraform plan can still fail at runtime if the selected instance type is unavailable in the target Availability Zone or not supported by your launch constraints. If you suspect this, temporarily try a widely available type such as t3.medium in a region that supports it.

Finally, make sure the cluster reaches ACTIVE before worker creation starts. If the EKS control plane, security groups, or endpoint access settings are still settling, node registration can fail even though the IAM role is correct.

A Useful Troubleshooting Workflow

A short, repeatable workflow saves time:

bash
1terraform plan
2terraform apply
3aws eks describe-nodegroup --cluster-name my-cluster --nodegroup-name app-nodes
4aws ec2 describe-subnets --subnet-ids subnet-aaa subnet-bbb

If Terraform output is still too vague, enable provider logging for one run:

bash
TF_LOG=DEBUG terraform apply

Use that sparingly because it produces a lot of noise, but it can confirm whether the provider sent the expected subnet IDs, role ARN, and scaling configuration.

Common Pitfalls

One common mistake is assuming that a successful cluster resource means the cluster is ready for nodes immediately. In practice, the safest approach is to let Terraform reference the cluster resource directly and verify the cluster status if node creation fails.

Another pitfall is omitting one of the three baseline IAM policies from the worker role. The resource may still be created, but the instances will not behave like healthy Kubernetes workers.

Subnet configuration causes many hard-to-read failures. Private subnets without egress, public subnets with inconsistent route tables, or subnets from the wrong VPC can all produce node group errors that look unrelated at first glance.

It is also easy to chase Terraform syntax when the real issue is AWS capacity. If a deployment works in one Availability Zone and not another, instance availability is often the reason.

Summary

  • Check aws eks describe-nodegroup first to get the AWS-side failure reason.
  • Ensure the cluster is ACTIVE before expecting a managed node group to succeed.
  • Attach the required node IAM policies before creating the node group.
  • Verify subnet correctness, available IPs, and outbound connectivity for worker nodes.
  • Use TF_LOG=DEBUG only when the normal Terraform output does not reveal enough detail.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.