CtrlK
BlogDocsLog inGet started
Tessl Logo

terraform-eks

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

Quality

84%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Terraform EKS Cluster Provisioning

Production-ready patterns for provisioning AWS EKS clusters with Terraform using the official terraform-aws-modules/eks module.

Quick Reference

CommandDescription
terraform initInitialize Terraform working directory
terraform planPreview infrastructure changes
terraform applyCreate/update EKS cluster
terraform destroyDelete EKS cluster and resources
aws eks update-kubeconfig --name <cluster>Configure kubectl access
terraform outputView cluster outputs
terraform state listList managed resources

Version Requirements

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"
    }
  }
}

Basic EKS Cluster Example

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"
  }
}

Managed Node Groups

On-Demand Nodes

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 Instances

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

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"
        }
      }
    ]
  }
}

IRSA (IAM Roles for Service Accounts)

# 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
    }
  }
}

EKS Add-ons

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
  }
}

VPC Integration

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"
  }
}

Private Cluster Configuration

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
    }
  }
}

Detailed Documentation

For comprehensive guides, see:

  • Cluster Configuration - Complete cluster setup, authentication modes, encryption
  • Node Groups - Managed, self-managed, and Fargate patterns
  • Add-ons & IRSA - EKS add-ons, IRSA setup, service account configuration

Common Patterns

Update kubeconfig

aws eks update-kubeconfig --name production-eks --region us-east-1

Access Private Cluster

# 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

Check Cluster Status

# 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-system

Best Practices

  1. Always use private clusters for production (public_access = false)
  2. Enable IRSA for pod-level IAM permissions (enable_irsa = true)
  3. Encrypt secrets with KMS (cluster_encryption_config)
  4. Use managed node groups unless you need custom AMIs
  5. Tag everything for cost tracking and organization
  6. Separate state files by component (VPC, EKS, add-ons)
  7. Use VPC endpoints for private cluster access
  8. Implement lifecycle policies (prevent_destroy for critical resources)

References

  • terraform-aws-modules/eks
  • HashiCorp EKS Tutorial
  • AWS EKS Best Practices
Repository
fernandezbaptiste/Skrillz
Last updated
First committed

Also appears in

fernandezbaptiste/Skrillz
In sync

since Sep 12, 2026

Is this your skill?

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.