Röviden: A hálózat az a réteg, amit később a legfájdalmasabb átépíteni. Végigtervezünk egy multi-AZ VPC-t publikus és privát subnetekkel, NAT-tal, útvonaltáblákkal és szigorú security groupokkal — teljes Terraform-kóddal.
A hálózat az a réteg, amit a legkényelmetlenebb utólag átszabni: ha rosszul méretezed a CIDR-t vagy összekevered a publikus és privát útválasztást, később egy egész környezetet kell újraépíteni. Ezért érdemes a VPC-t az elején, tudatosan, kódban megtervezni. Ebben a cikkben egy klasszikus, két elérhetőségi zónára (AZ) terülő production VPC-t építünk: publikus subnetek a bejövő forgalomnak, privát subnetek az alkalmazásnak, NAT a kimenő forgalomhoz, és szigorúan szabályozott security groupok.
A cél-topológia
Két AZ-ban egy-egy publikus és egy-egy privát subnet. A publikus subnetekben ül az internet gateway felé nyíló load balancer és a NAT gateway. A privát subnetekben futnak az alkalmazás-instance-ok, amelyek csak a NAT-on keresztül érik el az internetet — kifelé igen, befelé közvetlenül nem.
CIDR-tervezés: gondolkodj előre
A /16-os VPC (65 536 cím) bőven elég, és hagy helyet a jövőnek. A subneteket /24-esre szabjuk (256 cím zónánként), és szándékosan hagyunk hézagot a publikus és privát tartomány között, hogy később új subnet-típusokat (pl. adatbázis) is beilleszthess ütközés nélkül.
| Subnet | CIDR | AZ | Használható IP | Cél |
|---|---|---|---|---|
| public-a | 10.0.0.0/24 | 1a | ~251 | ALB, NAT |
| public-b | 10.0.1.0/24 | 1b | ~251 | ALB |
| private-a | 10.0.10.0/24 | 1a | ~251 | app |
| private-b | 10.0.11.0/24 | 1b | ~251 | app |
| (fenntartva) | 10.0.20.0/24+ | — | — | DB, cache |
A VPC és a subnetek Terraformban
A subneteket for_each-csel generáljuk egy lokális map-ből, hogy ne másoljuk a kódot négyszer. Ez a minta jól skálázódik, ha később bővítesz.
locals {
azs = ["eu-central-1a", "eu-central-1b"]
public_subnets = {
"public-a" = { cidr = "10.0.0.0/24", az = "eu-central-1a" }
"public-b" = { cidr = "10.0.1.0/24", az = "eu-central-1b" }
}
private_subnets = {
"private-a" = { cidr = "10.0.10.0/24", az = "eu-central-1a" }
"private-b" = { cidr = "10.0.11.0/24", az = "eu-central-1b" }
}
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = merge(local.tags, { Name = "${var.project}-vpc" })
}
resource "aws_subnet" "public" {
for_each = local.public_subnets
vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr
availability_zone = each.value.az
map_public_ip_on_launch = true
tags = merge(local.tags, { Name = each.key })
}
resource "aws_subnet" "private" {
for_each = local.private_subnets
vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr
availability_zone = each.value.az
tags = merge(local.tags, { Name = each.key })
}Internet gateway, NAT és útvonaltáblák
Az internet gateway a VPC ajtaja kifelé. A publikus subnetek útvonaltáblája 0.0.0.0/0-t az IGW felé küldi. A privát subnetek viszont a NAT gatewayre mutatnak — így az app-instance-ok le tudnak tölteni csomagokat és hívhatnak külső API-t, de kívülről nem címezhetők közvetlenül.
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = merge(local.tags, { Name = "${var.project}-igw" })
}
resource "aws_eip" "nat" {
domain = "vpc"
tags = local.tags
}
resource "aws_nat_gateway" "nat" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public["public-a"].id
tags = merge(local.tags, { Name = "${var.project}-nat" })
depends_on = [aws_internet_gateway.igw]
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = merge(local.tags, { Name = "${var.project}-public-rt" })
}
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat.id
}
tags = merge(local.tags, { Name = "${var.project}-private-rt" })
}
resource "aws_route_table_association" "public" {
for_each = aws_subnet.public
subnet_id = each.value.id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private" {
for_each = aws_subnet.private
subnet_id = each.value.id
route_table_id = aws_route_table.private.id
}Security groupok: a valódi tűzfal
A security group állapotkövető (stateful): ha beengedsz egy kérést, a válasz automatikusan kimehet. A jó minta rétegez: a load balancer SG a 443-at engedi az internetről, az app SG pedig CSAK a load balancer SG-jétől fogad forgalmat — nem az egész internettől. Ez a hivatkozás-SG-re minta a legfontosabb hálózati védelem.
resource "aws_security_group" "alb" {
name = "${var.project}-alb"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTPS az internetről"
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"]
}
tags = local.tags
}
resource "aws_security_group" "app" {
name = "${var.project}-app"
vpc_id = aws_vpc.main.id
ingress {
description = "Csak az ALB-től"
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = local.tags
}Forgalomszabályozás: ki beszélhet kivel?
A rétegzett SG-k így egy tiszta forgalmi láncot adnak: az internet csak az ALB-vel beszél, az ALB csak az app-pal, az app pedig a NAT-on át ér ki. Semmi nem címezhető közvetlenül kívülről a privát rétegben.
NACL vagy security group?
Két hálózati kontroll létezik, és gyakran összekeverik őket. A security group instance-szintű és stateful; a network ACL subnet-szintű és stateless. A legtöbb esetben a security group elég és kényelmesebb; a NACL akkor jön jól, ha egész subnetre akarsz durva, IP-alapú tiltást (pl. egy támadó tartomány kizárása).
| Tulajdonság | Security Group | Network ACL |
|---|---|---|
| Szint | instance / ENI | subnet |
| Állapot | stateful | stateless |
| Szabályok | csak allow | allow és deny |
| Kiértékelés | mind | sorrendben, szám szerint |
| Tipikus használat | alapvédelem | durva subnet-szintű tiltás |
Mit jelent ez neked?
Ez a VPC-alap — két AZ, publikus és privát subnetek, NAT, rétegzett security groupok — a legtöbb production workload biztonságos kiindulása. A kulcsdöntések láthatók és verziózottak: a CIDR-terv hagy helyet a jövőnek, a privát subnetek nem címezhetők kívülről, és az SG-hivatkozás minta valódi szegmentációt ad. Ha ezt egyszer jól felépíted modulként, a következő környezet (staging, prod) már csak egy terraform apply más változókkal. A hálózatot nem szabad kézzel kattintgatni — pont ez az a réteg, ahol a kód-alapú, reprodukálható megközelítés a legtöbbet éri.