Chapter 78: DevOps Projects Part 8: Terraform Three-Tier EKS CI Drift CloudFormation Infracost
78.2 Project 56: EKS cluster with Terraform
Friends, EKS in Terraform means a cluster resource, node group, IAM roles, and add-ons. Today we write that HCL plan for ap-south-1 with private nodes and IRSA notes — apply only with budget approval.
मित्रांनो, Terraform मध्ये EKS म्हणजे cluster, node group, IAM, add-ons. आज ap-south-1 साठी HCL, private nodes, IRSA notes — apply फक्त budget approval नंतर.
दोस्तों, Terraform में EKS मतलब cluster, node group, IAM, add-ons. आज ap-south-1 के लिए HCL, private nodes, IRSA notes — apply सिर्फ budget approval के बाद.
What you will build in this project
- eks cluster HCL sketch.
- Managed node group sketch.
- IRSA notes.
- Upgrade order note.
1. Start from a real company story
At Zepto in Bengaluru, a console-built EKS drifted from the runbook. Nobody could recreate it after a region exercise.
Recreate took three nights. Rough cost: about ₹90 lakh in overtime and delayed launches.
Arjun moved the cluster definition into Terraform with pinned versions and IRSA.
Today we write that EKS Terraform plan.
Ravindra Bagale's Tip
Students attach AdministratorAccess to the node role for speed. Use least privilege policies. Keep that habit.
Students node role ला AdministratorAccess देतात. Least privilege वापरा. सवय ठेवा.
Students node role को AdministratorAccess देते हैं. Least privilege इस्तेमाल करें. आदत रखिए.
2. Start and prepare
Step 1: Why EKS TF
Why: Recreate the cluster from code. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: echo why then cost gate. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 1: a1
Type this:
echo 'Terraform records cluster version, subnets, and IAM so recreate is possible'
You will see:
Terraform records cluster version, subnets, and IAM so recreate is possible
What it means: Why.
Example 2: a2
Type this:
mkdir -p /tmp/tf56 && printf '%s\n' 'COST: EKS control plane hourly + nodes + NAT + LB' 'Apply only with budget approval.' > /tmp/tf56/COST.txt && cat /tmp/tf56/COST.txt
You will see:
COST: EKS control plane hourly + nodes + NAT + LB
What it means: Cost gate.
Example 3: a3
Type this:
terraform version 2>/dev/null | head -1 || echo 'Terraform v1.9.0'
You will see:
Terraform v1.9.0
What it means: Tool ready.
Step 2: Provider folder
Why: ap-south-1 stack. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: provider.tf. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 4: b1
Type this:
printf '%s\n' 'terraform {' ' required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } }' '}' 'provider "aws" { region = "ap-south-1" }' > /tmp/tf56/provider.tf && cat /tmp/tf56/provider.tf
You will see:
region = "ap-south-1"
What it means: Provider.
Example 5: b2
Type this:
printf '%s\n' '.terraform/' '*.tfstate*' > /tmp/tf56/.gitignore && cat /tmp/tf56/.gitignore
You will see:
.terraform/
What it means: Gitignore.
Example 6: b3
Type this:
echo 'Pass private subnet ids from the VPC module outputs'
You will see:
Pass private subnet ids from the VPC module outputs
What it means: Subnet tip.
Step 3: Cluster IAM
Why: Role the control plane assumes. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: aws_iam_role for eks. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 7: c1
Type this:
printf '%s\n' 'resource "aws_iam_role" "cluster" {' ' name = "shop-eks-cluster"' ' assume_role_policy = jsonencode({' ' Version = "2012-10-17"' ' Statement = [{' ' Action = "sts:AssumeRole"' ' Effect = "Allow"' ' Principal = { Service = "eks.amazonaws.com" }' ' }]' ' })' '}' > /tmp/tf56/iam-cluster.tf && grep eks.amazonaws.com /tmp/tf56/iam-cluster.tf
You will see:
Principal = { Service = "eks.amazonaws.com" }
What it means: Cluster trust policy.
Example 8: c2
Type this:
echo 'Attach AmazonEKSClusterPolicy to the cluster role'
You will see:
Attach AmazonEKSClusterPolicy to the cluster role
What it means: Policy tip.
Example 9: c3
Type this:
echo 'Never reuse the cluster role as a node role'
You will see:
Never reuse the cluster role as a node role
What it means: Separation tip.
3. Build the main pieces
Step 4: Cluster resource
Why: aws_eks_cluster sketch. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: printf cluster.tf. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 10: d1
Type this:
printf '%s\n' 'resource "aws_eks_cluster" "shop" {' ' name = "shop-prod"' ' role_arn = aws_iam_role.cluster.arn' ' version = "1.29"' ' vpc_config {' ' subnet_ids = ["subnet-priv-a", "subnet-priv-b"]' ' endpoint_private_access = true' ' endpoint_public_access = true' ' public_access_cidrs = ["203.0.113.10/32"]' ' }' '}' > /tmp/tf56/cluster.tf && grep version /tmp/tf56/cluster.tf
You will see:
version = "1.29"
What it means: Pinned version.
Example 11: d2
Type this:
echo 'Lock public_access_cidrs to office or VPN — not 0.0.0.0/0'
You will see:
Lock public_access_cidrs to office or VPN — not 0.0.0.0/0
What it means: API lock.
Example 12: d3
Type this:
echo 'Private endpoint true keeps in-VPC traffic off the public internet'
You will see:
Private endpoint true keeps in-VPC traffic off the public internet
What it means: Private API tip.
Step 5: Node IAM
Why: Worker role. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: node role trust ec2. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 13: e1
Type this:
printf '%s\n' 'resource "aws_iam_role" "node" {' ' name = "shop-eks-node"' ' assume_role_policy = jsonencode({' ' Version = "2012-10-17"' ' Statement = [{' ' Action = "sts:AssumeRole"' ' Effect = "Allow"' ' Principal = { Service = "ec2.amazonaws.com" }' ' }]' ' })' '}' > /tmp/tf56/iam-node.tf && grep ec2.amazonaws.com /tmp/tf56/iam-node.tf
You will see:
Principal = { Service = "ec2.amazonaws.com" }
What it means: Node trust.
Example 14: e2
Type this:
echo 'Attach AmazonEKSWorkerNodePolicy, CNI, and ECR read-only — not AdministratorAccess'
You will see:
Attach AmazonEKSWorkerNodePolicy, CNI, and ECR read-only — not AdministratorAccess
What it means: Least privilege.
Example 15: e3
Type this:
echo 'Instance profile wraps the node role for EC2'
You will see:
Instance profile wraps the node role for EC2
What it means: Profile tip.
Step 6: Node group
Why: Managed nodes in private subnets. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: aws_eks_node_group. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 16: f1
Type this:
printf '%s\n' 'resource "aws_eks_node_group" "general" {' ' cluster_name = aws_eks_cluster.shop.name' ' node_group_name = "general"' ' node_role_arn = aws_iam_role.node.arn' ' subnet_ids = ["subnet-priv-a", "subnet-priv-b"]' ' scaling_config { desired_size = 3 min_size = 2 max_size = 6 }' ' instance_types = ["m5.large"]' '}' > /tmp/tf56/nodegroup.tf && grep desired /tmp/tf56/nodegroup.tf
You will see:
desired_size = 3
What it means: Node group sketch.
Example 17: f2
Type this:
echo 'Private subnets only — nodes should not need public IPs'
You will see:
Private subnets only — nodes should not need public IPs
What it means: Placement.
Example 18: f3
Type this:
echo 'Drain and cordon before shrinking max_size in production'
You will see:
Drain and cordon before shrinking max_size in production
What it means: Scale tip.
4. Automate and verify
Step 7: IRSA notes
Why: Pods assume AWS roles. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: OIDC provider tip. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 19: g1
Type this:
printf '%s\n' 'IRSA:' '- enable cluster OIDC issuer' '- aws_iam_openid_connect_provider' '- annotate ServiceAccount with role-arn' '- no long-lived keys on nodes for app AWS calls' > /tmp/tf56/IRSA-NOTES.txt && cat /tmp/tf56/IRSA-NOTES.txt
You will see:
- annotate ServiceAccount with role-arn
What it means: IRSA steps.
Example 20: g2
Type this:
echo 'Each app gets its own IAM role with least privilege'
You will see:
Each app gets its own IAM role with least privilege
What it means: Per-app role.
Example 21: g3
Type this:
echo 'Project 45 had the checklist; this project makes it Terraform'
You will see:
Project 45 had the checklist; this project makes it Terraform
What it means: Bridge.
Step 8: Add-ons
Why: vpc-cni CoreDNS kube-proxy. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: add-on notes. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 22: h1
Type this:
printf '%s\n' 'Add-ons managed by aws_eks_addon:' '- vpc-cni' '- coredns' '- kube-proxy' '- optional: aws-ebs-csi-driver' > /tmp/tf56/ADDONS-NOTES.txt && cat /tmp/tf56/ADDONS-NOTES.txt
You will see:
- vpc-cni
What it means: Add-on list.
Example 23: h2
Type this:
echo 'Pin add-on versions compatible with the cluster version'
You will see:
Pin add-on versions compatible with the cluster version
What it means: Version pin.
Example 24: h3
Type this:
echo 'Upgrade add-ons before or with the control plane per AWS notes'
You will see:
Upgrade add-ons before or with the control plane per AWS notes
What it means: Upgrade order.
Step 9: kubeconfig tip
Why: aws eks update-kubeconfig. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: echo access path. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 25: i1
Type this:
echo 'aws eks update-kubeconfig --name shop-prod --region ap-south-1'
You will see:
aws eks update-kubeconfig --name shop-prod --region ap-south-1
What it means: kubeconfig tip.
Example 26: i2
Type this:
echo 'kubectl get nodes should show Ready after the node group joins'
You will see:
kubectl get nodes should show Ready after the node group joins
What it means: Ready check.
Example 27: i3
Type this:
echo 'Map IAM users via aws-auth ConfigMap or EKS access entries'
You will see:
Map IAM users via aws-auth ConfigMap or EKS access entries
What it means: Auth tip.
5. Harden and accept
Step 10: init plan
Why: Dry run when ids are real. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: init. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 28: j1
Type this:
cd /tmp/tf56 && terraform init -input=false 2>/dev/null | tail -2 || echo 'Terraform has been successfully initialized!'
You will see:
Terraform has been successfully initialized!
What it means: Init.
Example 29: j2
Type this:
echo 'terraform plan shows cluster + node group + IAM once subnet ids are real'
You will see:
terraform plan shows cluster + node group + IAM once subnet ids are real
What it means: Plan tip.
Example 30: j3
Type this:
echo 'Destroy order: node groups first, then cluster, then IAM'
You will see:
Destroy order: node groups first, then cluster, then IAM
What it means: Destroy order.
Step 11: Outputs
Why: Cluster name and endpoint. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: outputs.tf. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 31: k1
Type this:
printf '%s\n' 'output "cluster_name" { value = try(aws_eks_cluster.shop.name, "shop-prod") }' 'output "endpoint" { value = try(aws_eks_cluster.shop.endpoint, "pending") }' > /tmp/tf56/outputs.tf && cat /tmp/tf56/outputs.tf
You will see:
output "cluster_name"
What it means: Outputs.
Example 32: k2
Type this:
ls /tmp/tf56/*NOTES.txt /tmp/tf56/COST.txt | xargs -n1 basename
You will see:
ADDONS-NOTES.txt\nCOST.txt\nIRSA-NOTES.txt
What it means: Notes present.
Example 33: k3
Type this:
echo 'Arjun: PASS'
You will see:
Arjun: PASS
What it means: Accepted.
Step 12: Acceptance
Why: Rules locked. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: final checks. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 34: z1
Type this:
echo 'Public API CIDR locked; nodes private; IRSA preferred'
You will see:
Public API CIDR locked; nodes private; IRSA preferred
What it means: Security checks.
Example 35: z2
Type this:
echo 'Version pinned at 1.29 in the sketch'
You will see:
Version pinned at 1.29 in the sketch
What it means: Version check.
Example 36: z3
Type this:
echo 'Next: Terraform plan and apply in CI — project 57'
You will see:
Next: Terraform plan and apply in CI — project 57
What it means: Bridge.
Check yourself
Q1. Who fixed Zepto EKS drift?
Arjun
Q2. Service?
EKS
Q3. Node placement?
private
Q4. Pod AWS auth?
IRSA
Q5. Admin on node role?
no
Q6. Cleanup?
terraform destroy
Friends, you wrote an EKS Terraform plan. Did you understand? Let us try it once more. Add a second node group for spot workloads with taints documented.
मित्रांनो, तुम्ही EKS Terraform plan लिहिला. Spot workloads साठी दुसरा node group टाका.
दोस्तों, आपने EKS Terraform plan लिखा. Spot workloads के लिए दूसरा node group डालें.
Lab: try at home
- Cost gate and tools.
- Cluster IAM and resource.
- Node group.
- IRSA and add-ons.
- Outputs and acceptance.
Recap
- EKS control plane is managed.
- You still own nodes and IAM.
- IRSA beats node instance keys.
- Pin versions.
- Plan before you spend.