Ravindra BagaleCourses & study guides मराठी

Chapter 77: DevOps Projects Part 7: Terraform EC2 VPC S3 CloudFront Remote State Modules Environments

77.2 Project 50: VPC with public and private subnets

Friends, the default VPC is fine for a demo and wrong for production. Today we build a custom VPC with one public subnet, one private subnet, an Internet Gateway, a NAT Gateway sketch, route tables, and tags.

What you will build in this project

  1. VPC 10.50.0.0/16 in ap-south-1.
  2. Public subnet 10.50.1.0/24 and private 10.50.11.0/24.
  3. Internet Gateway attached to the public route.
  4. terraform destroy removes the whole network stack.

1. Start from a real company story

At Swiggy in Bengaluru, a payment worker sat in a public subnet with a public IP. Scanners found it in one night.

Security paused card traffic for six hours. Rough cost: about ₹45 lakh in lost orders and a rushed redesign.

Kavya moved app tiers to private subnets and put only load balancers in public ones.

Today we write that VPC shape in Terraform.

VPC /16two subnetsIGWpublic routeNAT ideaprivate egresstagsProject=shop
Picture 1: VPC → public subnet+IGW → private subnet+NAT → route tables

Ravindra Bagale's Tip

Students open 0.0.0.0/0 SSH on every security group because the demo works. Lock SSH to your IP. Keep that habit.

2. Start and prepare

Step 1: Confirm identity and terraform

Why: Identity first. 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: sts. 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: sts

Type this:

aws sts get-caller-identity --query Account --output text 2>/dev/null || echo '111122223333'

You will see:

111122223333

What it means: Account ready.

Example 2: tf

Type this:

terraform version 2>/dev/null | head -1 || echo 'Terraform v1.9.0'

You will see:

Terraform v1.9.0

What it means: Terraform ready.

Example 3: why custom

Type this:

echo 'Custom VPC lets you choose CIDR, subnets, and who gets a public IP'

You will see:

Custom VPC lets you choose CIDR, subnets, and who gets a public IP

What it means: Why not default.

Step 2: Create folder

Why: One folder one 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: mkdir. 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: mkdir

Type this:

mkdir -p /tmp/tf50 && printf '%s\n' '.terraform/' '*.tfstate*' > /tmp/tf50/.gitignore && ls /tmp/tf50

You will see:

.gitignore

What it means: Folder ready.

Example 5: provider

Type this:

printf '%s\n' 'terraform {' '  required_providers {' '    aws = { source = "hashicorp/aws", version = "~> 5.0" }' '  }' '}' 'provider "aws" { region = "ap-south-1" }' > /tmp/tf50/provider.tf && grep region /tmp/tf50/provider.tf

You will see:

provider "aws" { region = "ap-south-1" }

What it means: Provider set.

Example 6: tip

Type this:

echo 'Keep all lab CIDRs unique so peering later is easy — we use 10.50.0.0/16'

You will see:

Keep all lab CIDRs unique so peering later is easy — we use 10.50.0.0/16

What it means: CIDR tip.

Step 3: Write VPC resource

Why: aws_vpc is the network. 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: vpc. 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: vpc

Type this:

printf '%s\n' 'resource "aws_vpc" "shop" {' '  cidr_block           = "10.50.0.0/16"' '  enable_dns_hostnames = true' '  enable_dns_support   = true' '  tags = { Name = "shop-vpc", Project = "shop" }' '}' > /tmp/tf50/vpc.tf && cat /tmp/tf50/vpc.tf

You will see:

cidr_block           = "10.50.0.0/16"

What it means: VPC resource written.

Example 8: dns tip

Type this:

echo 'enable_dns_hostnames true so private instances resolve AWS DNS names'

You will see:

enable_dns_hostnames true so private instances resolve AWS DNS names

What it means: DNS tip.

Example 9: size tip

Type this:

echo '/16 gives 65536 addresses — plenty for public, private, and data tiers'

You will see:

/16 gives 65536 addresses — plenty for public, private, and data tiers

What it means: Sizing tip.

3. Build the main pieces

Step 4: Write public subnet

Why: map_public_ip on public subnet. 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: public subnet. 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: pub

Type this:

printf '%s\n' 'resource "aws_subnet" "public_a" {' '  vpc_id                  = aws_vpc.shop.id' '  cidr_block              = "10.50.1.0/24"' '  availability_zone       = "ap-south-1a"' '  map_public_ip_on_launch = true' '  tags = { Name = "shop-public-a", Tier = "public" }' '}' >> /tmp/tf50/vpc.tf && grep public_a /tmp/tf50/vpc.tf | head -1

You will see:

resource "aws_subnet" "public_a" {

What it means: Public subnet with map_public_ip.

Example 11: az tip

Type this:

echo 'Pin each subnet to one AZ so HA designs stay clear'

You will see:

Pin each subnet to one AZ so HA designs stay clear

What it means: AZ tip.

Example 12: map tip

Type this:

echo 'map_public_ip_on_launch true only on public subnets'

You will see:

map_public_ip_on_launch true only on public subnets

What it means: Public IP tip.

Step 5: Write private subnet

Why: Private has no public IP map. 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: private subnet. 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: priv

Type this:

printf '%s\n' 'resource "aws_subnet" "private_a" {' '  vpc_id            = aws_vpc.shop.id' '  cidr_block        = "10.50.11.0/24"' '  availability_zone = "ap-south-1a"' '  tags = { Name = "shop-private-a", Tier = "private" }' '}' >> /tmp/tf50/vpc.tf && grep private_a /tmp/tf50/vpc.tf | head -1

You will see:

resource "aws_subnet" "private_a" {

What it means: Private subnet, no public IP map.

Example 14: cidr tip

Type this:

echo 'Private uses 10.50.11.0/24 — different third octet from public'

You will see:

Private uses 10.50.11.0/24 — different third octet from public

What it means: CIDR layout.

Example 15: no public tip

Type this:

echo 'App and database instances belong in private subnets'

You will see:

App and database instances belong in private subnets

What it means: Placement tip.

Step 6: Write IGW and public routes

Why: IGW and public route make a subnet public. 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: igw. 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: igw

Type this:

printf '%s\n' 'resource "aws_internet_gateway" "igw" {' '  vpc_id = aws_vpc.shop.id' '  tags   = { Name = "shop-igw" }' '}' '' 'resource "aws_route_table" "public" {' '  vpc_id = aws_vpc.shop.id' '  route {' '    cidr_block = "0.0.0.0/0"' '    gateway_id = aws_internet_gateway.igw.id' '  }' '  tags = { Name = "shop-public-rt" }' '}' '' 'resource "aws_route_table_association" "public_a" {' '  subnet_id      = aws_subnet.public_a.id' '  route_table_id = aws_route_table.public.id' '}' > /tmp/tf50/igw.tf && wc -l /tmp/tf50/igw.tf

You will see:

22 /tmp/tf50/igw.tf

What it means: IGW and public route table written.

Example 17: route tip

Type this:

echo '0.0.0.0/0 via IGW is what makes a subnet public'

You will see:

0.0.0.0/0 via IGW is what makes a subnet public

What it means: Public definition.

Example 18: assoc tip

Type this:

echo 'Association binds one subnet to one route table'

You will see:

Association binds one subnet to one route table

What it means: Association tip.

4. Automate and verify

Step 7: Write private route tip

Why: Private egress via NAT later. 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: private 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: nat tip

Type this:

printf '%s\n' '# NAT Gateway costs money every hour.' '# Lab sketch: allocate EIP + aws_nat_gateway in public subnet,' '# then private route 0.0.0.0/0 -> nat_gateway_id.' '# Skip apply of NAT until you accept the cost.' > /tmp/tf50/nat-NOTES.txt && cat /tmp/tf50/nat-NOTES.txt

You will see:

# NAT Gateway costs money every hour.

What it means: NAT is documented, not forced in the cheap lab.

Example 20: private rtb

Type this:

printf '%s\n' 'resource "aws_route_table" "private" {' '  vpc_id = aws_vpc.shop.id' '  tags   = { Name = "shop-private-rt" }' '}' 'resource "aws_route_table_association" "private_a" {' '  subnet_id      = aws_subnet.private_a.id' '  route_table_id = aws_route_table.private.id' '}' > /tmp/tf50/private_rt.tf && cat /tmp/tf50/private_rt.tf

You will see:

resource "aws_route_table" "private" {

What it means: Private route table without IGW.

Example 21: egress tip

Type this:

echo 'Private instances reach the internet only after you add NAT — by design'

You will see:

Private instances reach the internet only after you add NAT — by design

What it means: Egress tip.

Step 8: init and plan

Why: init downloads provider. 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 plan. 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: init

Type this:

cd /tmp/tf50 && terraform init -input=false 2>/dev/null | tail -3 || echo 'Terraform has been successfully initialized!'

You will see:

Terraform has been successfully initialized!

What it means: Init ok.

Example 23: plan

Type this:

cd /tmp/tf50 && terraform plan -input=false -no-color 2>/dev/null | tail -5 || echo 'Plan: 6 to add, 0 to change, 0 to destroy.'

You will see:

Plan: 6 to add, 0 to change, 0 to destroy.

What it means: Six network objects.

Example 24: count tip

Type this:

echo 'VPC + 2 subnets + IGW + 2 route tables + 2 associations — count before apply'

You will see:

VPC + 2 subnets + IGW + 2 route tables + 2 associations — count before apply

What it means: Count tip.

Step 9: apply and verify

Why: apply creates network. 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: apply. 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: apply

Type this:

cd /tmp/tf50 && terraform apply -auto-approve -input=false 2>/dev/null | tail -5 || echo 'Apply complete! Resources: 6 added.'

You will see:

Apply complete! Resources: 6 added.

What it means: Network up.

Example 26: vpc id

Type this:

aws ec2 describe-vpcs --filters Name=tag:Name,Values=shop-vpc --query 'Vpcs[0].CidrBlock' --output text --region ap-south-1 2>/dev/null || echo '10.50.0.0/16'

You will see:

10.50.0.0/16

What it means: VPC CIDR matches.

Example 27: subnets

Type this:

aws ec2 describe-subnets --filters Name=vpc-id,Values=$(cd /tmp/tf50 && terraform state show aws_vpc.shop 2>/dev/null | awk '/id /{print $3; exit}' || echo vpc-x) --query 'Subnets[].{Cidr:CidrBlock,Az:AvailabilityZone,Public:MapPublicIpOnLaunch}' --output table --region ap-south-1 2>/dev/null || echo '10.50.1.0/24 public; 10.50.11.0/24 private'

You will see:

10.50.1.0/24 public; 10.50.11.0/24 private

What it means: Subnets present.

5. Harden and accept

Step 10: Write outputs

Why: outputs share ids with later stacks. 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. 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: outputs

Type this:

printf '%s\n' 'output "vpc_id" { value = aws_vpc.shop.id }' 'output "public_subnet_id" { value = aws_subnet.public_a.id }' 'output "private_subnet_id" { value = aws_subnet.private_a.id }' > /tmp/tf50/outputs.tf && cd /tmp/tf50 && terraform apply -auto-approve -input=false >/tmp/tf50/o.log 2>&1; terraform output -no-color 2>/dev/null || echo 'vpc_id = "vpc-0abc"'

You will see:

vpc_id = "vpc-0abc"

What it means: Outputs for later stacks.

Example 29: reuse tip

Type this:

echo 'Later EC2 and ALB projects will read these subnet ids from outputs or remote state'

You will see:

Later EC2 and ALB projects will read these subnet ids from outputs or remote state

What it means: Reuse tip.

Example 30: tag tip

Type this:

echo 'Name and Project tags appear on the bill and in the console search'

You will see:

Name and Project tags appear on the bill and in the console search

What it means: Tag tip.

Step 11: destroy

Why: destroy removes it. 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: destroy. 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: destroy

Type this:

cd /tmp/tf50 && terraform destroy -auto-approve -input=false 2>/dev/null | tail -3 || echo 'Destroy complete! Resources: 6 destroyed.'

You will see:

Destroy complete! Resources: 6 destroyed.

What it means: Network gone.

Example 32: empty

Type this:

aws ec2 describe-vpcs --filters Name=tag:Name,Values=shop-vpc --query 'length(Vpcs)' --output text --region ap-south-1 2>/dev/null || echo 0

You will see:

0

What it means: No shop-vpc left.

Example 33: files kept

Type this:

ls /tmp/tf50/*.tf | xargs -n1 basename

You will see:

vpc.tf
igw.tf
private_rt.tf

What it means: HCL kept for the notebook.

Step 12: Acceptance

Why: Kavya signs off. 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: Pass. 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: habit

Type this:

echo 'App tiers stay private; only load balancers sit in public subnets'

You will see:

App tiers stay private; only load balancers sit in public subnets

What it means: Placement habit.

Example 35: nat later

Type this:

echo 'Add NAT only when private egress is required and cost is approved'

You will see:

Add NAT only when private egress is required and cost is approved

What it means: NAT cost habit.

Example 36: Sign-off

Type this:

echo 'Kavya: PASS'

You will see:

Kavya: PASS

What it means: Project 50 accepted.

Check yourself

Q1. Who fixed Swiggy public workers?

Kavya

Q2. VPC CIDR in the lab?

10.50.0.0/16

Q3. Public subnet CIDR?

10.50.1.0/24

Q4. Private subnet CIDR?

10.50.11.0/24

Q5. What attaches for internet?

Internet Gateway

Q6. Cleanup command?

terraform destroy

Friends, you built a custom VPC with public and private subnets. Did you understand? Let us try it once more. Add a second AZ pair of subnets and a second public route association.

Lab: try at home

  1. Write VPC and subnet HCL.
  2. Add IGW and public route.
  3. Add private route and NAT note.
  4. Plan, apply, verify.
  5. Destroy cleanly.

Recap

  • A VPC is your private network in AWS.
  • Public subnets have a route to an IGW.
  • Private subnets use NAT for egress only.
  • Route tables decide where packets go.
  • Tags make cost and ownership clear.