Terraform modules for EKS clusters are less about abstracting away EKS and more about orchestrating the complex, interdependent pieces that make an EKS cluster work.
Let’s see it in action. We’ll spin up a minimal EKS cluster using the official Terraform AWS EKS module.
provider "aws" {
region = "us-east-1"
}
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "19.15.3" # Pin to a specific version for repeatability
cluster_name = "my-demo-cluster"
cluster_version = "1.28"
vpc_id = aws_vpc.main.id
subnet_ids = aws_subnet.private.ids
enable_irsa = true # Essential for AWS service integrations
cluster_endpoint_public_access = true
tags = {
Environment = "demo"
Terraform = "true"
}
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "eks-vpc"
}
}
resource "aws_subnet" "private" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
availability_zone = "us-east-1${element(["a", "b"], count.index)}"
tags = {
Name = "eks-private-subnet-${count.index}"
}
}
output "cluster_endpoint" {
description = "Endpoint for EKS control plane."
value = module.eks.cluster_endpoint
}
output "cluster_oidc_issuer_url" {
description = "OIDC issuer URL for the cluster."
value = module.eks.oidc_issuer_url
}
After running terraform init and terraform apply, you’ll have an EKS cluster. The cluster_endpoint output will give you the Kubernetes API server address, and oidc_issuer_url is crucial for IAM Roles for Service Accounts (IRSA).
The problem this solves is the sheer complexity of EKS. It’s not just a control plane; it’s a control plane, networking (VPC, subnets, security groups, NAT gateways), IAM roles, OIDC providers, and worker nodes. Each has its own lifecycle and dependencies. A Terraform module consolidates these into a manageable, versioned unit.
Internally, the module provisions:
- VPC and Subnets: If not provided, it can create them. Crucially, these subnets need specific tags for EKS to discover them.
- Security Groups: For the control plane and worker nodes.
- IAM Roles: For the control plane and worker nodes (often managed via
aws-authConfigMap or IRSA). - EKS Control Plane: The
aws_eks_clusterresource. - Worker Node Groups:
aws_eks_node_groupresources or integration with EKS Managed Node Groups. - OIDC Provider: For IRSA, allowing pods to assume IAM roles.
The exact levers you control are primarily through input variables. cluster_name, cluster_version, vpc_id, subnet_ids, enable_irsa, cluster_endpoint_public_access, and tags are common. For more advanced setups, you’d look at create_iam_role, manage_aws_auth_configmap, node_groups configuration (instance types, desired/min/max size), and fargate_profiles.
When enabling IRSA with enable_irsa = true, the module automatically creates an IAM OIDC provider for your cluster and sets up the necessary IAM policies and instance profiles for your worker nodes. This is fundamental for granting Kubernetes pods permissions to interact with AWS services securely, without needing static credentials in your pods.
The aws-auth ConfigMap, which maps Kubernetes identities to AWS IAM identities, is often managed by the module or by kubectl after cluster creation. The module can handle its creation and updates, simplifying the initial setup of who can access the cluster’s API.
A subtle but critical detail is how the module handles subnet tagging. For EKS to correctly route traffic and identify nodes, your subnets (whether created by the module or provided externally) must have specific tags, like kubernetes.io/cluster/<cluster-name> set to owned or shared. The module ensures these are present if it’s managing the VPC/subnets.
The next concept you’ll likely explore is managing Kubernetes resources within the provisioned EKS cluster using Terraform, often via the kubernetes provider.