Why Manage Kubernetes with Terraform?
Terraform manages the infrastructure layer of Kubernetes โ the cluster, node pools, networking, IAM roles, and storage โ while tools like Helm or Flux manage the application layer (Deployments, Services, ConfigMaps). This separation gives you full lifecycle control over your clusters alongside your other cloud infrastructure.
AWS EKS with Terraform
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "${var.project}-eks"
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
cluster_endpoint_public_access = true
cluster_endpoint_private_access = true
eks_managed_node_groups = {
general = {
instance_types = ["m6i.large"]
min_size = 2
max_size = 10
desired_size = 3
disk_size = 50
}
gpu = {
instance_types = ["g4dn.xlarge"]
min_size = 0
max_size = 4
desired_size = 0
taints = [{
key = "nvidia.com/gpu"
value = "true"
effect = "NO_SCHEDULE"
}]
}
}
}
Google GKE Autopilot
resource "google_container_cluster" "main" {
name = "${var.project}-gke"
location = var.region
enable_autopilot = true # Google manages node pools automatically
network = google_compute_network.main.name
subnetwork = google_compute_subnetwork.private.name
private_cluster_config {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = "172.16.0.0/28"
}
workload_identity_config {
workload_pool = "${var.project_id}.svc.id.goog"
}
}
Azure AKS
resource "azurerm_kubernetes_cluster" "main" {
name = "${var.project}-aks"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
dns_prefix = var.project
kubernetes_version = "1.29"
default_node_pool {
name = "system"
node_count = 3
vm_size = "Standard_D4s_v3"
os_disk_size_gb = 128
type = "VirtualMachineScaleSets"
enable_auto_scaling = true
min_count = 2
max_count = 10
}
identity { type = "SystemAssigned" }
oidc_issuer_enabled = true
workload_identity_enabled = true
azure_policy_enabled = true
}
Installing Helm Charts with Terraform
resource "helm_release" "cert_manager" {
name = "cert-manager"
repository = "https://charts.jetstack.io"
chart = "cert-manager"
version = "v1.14.0"
namespace = "cert-manager"
create_namespace = true
set { name = "installCRDs"; value = "true" }
depends_on = [module.eks]
}
resource "helm_release" "ingress_nginx" {
name = "ingress-nginx"
repository = "https://kubernetes.github.io/ingress-nginx"
chart = "ingress-nginx"
version = "4.9.0"
namespace = "ingress-nginx"
create_namespace = true
}
Always use explicit chart versions in production Helm releases. Floating versions like
latest cause unexpected upgrades during terraform apply.Production Hardening Checklist
- Enable private cluster endpoints โ master API not exposed to internet
- Use managed identity / Workload Identity for pod AWS/GCP/Azure access
- Set resource requests and limits on all pods
- Enable Pod Disruption Budgets for critical workloads
- Use Cluster Autoscaler or Karpenter for node auto-scaling
- Enable network policies (Calico or Cilium)
- Separate system and application node pools
- Enable audit logging for the Kubernetes API server
Try CloudFormation Free
Design infrastructure visually and generate production-ready Terraform in seconds โ 693 resources across 9 cloud providers.
๐ Open the Designer โ