Provision production-ready AWS EKS clusters with Terraform. Covers cluster configuration, managed node groups, Fargate profiles, IRSA, EKS add-ons (CoreDNS, kube-proxy, VPC CNI, EBS CSI), VPC integration, and security best practices. Use when provisioning EKS, setting up Kubernetes on AWS, configuring node groups, implementing IRSA, or managing EKS infrastructure as code.
69
84%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
The canonical home for this skill is terraform-eks in fernandezbaptiste/Skrillz
Production-ready patterns for provisioning AWS EKS clusters with Terraform using the official terraform-aws-modules/eks module.
| Command | Description |
|---|---|
terraform init | Initialize Terraform working directory |
terraform plan | Preview infrastructure changes |
terraform apply | Create/update EKS cluster |
terraform destroy | Delete EKS cluster and resources |
aws eks update-kubeconfig --name <cluster> | Configure kubectl access |
terraform output | View cluster outputs |
terraform state list | List managed resources |
terraform {
required_version = ">= 1.11.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.35"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.16"
}
}
}module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 21.0"
cluster_name = "production-eks"
cluster_version = "1.33"
# VPC configuration
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
# Cluster access
cluster_endpoint_public_access = false
cluster_endpoint_private_access = true
# Enable IRSA
enable_irsa = true
# Cluster encryption
cluster_encryption_config = {
resources = ["secrets"]
provider_key_arn = aws_kms_key.eks.arn
}
# EKS add-ons
cluster_addons = {
coredns = {
addon_version = "v1.11.3-eksbuild.2"
resolve_conflicts = "OVERWRITE"
}
kube-proxy = {
addon_version = "v1.33.1-eksbuild.1"
}
vpc-cni = {
addon_version = "v1.19.2-eksbuild.1"
configuration_values = jsonencode({
env = {
ENABLE_PREFIX_DELEGATION = "true"
}
})
}
aws-ebs-csi-driver = {
addon_version = "v1.38.2-eksbuild.1"
service_account_role_arn = module.ebs_csi_irsa.iam_role_arn
}
}
# Managed node groups
eks_managed_node_groups = {
general = {
instance_types = ["t3.large"]
min_size = 2
max_size = 10
desired_size = 3
labels = {
role = "general"
}
}
}
tags = {
Environment = "production"
Terraform = "true"
}
}eks_managed_node_groups = {
general = {
name = "general-nodes"
instance_types = ["m5.xlarge"]
min_size = 3
max_size = 20
desired_size = 5
capacity_type = "ON_DEMAND"
ami_type = "AL2023_x86_64_STANDARD"
# Disk configuration
block_device_mappings = {
xvda = {
device_name = "/dev/xvda"
ebs = {
volume_size = 100
volume_type = "gp3"
encrypted = true
}
}
}
labels = {
role = "general"
}
tags = {
"k8s.io/cluster-autoscaler/enabled" = "true"
}
}
}spot = {
instance_types = ["t3.large", "t3a.large"]
min_size = 0
max_size = 5
desired_size = 2
capacity_type = "SPOT"
labels = {
workload = "batch"
}
taints = [{
key = "spot"
value = "true"
effect = "NoSchedule"
}]
}fargate_profiles = {
kube_system = {
name = "kube-system"
selectors = [
{
namespace = "kube-system"
labels = {
k8s-app = "kube-dns"
}
}
]
subnet_ids = module.vpc.private_subnets
}
application = {
name = "app"
selectors = [
{
namespace = "production"
},
{
namespace = "staging"
labels = {
compute = "fargate"
}
}
]
}
}# Enable IRSA in EKS module
module "eks" {
enable_irsa = true
}
# Create IAM role for service account
module "ebs_csi_irsa" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.0"
role_name = "ebs-csi-controller"
attach_ebs_csi_policy = true
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
}
}
}
# Kubernetes service account
resource "kubernetes_service_account" "ebs_csi" {
metadata {
name = "ebs-csi-controller-sa"
namespace = "kube-system"
annotations = {
"eks.amazonaws.com/role-arn" = module.ebs_csi_irsa.iam_role_arn
}
}
}cluster_addons = {
# CoreDNS for cluster DNS
coredns = {
addon_version = "v1.11.3-eksbuild.2"
resolve_conflicts = "OVERWRITE"
configuration_values = jsonencode({
computeType = "Fargate"
resources = {
limits = {
cpu = "100m"
memory = "150Mi"
}
}
})
}
# VPC CNI for pod networking
vpc-cni = {
addon_version = "v1.19.2-eksbuild.1"
configuration_values = jsonencode({
env = {
ENABLE_PREFIX_DELEGATION = "true"
ENABLE_POD_ENI = "true"
}
})
service_account_role_arn = module.vpc_cni_irsa.iam_role_arn
}
# EBS CSI Driver for persistent volumes
aws-ebs-csi-driver = {
addon_version = "v1.38.2-eksbuild.1"
service_account_role_arn = module.ebs_csi_irsa.iam_role_arn
}
# EFS CSI Driver for shared storage
aws-efs-csi-driver = {
addon_version = "v2.1.3-eksbuild.1"
service_account_role_arn = module.efs_csi_irsa.iam_role_arn
}
}module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "eks-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = false # One per AZ for HA
# Required tags for EKS
public_subnet_tags = {
"kubernetes.io/role/elb" = "1"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = "1"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
}
}module "eks" {
source = "terraform-aws-modules/eks/aws"
# Private cluster
cluster_endpoint_public_access = false
cluster_endpoint_private_access = true
# Control plane subnets
control_plane_subnet_ids = module.vpc.intra_subnets
subnet_ids = module.vpc.private_subnets
}
# VPC endpoints required for private clusters
module "vpc_endpoints" {
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
vpc_id = module.vpc.vpc_id
endpoints = {
s3 = {
service = "s3"
service_type = "Gateway"
}
ecr_api = {
service = "ecr.api"
private_dns_enabled = true
subnet_ids = module.vpc.private_subnets
}
ecr_dkr = {
service = "ecr.dkr"
private_dns_enabled = true
subnet_ids = module.vpc.private_subnets
}
}
}For comprehensive guides, see:
aws eks update-kubeconfig --name production-eks --region us-east-1# Via AWS Systems Manager (no SSH)
aws ssm start-session --target i-bastion-instance-id
# Configure kubectl on bastion
aws eks update-kubeconfig --name production-eks --region us-east-1
kubectl get nodes# Get cluster info
terraform output cluster_name
terraform output cluster_endpoint
# Verify add-ons
kubectl get daemonsets -n kube-system
kubectl get pods -n kube-system93ed392
Canonical home
since Sep 12, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.