☁️ Week 5: AWS Cloud

Day 5: VPC Networking

⏱ Duration: 5 Hours

📚 Learning Objectives

  • Understand VPC concepts and architecture
  • Create VPCs and subnets
  • Configure route tables and internet gateways
  • Set up security groups and NACLs
  • Build a complete VPC with public/private subnets

📖 Core Concepts (2 Hours)

What is VPC?

Amazon Virtual Private Cloud (VPC) lets you provision a logically isolated section of the AWS Cloud where you can launch resources in a virtual network you define.

  • VPC: Your private network in AWS
  • Subnets: Segments within a VPC (public/private)
  • Route Tables: Direct network traffic
  • Internet Gateway: Connect VPC to internet
  • NAT Gateway: Allow private subnets to access internet

VPC Architecture

┌─────────────────────────────────────────────────────────────┐ │ AWS Region (us-east-1) │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ VPC (10.0.0.0/16) │ │ │ │ ┌──────────────┐ │ │ │ │ │ Internet │ │ │ │ │ │ Gateway │ │ │ │ │ └──────┬───────┘ │ │ │ │ │ │ │ │ │ ┌────────────────────────────┼───────────────────┐ │ │ │ │ │ Public Subnet (10.0.1.0/24) │ │ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ │ │ EC2 │ │ NAT │ │ ALB │ │ │ │ │ │ │ │ (Bastion)│ │ Gateway │ │ │ │ │ │ │ │ │ └──────────┘ └────┬─────┘ └──────────┘ │ │ │ │ │ └───────────────────────┼────────────────────────┘ │ │ │ │ │ │ │ │ │ ┌───────────────────────┼────────────────────────┐ │ │ │ │ │ Private Subnet (10.0.2.0/24) │ │ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ │ │ EC2 │ │ EC2 │ │ RDS │ │ │ │ │ │ │ │ (App) │ │ (App) │ │ │ │ │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ └────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘

CIDR Notation

CIDR = Classless Inter-Domain Routing Format: IP_ADDRESS/PREFIX_LENGTH Examples: 10.0.0.0/16 = 10.0.0.0 - 10.0.255.255 (65,536 IPs) 10.0.0.0/24 = 10.0.0.0 - 10.0.0.255 (256 IPs) 10.0.0.0/28 = 10.0.0.0 - 10.0.0.15 (16 IPs) VPC CIDR Guidelines: ├── Allowed: /16 to /28 ├── Recommended: /16 for flexibility ├── Cannot overlap with other VPCs if peered └── AWS reserves 5 IPs per subnet: .0 = Network address .1 = VPC router .2 = DNS .3 = Future use .255 = Broadcast

Security: Security Groups vs NACLs

┌─────────────────────┬─────────────────────┐ │ Security Groups │ NACLs │ ├─────────────────────┼─────────────────────┤ │ Instance level │ Subnet level │ │ Stateful │ Stateless │ │ Allow rules only │ Allow & Deny rules │ │ All rules evaluated │ Rules in order │ │ Must be associated │ Auto-applies │ └─────────────────────┴─────────────────────┘ Stateful (SG): Return traffic auto-allowed Stateless (NACL): Must explicitly allow return traffic Best Practice: Use both for defense in depth

VPC Components Summary

Component Description ───────────────────────────────────────────────────── VPC Virtual network container Subnet IP range within VPC (AZ-specific) Internet Gateway Connects VPC to internet NAT Gateway Outbound internet for private subnets Route Table Rules for routing traffic Security Group Instance-level firewall (stateful) NACL Subnet-level firewall (stateless) Elastic IP Static public IP address VPC Peering Connect VPCs together VPN Gateway VPN connection to on-premises

🔬 Hands-on Lab (2.5 Hours)

Lab 1: Create VPC with Subnets

  • Create a custom VPC
  • Create public and private subnets
# Create VPC VPC_ID=$(aws ec2 create-vpc \ --cidr-block 10.0.0.0/16 \ --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=devops-vpc}]' \ --query 'Vpc.VpcId' --output text) echo "VPC ID: $VPC_ID" # Enable DNS hostnames aws ec2 modify-vpc-attribute \ --vpc-id $VPC_ID \ --enable-dns-hostnames # Create public subnet in AZ-a PUBLIC_SUBNET=$(aws ec2 create-subnet \ --vpc-id $VPC_ID \ --cidr-block 10.0.1.0/24 \ --availability-zone us-east-1a \ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=devops-public-subnet}]' \ --query 'Subnet.SubnetId' --output text) echo "Public Subnet: $PUBLIC_SUBNET" # Create private subnet in AZ-a PRIVATE_SUBNET=$(aws ec2 create-subnet \ --vpc-id $VPC_ID \ --cidr-block 10.0.2.0/24 \ --availability-zone us-east-1a \ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=devops-private-subnet}]' \ --query 'Subnet.SubnetId' --output text) echo "Private Subnet: $PRIVATE_SUBNET" # Enable auto-assign public IP for public subnet aws ec2 modify-subnet-attribute \ --subnet-id $PUBLIC_SUBNET \ --map-public-ip-on-launch

Lab 2: Configure Internet Gateway

  • Create and attach internet gateway
  • Configure route table for public subnet
# Create Internet Gateway IGW_ID=$(aws ec2 create-internet-gateway \ --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=devops-igw}]' \ --query 'InternetGateway.InternetGatewayId' --output text) echo "Internet Gateway: $IGW_ID" # Attach to VPC aws ec2 attach-internet-gateway \ --internet-gateway-id $IGW_ID \ --vpc-id $VPC_ID # Create public route table PUBLIC_RT=$(aws ec2 create-route-table \ --vpc-id $VPC_ID \ --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=devops-public-rt}]' \ --query 'RouteTable.RouteTableId' --output text) echo "Public Route Table: $PUBLIC_RT" # Add route to internet gateway aws ec2 create-route \ --route-table-id $PUBLIC_RT \ --destination-cidr-block 0.0.0.0/0 \ --gateway-id $IGW_ID # Associate public subnet with public route table aws ec2 associate-route-table \ --route-table-id $PUBLIC_RT \ --subnet-id $PUBLIC_SUBNET

Lab 3: Configure NAT Gateway

  • Create NAT Gateway for private subnet
  • Configure route table for private subnet
# Allocate Elastic IP for NAT Gateway EIP_ALLOC=$(aws ec2 allocate-address \ --domain vpc \ --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=devops-nat-eip}]' \ --query 'AllocationId' --output text) echo "Elastic IP Allocation: $EIP_ALLOC" # Create NAT Gateway in public subnet NAT_GW=$(aws ec2 create-nat-gateway \ --subnet-id $PUBLIC_SUBNET \ --allocation-id $EIP_ALLOC \ --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=devops-nat}]' \ --query 'NatGateway.NatGatewayId' --output text) echo "NAT Gateway: $NAT_GW" # Wait for NAT Gateway to be available echo "Waiting for NAT Gateway..." aws ec2 wait nat-gateway-available --nat-gateway-ids $NAT_GW # Create private route table PRIVATE_RT=$(aws ec2 create-route-table \ --vpc-id $VPC_ID \ --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=devops-private-rt}]' \ --query 'RouteTable.RouteTableId' --output text) echo "Private Route Table: $PRIVATE_RT" # Add route to NAT Gateway aws ec2 create-route \ --route-table-id $PRIVATE_RT \ --destination-cidr-block 0.0.0.0/0 \ --nat-gateway-id $NAT_GW # Associate private subnet with private route table aws ec2 associate-route-table \ --route-table-id $PRIVATE_RT \ --subnet-id $PRIVATE_SUBNET

Lab 4: Create Security Groups

  • Create security group for public instances
  • Create security group for private instances
# Create public security group (bastion/web) PUBLIC_SG=$(aws ec2 create-security-group \ --group-name devops-public-sg \ --description "Public subnet security group" \ --vpc-id $VPC_ID \ --query 'GroupId' --output text) echo "Public Security Group: $PUBLIC_SG" # Add rules to public security group aws ec2 authorize-security-group-ingress \ --group-id $PUBLIC_SG \ --protocol tcp --port 22 --cidr 0.0.0.0/0 aws ec2 authorize-security-group-ingress \ --group-id $PUBLIC_SG \ --protocol tcp --port 80 --cidr 0.0.0.0/0 aws ec2 authorize-security-group-ingress \ --group-id $PUBLIC_SG \ --protocol tcp --port 443 --cidr 0.0.0.0/0 # Create private security group (app servers) PRIVATE_SG=$(aws ec2 create-security-group \ --group-name devops-private-sg \ --description "Private subnet security group" \ --vpc-id $VPC_ID \ --query 'GroupId' --output text) echo "Private Security Group: $PRIVATE_SG" # Allow SSH only from public security group aws ec2 authorize-security-group-ingress \ --group-id $PRIVATE_SG \ --protocol tcp --port 22 \ --source-group $PUBLIC_SG # Allow app traffic from public subnet aws ec2 authorize-security-group-ingress \ --group-id $PRIVATE_SG \ --protocol tcp --port 8080 \ --source-group $PUBLIC_SG # List security group rules aws ec2 describe-security-groups \ --group-ids $PUBLIC_SG $PRIVATE_SG \ --query 'SecurityGroups[*].[GroupName,IpPermissions]'

Lab 5: Launch Instances and Test

  • Launch instance in public subnet
  • Launch instance in private subnet
  • Test connectivity
# Create key pair aws ec2 create-key-pair \ --key-name vpc-key \ --query 'KeyMaterial' --output text > vpc-key.pem chmod 400 vpc-key.pem # Get latest Amazon Linux 2023 AMI AMI_ID=$(aws ec2 describe-images \ --owners amazon \ --filters "Name=name,Values=al2023-ami-2023*-x86_64" \ "Name=state,Values=available" \ --query 'Images | sort_by(@, &CreationDate) | [-1].ImageId' \ --output text) # Launch public instance (bastion) PUBLIC_INSTANCE=$(aws ec2 run-instances \ --image-id $AMI_ID \ --instance-type t2.micro \ --key-name vpc-key \ --subnet-id $PUBLIC_SUBNET \ --security-group-ids $PUBLIC_SG \ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=bastion-host}]' \ --query 'Instances[0].InstanceId' --output text) # Launch private instance PRIVATE_INSTANCE=$(aws ec2 run-instances \ --image-id $AMI_ID \ --instance-type t2.micro \ --key-name vpc-key \ --subnet-id $PRIVATE_SUBNET \ --security-group-ids $PRIVATE_SG \ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=app-server}]' \ --query 'Instances[0].InstanceId' --output text) # Wait for instances aws ec2 wait instance-running --instance-ids $PUBLIC_INSTANCE $PRIVATE_INSTANCE # Get IPs PUBLIC_IP=$(aws ec2 describe-instances \ --instance-ids $PUBLIC_INSTANCE \ --query 'Reservations[0].Instances[0].PublicIpAddress' --output text) PRIVATE_IP=$(aws ec2 describe-instances \ --instance-ids $PRIVATE_INSTANCE \ --query 'Reservations[0].Instances[0].PrivateIpAddress' --output text) echo "Bastion Public IP: $PUBLIC_IP" echo "App Server Private IP: $PRIVATE_IP" # Test: SSH to bastion, then to private instance # First, copy key to bastion scp -i vpc-key.pem vpc-key.pem ec2-user@$PUBLIC_IP:~/ # SSH to bastion ssh -i vpc-key.pem ec2-user@$PUBLIC_IP # From bastion, SSH to private instance # ssh -i vpc-key.pem ec2-user@PRIVATE_IP # Test internet from private instance # curl -s http://checkip.amazonaws.com

Lab 6: Clean Up All Resources

# Terminate instances aws ec2 terminate-instances --instance-ids $PUBLIC_INSTANCE $PRIVATE_INSTANCE aws ec2 wait instance-terminated --instance-ids $PUBLIC_INSTANCE $PRIVATE_INSTANCE # Delete NAT Gateway aws ec2 delete-nat-gateway --nat-gateway-id $NAT_GW echo "Waiting for NAT Gateway deletion..." sleep 60 # Release Elastic IP aws ec2 release-address --allocation-id $EIP_ALLOC # Delete subnets aws ec2 delete-subnet --subnet-id $PUBLIC_SUBNET aws ec2 delete-subnet --subnet-id $PRIVATE_SUBNET # Delete route tables (disassociate first if needed) aws ec2 delete-route-table --route-table-id $PUBLIC_RT aws ec2 delete-route-table --route-table-id $PRIVATE_RT # Detach and delete internet gateway aws ec2 detach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID # Delete security groups aws ec2 delete-security-group --group-id $PUBLIC_SG aws ec2 delete-security-group --group-id $PRIVATE_SG # Delete VPC aws ec2 delete-vpc --vpc-id $VPC_ID # Delete key pair aws ec2 delete-key-pair --key-name vpc-key rm vpc-key.pem echo "Cleanup complete!"

✅ Day 5 Checklist

  • Understand VPC components and architecture
  • Can create VPCs and subnets
  • Can configure internet and NAT gateways
  • Can set up route tables
  • Understand security groups vs NACLs
  • Built complete VPC with public/private subnets