VPC & Networking: Xây dựng hạ tầng mạng

Thiết kế VPC, subnets, route tables và kết nối an toàn giữa các services trong AWS.

Amazon VPC là gì?

VPC (Virtual Private Cloud) là mạng ảo riêng trong AWS cloud. Bạn có toàn quyền kiểm soát IP ranges, subnets, route tables và network gateways.

Các thành phần chính

ComponentMô tả
VPCMạng ảo với CIDR block (VD: 10.0.0.0/16)
SubnetPhân đoạn VPC (public/private)
Route TableĐiều hướng traffic
Internet GatewayKết nối internet
NAT GatewayInternet cho private subnets
Security GroupFirewall ở instance level
NACLFirewall ở subnet level

VPC Module với Terraform

Cấu trúc Module

modules/vpc/
├── main.tf
├── variables.tf
├── outputs.tf
└── README.md

Main VPC Configuration

# modules/vpc/main.tf

# VPC
resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "${var.project_name}-vpc"
  }
}

# Internet Gateway
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-igw"
  }
}

# Public Subnets
resource "aws_subnet" "public" {
  count                   = length(var.availability_zones)
  vpc_id                  = aws_vpc.main.id
  cidr_block              = cidrsubnet(var.vpc_cidr, 4, count.index)
  availability_zone       = var.availability_zones[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.project_name}-public-${var.availability_zones[count.index]}"
    Type = "public"
  }
}

# Private Subnets
resource "aws_subnet" "private" {
  count             = length(var.availability_zones)
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 4, count.index + length(var.availability_zones))
  availability_zone = var.availability_zones[count.index]

  tags = {
    Name = "${var.project_name}-private-${var.availability_zones[count.index]}"
    Type = "private"
  }
}

# Elastic IP for NAT Gateway
resource "aws_eip" "nat" {
  count  = var.enable_nat_gateway ? 1 : 0
  domain = "vpc"

  tags = {
    Name = "${var.project_name}-nat-eip"
  }
}

# NAT Gateway
resource "aws_nat_gateway" "main" {
  count         = var.enable_nat_gateway ? 1 : 0
  allocation_id = aws_eip.nat[0].id
  subnet_id     = aws_subnet.public[0].id

  tags = {
    Name = "${var.project_name}-nat"
  }

  depends_on = [aws_internet_gateway.main]
}

# Public Route Table
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.project_name}-public-rt"
  }
}

# Private Route Table
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id

  dynamic "route" {
    for_each = var.enable_nat_gateway ? [1] : []
    content {
      cidr_block     = "0.0.0.0/0"
      nat_gateway_id = aws_nat_gateway.main[0].id
    }
  }

  tags = {
    Name = "${var.project_name}-private-rt"
  }
}

# Route Table Associations - Public
resource "aws_route_table_association" "public" {
  count          = length(var.availability_zones)
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

# Route Table Associations - Private
resource "aws_route_table_association" "private" {
  count          = length(var.availability_zones)
  subnet_id      = aws_subnet.private[count.index].id
  route_table_id = aws_route_table.private.id
}

Variables

# modules/vpc/variables.tf

variable "project_name" {
  description = "Project name for resource naming"
  type        = string
}

variable "vpc_cidr" {
  description = "CIDR block for VPC"
  type        = string
  default     = "10.0.0.0/16"
}

variable "availability_zones" {
  description = "List of availability zones"
  type        = list(string)
  default     = ["ap-southeast-1a", "ap-southeast-1b"]
}

variable "enable_nat_gateway" {
  description = "Enable NAT Gateway for private subnets"
  type        = bool
  default     = true
}

Outputs

# modules/vpc/outputs.tf

output "vpc_id" {
  value = aws_vpc.main.id
}

output "vpc_cidr" {
  value = aws_vpc.main.cidr_block
}

output "public_subnet_ids" {
  value = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  value = aws_subnet.private[*].id
}

output "internet_gateway_id" {
  value = aws_internet_gateway.main.id
}

output "nat_gateway_id" {
  value = var.enable_nat_gateway ? aws_nat_gateway.main[0].id : null
}

Sử dụng Module

# main.tf (root module)

module "vpc" {
  source = "./modules/vpc"

  project_name       = "myapp"
  vpc_cidr           = "10.0.0.0/16"
  availability_zones = ["ap-southeast-1a", "ap-southeast-1b"]
  enable_nat_gateway = true
}

# Tham chiếu outputs
resource "aws_instance" "web" {
  subnet_id = module.vpc.public_subnet_ids[0]
  # ...
}

AWS CLI Commands

# Tạo VPC
aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=my-vpc}]'

# Tạo Subnet
aws ec2 create-subnet \
  --vpc-id vpc-xxx \
  --cidr-block 10.0.1.0/24 \
  --availability-zone ap-southeast-1a

# Tạo Internet Gateway
aws ec2 create-internet-gateway
aws ec2 attach-internet-gateway --vpc-id vpc-xxx --internet-gateway-id igw-xxx

# Describe VPCs
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=my-vpc"

# Describe Subnets
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-xxx"

Network Architecture Pattern

                    Internet

                ┌───────▼───────┐
                │ Internet GW   │
                └───────┬───────┘

        ┌───────────────┼───────────────┐
        │               │               │
   ┌────▼────┐     ┌────▼────┐     ┌────▼────┐
   │Public   │     │Public   │     │Public   │
   │Subnet-A │     │Subnet-B │     │Subnet-C │
   │(ALB,NAT)│     │(ALB)    │     │(ALB)    │
   └────┬────┘     └─────────┘     └─────────┘

   ┌────▼────┐
   │ NAT GW  │
   └────┬────┘

   ┌────▼────┐     ┌─────────┐     ┌─────────┐
   │Private  │     │Private  │     │Private  │
   │Subnet-A │     │Subnet-B │     │Subnet-C │
   │(EC2,ECS)│     │(EC2,ECS)│     │(EC2,ECS)│
   └─────────┘     └─────────┘     └─────────┘

Security Groups vs NACLs

FeatureSecurity GroupNACL
LevelInstanceSubnet
StateStatefulStateless
RulesAllow onlyAllow + Deny
EvaluationAll rulesNumber order

Security Group Example

resource "aws_security_group" "alb" {
  name        = "${var.project_name}-alb-sg"
  description = "Security group for ALB"
  vpc_id      = module.vpc.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Best Practices

  1. Multi-AZ - Luôn deploy across 2+ AZs
  2. Private subnets - Đặt databases, app servers ở private
  3. NAT Gateway - Cho phép private resources access internet
  4. VPC Flow Logs - Enable để troubleshoot và audit
  5. Least privilege - Security Groups chỉ mở ports cần thiết

Bài tiếp theo: IAM Identity - Quản lý access control với Terraform.