Looking at what we are Building
Never Use Your AWS Root User!
The root user (the email/password you signed up to AWS with) can do anything, including closing the account. It should basically never be used day-to-day. Instead, create a dedicated IAM user just for this project. In real life you would create a dedicated IAM user for your CI/CD pipeline to automate deployments:
- AWS Console → IAM → Users → Create user (e.g.
terraform-voting-app). - Do not enable AWS Console access; this user only needs programmatic access, i.e. an API key pair.
- The AWS managed policy
AdministratorAccessis the path of least friction, and is what you should use for the IAM user to test things out. But in real life you would go with a least‑privilege approach; learn more about it in AWS EKS IAM policy examples. - On the user's Security credentials tab → Create access key → choose "Command Line Interface (CLI)". You'll get an Access Key ID and a Secret Access Key; store them somewhere safe, we will be needing them later.
Give Terraform Those Credentials
The rule: credentials never go inside a .tf file, and never inside terraform.tfvars. So in your local machine or CI/CD pipeline you need to export AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION as environment variables in the shell.
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=us-east-1
Then you won't be needing aws configure or aws login step anywhere; the AWS provider has no access_key / secret_key arguments of its own, so it falls back to the AWS SDK's standard credential chain, which checks these exact environment variables first. The AWS CLI and, later, kubectl read the same variables.
In my local machine I do export an env variable file using a shell script. The export only lasts for the current shell session; re‑run it in any new terminal before running terraform / aws / kubectl.
What You Are About to Build
This is the part most beginner Terraform/EKS tutorials skip, and it's the part that makes the actual .tf files make sense at a glance instead of feeling like a wall of unfamiliar arguments.
flowchart TB
subgraph AWS["AWS Account / Region"]
subgraph VPC["VPC - 10.0.0.0/16"]
IGW["Internet Gateway"]
subgraph AZ1["Availability Zone A"]
PubA["Public subnet\n10.0.100.0/24"]
PrivA["Private subnet\n10.0.0.0/24"]
end
subgraph AZ2["Availability Zone B"]
PubB["Public subnet\n10.0.101.0/24"]
PrivB["Private subnet\n10.0.1.0/24"]
end
NAT["NAT Gateway\n(in a public subnet)"]
CP["EKS Control Plane\n(managed by AWS,\nnot inside your subnets)"]
PrivA --- Node1["EC2 worker node"]
PrivB --- Node2["EC2 worker node"]
end
NLB["Network Load Balancer\n(public, one per exposed Service)"]
end
Internet(("Internet")) --> IGW
IGW --> PubA
IGW --> PubB
PubA --> NAT
NAT -.outbound only.-> Node1
NAT -.outbound only.-> Node2
CP <-. manages .-> Node1
CP <-. manages .-> Node2
Internet --> NLB
NLB --> Node1
NLB --> Node2
Node1 -- runs --> Pods1["voting / result / worker\nredis / postgres pods"]
Node2 -- runs --> Pods2["voting / result / worker\nredis / postgres pods"]
Reading it top to bottom:
- VPC: a private network inside AWS,
10.0.0.0/16here (65k addresses is just the conventional default and more than what we need). - Two Availability Zones: EKS requires subnets in at least 2 AZs, so a single AZ failure can't take the whole cluster down.
- Public subnets have a route to the Internet Gateway. Their only job is hosting the NAT Gateway and, later, the public‑facing Load Balancers.
- Private subnets is where the actual EC2 worker nodes live. They have no direct route in from the internet, and no public IP at all.
- NAT Gateway lets the private‑subnet nodes reach out to the internet (to pull container images, talk to the EKS API, etc.) without allowing anything in from the internet. One‑way door.
- EKS Control Plane is a managed AWS service which is the Kubernetes API server, scheduler, etc. It doesn't live "in" your subnets the way an EC2 instance does, though it does attach elastic network interfaces into them to talk to your nodes.
- Worker nodes are plain EC2 instances, sitting in the private subnets, that the EKS control plane schedules your pods onto. This is the "data plane", as opposed to the control plane above.
- Network Load Balancer is created later, by Kubernetes (not Terraform) when you expose a Service as
type: LoadBalancer. This is how traffic actually reaches your app from a browser.
EKS Costs
We have two separate charges, both starting the moment terraform apply finishes:
- The EKS control plane itself has a flat hourly rate. Check current EKS pricing and this is regardless of whether any pods are running.
- The EC2 worker nodes: ordinary EC2 billing, because they're ordinary EC2 instances. Two
t3.mediumnodes, in this project. Plus a NAT Gateway (hourly + per‑GB processed) and small EBS volumes for each node's disk. None of it is free‑tier.
Reference Links
Top comments (0)
Comments
No comments yet. Start the discussion.