Skip to content

EKS Auto Mode with Terraform

EKS Auto mode Terraform logo

Amazon EKS Auto Mode represents a major evolution in managed Kubernetes on AWS. It delivers an opinionated, fully automated infrastructure experience by managing compute (Karpenter), networking (VPC CNI & ELB Controller), storage (EBS CSI), and security directly as part of the EKS control plane lifecycle.

📁 Source Code: aws-eks-terraform / EKS-Cluster-auto-mode


📺 Video Walkthrough


Why Choose EKS Auto Mode?

In standard EKS, platform teams are responsible for managing, upgrading, and reconciling multiple add-ons (VPC-CNI, CoreDNS, Kube-Proxy, Karpenter, AWS Load Balancer Controller, and EBS CSI Driver). EKS Auto Mode offloads this maintenance to AWS.

Capability Standard EKS EKS Auto Mode
Node Provisioning Manual Managed NodeGroups / Karpenter setup Built-in Karpenter with default NodePool
Storage Driver Self-managed EBS CSI Driver Add-on Automated storage_config block storage
Ingress & Load Balancing Self-managed AWS Load Balancer Controller Automated elastic_load_balancing network config
Pod Networking Self-managed VPC CNI DaemonSet Automated AWS-managed VPC CNI
Cluster Authentication Legacy ConfigMap or Access Entries Enforced EKS Access Entries (API mode)

Terraform Implementation

Step 1. Configure Subnet Tags for Load Balancer Discovery

Ensure subnets have appropriate discovery tags:

vpc.tf

public_subnet_tags = {
  "kubernetes.io/role/elb" = "1" # Tag for external Application / Network Load Balancers
}

private_subnet_tags = {
  "kubernetes.io/role/internal-elb" = "1" # Tag for internal Load Balancers
}


Step 2. Create IAM Roles for Cluster and Nodes

EKS Auto Mode requires specific IAM policies for both the cluster control plane and the auto-provisioned worker nodes.

iam.tf

# 1. Node Role
resource "aws_iam_role" "node" {
  name = "eks-auto-node-${var.cluster_name}"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action    = ["sts:AssumeRole"]
        Effect    = "Allow"
        Principal = { Service = "ec2.amazonaws.com" }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "node_minimal" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy"
  role       = aws_iam_role.node.name
}

resource "aws_iam_role_policy_attachment" "node_ecr" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly"
  role       = aws_iam_role.node.name
}

# 2. Cluster Role
resource "aws_iam_role" "cluster" {
  name = "eks-cluster-${var.cluster_name}"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action    = ["sts:AssumeRole", "sts:TagSession"]
        Effect    = "Allow"
        Principal = { Service = "eks.amazonaws.com" }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "cluster_policies" {
  for_each = toset([
    "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy",
    "arn:aws:iam::aws:policy/AmazonEKSComputePolicy",
    "arn:aws:iam::aws:policy/AmazonEKSBlockStoragePolicy",
    "arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy",
    "arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy"
  ])

  policy_arn = each.value
  role       = aws_iam_role.cluster.name
}


Step 3. Provision the EKS Auto Cluster

eks-auto.tf

resource "aws_eks_cluster" "eks_auto" {
  name     = "eks-auto-demo"
  version  = "1.31"
  role_arn = aws_iam_role.cluster.arn

  access_config {
    authentication_mode = "API"
  }

  bootstrap_self_managed_addons = false

  compute_config {
    enabled       = true
    node_pools    = ["general-purpose"]
    node_role_arn = aws_iam_role.node.arn
  }

  kubernetes_network_config {
    elastic_load_balancing {
      enabled = true
    }
  }

  storage_config {
    block_storage {
      enabled = true
    }
  }

  vpc_config {
    endpoint_private_access = true
    endpoint_public_access  = true
    subnet_ids              = module.vpc.private_subnets
  }

  depends_on = [aws_iam_role_policy_attachment.cluster_policies]
}


Step 4. EKS Access Entry (Cluster Admin)

Grant cluster administrator permissions to the identity applying Terraform:

access-entries.tf

data "aws_caller_identity" "current" {}

resource "aws_eks_access_entry" "admin" {
  cluster_name  = aws_eks_cluster.eks_auto.name
  principal_arn = data.aws_caller_identity.current.arn
  type          = "STANDARD"
}

resource "aws_eks_access_policy_association" "admin" {
  cluster_name  = aws_eks_cluster.eks_auto.name
  policy_arn    = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
  principal_arn = data.aws_caller_identity.current.arn

  access_scope {
    type = "cluster"
  }
}


Connect and Validate

# 1. Update kubeconfig
aws eks --region eu-west-1 update-kubeconfig --name eks-auto-demo

# 2. Verify cluster status
kubectl cluster-info

# 3. Check registered NodePools and IngressClasses
kubectl get nodepool,ingressclass,nodes

Ingress Architecture Recommendation

While EKS Auto Mode includes a built-in Ingress controller, adopting the Kubernetes Gateway API (e.g. Envoy Gateway) is recommended for production environments. Gateway API provides faster health checking, seamless traffic shifting, and avoids traditional ALB target group registration delays.