Skip to content

EKS Auto Mode with Terraform

EKS Auto mode Terraform logo

Amazon EKS Auto Mode fully automates Kubernetes cluster management for compute, storage, and networking on AWS. It comes with Karpenter pre-installed and a default NodePool that provisions AMD-based servers on demand.

Why opt for EKS Auto Mode?

EKS clusters require many add-ons and features to be installed for full functionality, and keeping versions compatible across components is challenging. With EKS Auto Mode, all of these are managed by AWS.

Components managed by AWS in EKS Auto Mode
VPC CNI Load Balancer controller
EKS Pod Identity Kube Proxy
Ingress controller (recommend using Gateway API instead) Karpenter autoscaler with default NodePool

EKS Auto Cluster build

With EKS Auto Mode, creating a cluster has minimal requirements. Terraform code for this example is at aws-eks-terraform → EKS-Cluster-auto-mode.

  1. VPC with at least 2 subnets and the required subnet tags
  2. EKS Auto Mode cluster with API authentication and access entry

Step 1. Create VPC

The VPC must have at least 2 subnets with the following tags so load balancers are created in the correct subnet:

public_subnet_tags = {
  "kubernetes.io/role/elb" = "1"          # Tag for external load balancers
}
private_subnet_tags = {
  "kubernetes.io/role/internal-elb" = "1" # Tag for internal load balancers
}

Step 2. Provision the EKS Auto Mode cluster

IAM Roles

Two IAM roles are required before creating the cluster:

  • Node role — with AmazonEKSWorkerNodeMinimalPolicy and AmazonEC2ContainerRegistryPullOnly
  • Cluster role — with AmazonEKSClusterPolicy, AmazonEKSComputePolicy, AmazonEKSBlockStoragePolicy, AmazonEKSLoadBalancingPolicy, and AmazonEKSNetworkingPolicy

iam.tf

resource "aws_iam_role" "node" {
  name = "eks-auto-node-example"
  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_AmazonEKSWorkerNodeMinimalPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy"
  role       = aws_iam_role.node.name
}
resource "aws_iam_role_policy_attachment" "node_AmazonEC2ContainerRegistryPullOnly" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly"
  role       = aws_iam_role.node.name
}
resource "aws_iam_role" "cluster" {
  name = "eks-cluster-eks-auto-demo"
  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_AmazonEKSClusterPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  role       = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSComputePolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSComputePolicy"
  role       = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSBlockStoragePolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSBlockStoragePolicy"
  role       = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSLoadBalancingPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy"
  role       = aws_iam_role.cluster.name
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSNetworkingPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy"
  role       = aws_iam_role.cluster.name
}

EKS Cluster

When creating an EKS Auto Mode cluster, compute_config, kubernetes_network_config (elastic load balancing), and storage_config must all be enabled. This instructs AWS to configure Karpenter, VPC-CNI, the LB controller, and the EBS CSI driver.

eks-auto.tf

resource "aws_eks_cluster" "eks-auto-demo" {
  name = "eks-auto-demo"
  access_config {
    authentication_mode = "API"
  }
  role_arn = aws_iam_role.cluster.arn
  version  = "1.31"
  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_AmazonEKSClusterPolicy,
    aws_iam_role_policy_attachment.cluster_AmazonEKSComputePolicy,
    aws_iam_role_policy_attachment.cluster_AmazonEKSBlockStoragePolicy,
    aws_iam_role_policy_attachment.cluster_AmazonEKSLoadBalancingPolicy,
    aws_iam_role_policy_attachment.cluster_AmazonEKSNetworkingPolicy,
  ]
}

EKS Access entry

By default, the creator of an EKS cluster does not have Cluster Admin permissions. You must add users to aws_eks_access_entry and assign them appropriate permissions. The example below grants ClusterAdmin to the identity running Terraform.

access_entry.tf

data "aws_caller_identity" "current" {}

resource "aws_eks_access_entry" "aws_eks_access_entry" {
  cluster_name  = aws_eks_cluster.eks-auto-demo.name
  principal_arn = data.aws_caller_identity.current.arn
  type          = "STANDARD"
}
resource "aws_eks_access_policy_association" "aws_eks_access_policy_association" {
  cluster_name  = aws_eks_cluster.eks-auto-demo.name
  policy_arn    = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
  principal_arn = data.aws_caller_identity.current.arn
  access_scope {
    type = "cluster"
  }
}

Apply Terraform

terraform plan
terraform apply --auto-approve

Connect to the EKS cluster and validate

aws eks --profile labs --region eu-west-1 update-kubeconfig --name eks-auto-demo
kubectl cluster-info
kubectl get nodepool,ingressclass,nodes

By default there will be a NodePool but no nodes will be created until an application is deployed. The ingress controller is installed; you must create an IngressClass before using it.

Deploy a sample app and you will see Karpenter spin up a new node as needed.


Why you should avoid the EKS default Ingress controller

EKS Auto Mode includes an ingress controller, but it is better to use a Gateway API implementation such as Envoy Gateway. When you create an Ingress resource, the AWS Ingress controller creates Target Groups and forwards traffic directly to your pods. However, the Target Group health checks are traditional and slower than Kubernetes-native checks, which can cause connection drops during deployments, scale-up, and scale-down events as the Target Group takes longer to detect pod changes.