summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--astroshop-terraform/README.md28
-rw-r--r--astroshop-terraform/backend.tf4
-rw-r--r--astroshop-terraform/main.tf9
-rw-r--r--astroshop-terraform/modules/vpc/README.md260
-rw-r--r--astroshop-terraform/modules/vpc/main.tf103
-rw-r--r--astroshop-terraform/modules/vpc/outputs.tf14
-rw-r--r--astroshop-terraform/modules/vpc/variables.tf24
-rw-r--r--astroshop-terraform/variables.tf29
9 files changed, 472 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..66f8fb5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea/
+.vscode/
diff --git a/astroshop-terraform/README.md b/astroshop-terraform/README.md
new file mode 100644
index 0000000..5cee086
--- /dev/null
+++ b/astroshop-terraform/README.md
@@ -0,0 +1,28 @@
+# Detailed Breakdown of Terraform Configuration
+
+## 0. BACKEND (3 resources) - State Management
+
+### 1. **S3 Bucket: `astroshop-terraform-state-647242312368`**
+**Purpose:** Remote state storage
+- Stores your Terraform state file (tracks all infrastructure you create)
+- Named with your AWS account ID to ensure global uniqueness
+- `prevent_destroy = true` prevents accidental deletion
+
+**Why it matters:** Without this, Terraform state would be stored locally, making it:
+- Hard to collaborate (other team members can't see changes)
+- Risky (if your laptop dies, you lose track of infrastructure)
+
+### 2. **S3 Bucket Versioning**
+**Purpose:** State file backup and rollback
+- Keeps version history of your state file
+- Lets you recover from mistakes: `terraform state pull <version>`
+- If you accidentally corrupt state, you can restore from an older version
+
+### 3. **S3 Bucket Server-Side Encryption (AES256)**
+**Purpose:** Security
+- Encrypts state file at rest
+- Your state contains sensitive info (passwords, API keys, database credentials)
+- AES256 is AWS-managed encryption (free, automatic)
+
+---
+
diff --git a/astroshop-terraform/backend.tf b/astroshop-terraform/backend.tf
index 10553ae..88e6e36 100644
--- a/astroshop-terraform/backend.tf
+++ b/astroshop-terraform/backend.tf
@@ -1,5 +1,7 @@
+data "aws_caller_identity" "current" {}
+
resource "aws_s3_bucket" "terraform_state" {
- bucket = "astroshop-terraform-state"
+ bucket = "astroshop-terraform-state-${data.aws_caller_identity.current.account_id}"
lifecycle {
prevent_destroy = true
diff --git a/astroshop-terraform/main.tf b/astroshop-terraform/main.tf
new file mode 100644
index 0000000..fe7b692
--- /dev/null
+++ b/astroshop-terraform/main.tf
@@ -0,0 +1,9 @@
+module "vpc" {
+ source = "./modules/vpc"
+
+ vpc_cidr = var.vpc_cidr
+ availability_zones = var.availability_zones
+ private_subnet_cidrs = var.private_subnet_cidrs
+ public_subnet_cidrs = var.public_subnet_cidrs
+ cluster_name = var.cluster_name
+} \ No newline at end of file
diff --git a/astroshop-terraform/modules/vpc/README.md b/astroshop-terraform/modules/vpc/README.md
new file mode 100644
index 0000000..bac9af0
--- /dev/null
+++ b/astroshop-terraform/modules/vpc/README.md
@@ -0,0 +1,260 @@
+# Module 1: VPC (Virtual Private Cloud) - 24 resources
+
+VPC is a logically **isolated network in AWS**. Everything inside needs to communicate through VPC.
+
+### **Core Network Infrastructure:**
+
+#### **1. VPC: `astroshop-eks-cluster-vpc`**
+```
+CIDR: 10.0.0.0/16 (65,536 IP addresses available)
+```
+**Purpose:** Main network container
+- Private network isolated from the internet
+- All your resources (EKS cluster, databases, etc.) live here
+- DNS enabled for internal service discovery
+- Cannot directly reach outside without routing rules
+
+**Visual:**
+```
+┌─────────────────────────────────────────┐
+│ VPC: 10.0.0.0/16 │
+│ (Your entire isolated network) │
+│ │
+│ ┌──────────┐ ┌──────────┐ │
+│ │ Subnet │ │ Subnet │ ... │
+│ │ 10.0.x/24│ │ 10.0.x/24│ │
+│ └──────────┘ └──────────┘ │
+└─────────────────────────────────────────┘
+```
+
+---
+
+### **Subnets: Dividing the VPC into Smaller Zones**
+
+#### **3 Private Subnets** (for EKS worker nodes)
+```
+- private-1: 10.0.1.0/24 (256 IPs) → AZ: ap-south-1a
+- private-2: 10.0.2.0/24 (256 IPs) → AZ: ap-south-1b
+- private-3: 10.0.3.0/24 (256 IPs) → AZ: ap-south-1c
+```
+
+**Purpose:**
+- Host your EKS worker nodes (Kubernetes pods run here)
+- No public internet access (secure)
+- Instances get private IPs: `10.0.1.x`, `10.0.2.x`, etc.
+- Cannot be reached from the internet directly
+- Have tags for Kubernetes load balancer discovery
+
+**Why 3 subnets in 3 AZs?**
+- **High Availability**: If one AZ goes down, your cluster survives
+- **Load Distribution**: Spreads traffic across zones
+- **Cost-effective redundancy**: No extra cost for multi-AZ
+
+#### **3 Public Subnets** (for load balancers/NAT)
+```
+- public-1: 10.0.4.0/24 (256 IPs) → AZ: ap-south-1a
+- public-2: 10.0.5.0/24 (256 IPs) → AZ: ap-south-1b
+- public-3: 10.0.6.0/24 (256 IPs) → AZ: ap-south-1c
+```
+
+**Purpose:**
+- Host internet-facing load balancers
+- Auto-assign public IPs to resources (`map_public_ip_on_launch = true`)
+- Can reach the internet directly
+- Will hold NAT Gateways for private subnets
+
+---
+
+### **Internet Connectivity:**
+
+#### **1. Internet Gateway (IGW): `astroshop-eks-cluster-igw`**
+**Purpose:** Gateway between your VPC and the internet
+
+**How it works:**
+```
+Internet
+ ↓
+Internet Gateway
+ ↓
+Public Subnets (10.0.4-6.0/24)
+ ↓
+Load Balancers / Public Resources
+```
+
+**Examples:**
+- External traffic reaches your Kubernetes service (LoadBalancer type)
+- Users access your web application through the IGW
+
+---
+
+#### **3 NAT Gateways** (one per AZ)
+**Purpose:** Allow private resources to reach the internet (one-way)
+
+**How it works:**
+```
+Private Subnet (10.0.1.0/24)
+ ↓
+ Pod needs to download Docker image from DockerHub
+ ↓
+ NAT Gateway (in public subnet)
+ ↓
+ Internet Gateway
+ ↓
+ DockerHub (internet)
+ ↓
+ Response comes back through NAT
+ ↓
+ Pod receives Docker image ✓
+```
+
+**Key:** Response traffic automatically finds way back to private subnet
+
+**Cost Warning:** USD 0.45/day per NAT Gateway in ap-south-1 = approx $40/month for 3
+
+---
+
+#### **3 Elastic IPs (EIPs)** for NAT Gateways
+**Purpose:** Static public IP for each NAT Gateway
+
+**Why needed?**
+- When private subnet makes request through NAT, it needs a public IP
+- EIP ensures it's always the same IP (important for whitelisting)
+- If NAT Gateway restarts, EIP stays attached
+
+**Example flow:**
+```
+Pod (10.0.1.10) → NAT Gateway → Internet (appears as EIP: x.y.z.w)
+```
+
+---
+
+### **Routing: How Traffic Flows**
+
+#### **1 Public Route Table**
+**Purpose:** Route traffic from public subnets to internet
+
+**Route Rule:**
+```
+Destination: 0.0.0.0/0 (everything) → Target: Internet Gateway
+```
+
+**In English:** Any traffic from public subnets destined for outside VPC goes through IGW
+
+**Example:**
+```
+Client request: 203.0.113.50 (internet) → Your Load Balancer (10.0.4.x)
+ ↓
+ IGW
+ ↓
+ Public Subnet
+ ↓
+ Load Balancer receives it ✓
+```
+
+---
+
+#### **3 Private Route Tables** (one per AZ)
+**Purpose:** Route traffic from private subnets through NAT
+
+**Route Rule:**
+```
+Destination: 0.0.0.0/0 (everything) → Target: NAT Gateway (in same AZ)
+```
+
+**In English:** Any traffic from private subnets destined for outside VPC goes through NAT
+
+**Why one per AZ?**
+- **Redundancy**: If NAT Gateway in AZ-a fails, only AZ-a is affected
+- **Performance**: Traffic stays within same AZ (lower latency)
+- **Cost**: You pay per NAT, so this is necessary
+
+**Example:**
+```
+Pod in private-1 (10.0.1.x) needs to reach DockerHub
+ ↓
+ Private Route Table-1
+ ↓
+ NAT Gateway-1 (in public-1)
+ ↓
+ Internet Gateway
+ ↓
+ DockerHub (internet)
+```
+
+---
+
+#### **6 Route Table Associations**
+**Purpose:** Connect subnets to their route tables
+
+**Mappings:**
+```
+Public Subnets (3):
+ - public-1 → Public Route Table
+ - public-2 → Public Route Table
+ - public-3 → Public Route Table
+
+Private Subnets (3):
+ - private-1 → Private Route Table-1
+ - private-2 → Private Route Table-2
+ - private-3 → Private Route Table-3
+```
+
+**Without these:** Traffic wouldn't know where to go!
+
+---
+
+## COMPLETE TRAFFIC FLOW DIAGRAM
+
+```
+┌────────────────────────────────────────────────────────────┐
+│ INTERNET │
+└───────────────────────┬──────────────────────────────────────┘
+ │
+ IGW (Internet Gateway)
+ │
+ ┌───────────────┴────────────────┐
+ │ │
+ ┌────▼─────┐ ┌─────▼──────┐
+ │ Public │ │ Private │
+ │ Subnet │ (Load Balancers) │ Subnet │
+ │10.0.4/24 │◄──────────────────►│ 10.0.1/24 │
+ └────┬─────┘ (internal) │(EKS Nodes) │
+ │ └─────┬──────┘
+ │ (external traffic) │
+ │ │ (needs internet)
+ │ NAT Gateway
+ │ │
+ └────────────────┬───────────────┘
+ │
+ IGW (outbound)
+ │
+ INTERNET
+```
+
+---
+
+## Summary Table
+
+| Component | Count | Purpose | Cost |
+|-----------|-------|---------|------|
+| VPC | 1 | Network container | Free |
+| Public Subnets | 3 | Load balancers/internet access | Free |
+| Private Subnets | 3 | EKS nodes (secure) | Free |
+| Internet Gateway | 1 | Internet connectivity | Free |
+| NAT Gateways | 3 | Private → Internet | $0.45/day each |
+| Elastic IPs | 3 | Static IP for NAT | Free (when attached) |
+| Route Tables | 4 | Traffic routing | Free |
+
+**Monthly VPC Cost:** ~$40 (NAT Gateways only) + data processing
+
+---
+
+## When EKS Deploys (Later)
+
+Your worker nodes will:
+```
+1. Launch in private subnets (10.0.1-3.0/24)
+2. Download container images via NAT → IGW → Internet
+3. Receive external traffic via Load Balancer in public subnet
+4. Respond back through same path
+``` \ No newline at end of file
diff --git a/astroshop-terraform/modules/vpc/main.tf b/astroshop-terraform/modules/vpc/main.tf
new file mode 100644
index 0000000..3694588
--- /dev/null
+++ b/astroshop-terraform/modules/vpc/main.tf
@@ -0,0 +1,103 @@
+resource "aws_vpc" "main" {
+ cidr_block = var.vpc_cidr
+ enable_dns_support = true
+ enable_dns_hostnames = true
+
+ tags = {
+ Name = "${var.cluster_name}-vpc"
+ }
+}
+
+resource "aws_subnet" "private" {
+ count = length(var.private_subnet_cidrs)
+ vpc_id = aws_vpc.main.id
+ cidr_block = var.private_subnet_cidrs[count.index]
+ availability_zone = var.availability_zones[count.index]
+
+ tags = {
+ Name = "${var.cluster_name}-private-${count.index + 1}"
+ "kubernetes.io/cluster/${var.cluster_name}" = "shared"
+ "kubernetes.io/role/internal-elb" = "1"
+ }
+}
+
+resource "aws_subnet" "public" {
+ count = length(var.public_subnet_cidrs)
+ vpc_id = aws_vpc.main.id
+ cidr_block = var.public_subnet_cidrs[count.index]
+ availability_zone = var.availability_zones[count.index]
+
+ map_public_ip_on_launch = true
+
+ tags = {
+ Name = "${var.cluster_name}-public-${count.index + 1}"
+ "kubernetes.io/cluster/${var.cluster_name}" = "shared"
+ "kubernetes.io/role/elb" = "1"
+ }
+}
+
+resource "aws_internet_gateway" "main" {
+ vpc_id = aws_vpc.main.id
+
+ tags = {
+ Name = "${var.cluster_name}-igw"
+ }
+}
+
+resource "aws_eip" "nat" {
+ count = length(var.public_subnet_cidrs)
+ domain = "vpc"
+
+ tags = {
+ Name = "${var.cluster_name}-nat-${count.index + 1}"
+ }
+}
+
+resource "aws_nat_gateway" "main" {
+ count = length(var.public_subnet_cidrs)
+ allocation_id = aws_eip.nat[count.index].id
+ subnet_id = aws_subnet.public[count.index].id
+
+ tags = {
+ Name = "${var.cluster_name}-nat-${count.index + 1}"
+ }
+}
+
+resource "aws_route_table" "public" {
+ vpc_id = aws_vpc.main.id
+
+ route {
+ cidr_block = "0.0.0.0/0"
+ gateway_id = aws_internet_gateway.main.id
+ }
+
+ tags = {
+ Name = "${var.cluster_name}-public"
+ }
+}
+
+resource "aws_route_table" "private" {
+ count = length(var.private_subnet_cidrs)
+ vpc_id = aws_vpc.main.id
+
+ route {
+ cidr_block = "0.0.0.0/0"
+ nat_gateway_id = aws_nat_gateway.main[count.index].id
+ }
+
+ tags = {
+ Name = "${var.cluster_name}-private-${count.index + 1}"
+ }
+}
+
+resource "aws_route_table_association" "private" {
+ count = length(var.private_subnet_cidrs)
+ subnet_id = aws_subnet.private[count.index].id
+ route_table_id = aws_route_table.private[count.index].id
+}
+
+resource "aws_route_table_association" "public" {
+ count = length(var.public_subnet_cidrs)
+ subnet_id = aws_subnet.public[count.index].id
+ route_table_id = aws_route_table.public.id
+} \ No newline at end of file
diff --git a/astroshop-terraform/modules/vpc/outputs.tf b/astroshop-terraform/modules/vpc/outputs.tf
new file mode 100644
index 0000000..4ff85f4
--- /dev/null
+++ b/astroshop-terraform/modules/vpc/outputs.tf
@@ -0,0 +1,14 @@
+output "vpc_id" {
+ description = "VPC ID"
+ value = aws_vpc.main.id
+}
+
+output "private_subnet_ids" {
+ description = "Private subnet IDs"
+ value = aws_subnet.private[*].id
+}
+
+output "public_subnet_ids" {
+ description = "Public subnet IDs"
+ value = aws_subnet.public[*].id
+} \ No newline at end of file
diff --git a/astroshop-terraform/modules/vpc/variables.tf b/astroshop-terraform/modules/vpc/variables.tf
new file mode 100644
index 0000000..50fe184
--- /dev/null
+++ b/astroshop-terraform/modules/vpc/variables.tf
@@ -0,0 +1,24 @@
+variable "vpc_cidr" {
+ description = "CIDR block for VPC"
+ type = string
+}
+
+variable "availability_zones" {
+ description = "Availability zones"
+ type = list(string)
+}
+
+variable "private_subnet_cidrs" {
+ description = "CIDR blocks for private subnets"
+ type = list(string)
+}
+
+variable "public_subnet_cidrs" {
+ description = "CIDR blocks for public subnets"
+ type = list(string)
+}
+
+variable "cluster_name" {
+ description = "Name of the EKS cluster"
+ type = string
+} \ No newline at end of file
diff --git a/astroshop-terraform/variables.tf b/astroshop-terraform/variables.tf
index 3b0968c..37ae09c 100644
--- a/astroshop-terraform/variables.tf
+++ b/astroshop-terraform/variables.tf
@@ -2,4 +2,33 @@ variable "region" {
description = "The AWS region to deploy resources in"
type = string
default = "ap-south-1"
+}
+variable "vpc_cidr" {
+ description = "The CIDR block for the VPC"
+ type = string
+ default = "10.0.0.0/16"
+}
+
+variable "availability_zones" {
+ description = "List of availability zones to use"
+ type = list(string)
+ default = ["ap-south-1a", "ap-south-1b", "ap-south-1c"]
+}
+
+variable "private_subnet_cidrs" {
+ description = "List of CIDR blocks for private subnets"
+ type = list(string)
+ default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+}
+
+variable "public_subnet_cidrs" {
+ description = "List of CIDR blocks for public subnets"
+ type = list(string)
+ default = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
+}
+
+variable "cluster_name" {
+ description = "The name of the EKS cluster"
+ type = string
+ default = "astroshop-eks-cluster"
} \ No newline at end of file