💾

Laboratorijska vežba – Modul 25 – Projektovanje i izrada VPC mreže

Cilj vežbe

  • Deo 1 (svi polaznici, besplatno): isprojektovati VPC za firmu (adresni plan u dve zone dostupnosti, tabele ruta, security group-e i network ACL) i proveriti adresni plan Python skriptom.
  • Deo 2 (opciono, AWS): u stvarnom AWS nalogu napraviti VPC sa javnim i privatnim subnetom, internet gateway-em, tabelom ruta, security group-om, network ACL-om i jednim veb serverom. Zatim dijagnostikovati dva tipična kvara i obrisati sve resurse.

Napomena o troškovima (Deo 2): VPC, subneti, tabele ruta, internet gateway, security group-e i network ACL-ovi se ne naplaćuju. Naplaćuju se EC2 instanca i javna IPv4 adresa, po satu. U okviru besplatnih pogodnosti novih naloga to je obično besplatno, a i bez njih vežba od 1–2 sata košta svega nekoliko centi. Uslovi se menjaju, pa ih proverite na stranici AWS Free Tier. Ne pravite NAT gateway ni load balancer, osim u dodatnom izazovu, uz tamo opisane mere. Korak 14 (brisanje resursa) je obavezan.

Potrebno predznanje

  • Kompletna teorija ovog modula (Teme 1–15).
  • Subnetting i VLSM (Modul 5), rutiranje (Modul 11), stateful/stateless filtriranje (Modul 16), osnove Python-a (Modul 24).

Potrebni programi

  • Deo 1: Python 3 (Ubuntu Server VM iz Modula 18 ili bilo koji računar) i editor teksta.
  • Deo 2: veb pregledač i AWS nalog. AWS CloudShell (komandna linija u pregledaču, sa već podešenim AWS CLI-jem) ne zahteva nikakvu instalaciju.

Scenario

Firma „Vojvodina Agro" pravi veb portal za partnere u AWS-u, u regionu eu-central-1 (Frankfurt). Zahtevi:

  • Lokalna mreža centrale je 172.16.0.0/16, a poslovnice koriste 192.168.0.0/16. VPC će kasnije biti povezan sa centralom site-to-site VPN-om.
  • Portal radi u dve zone dostupnosti.
  • Javni subneti: load balancer i NAT gateway — do 50 adresa po zoni.
  • Aplikacioni subneti (privatni): do 200 instanci po zoni; izlaz na internet preko NAT gateway-a svoje zone; pristup centrali preko VPN-a.
  • Subneti baze (privatni): do 20 adresa po zoni; bez izlaza na internet; pristup samo iz aplikacionih subneta i administratorske mreže centrale 172.16.50.0/24.
  • Korisnici pristupaju portalu samo preko HTTPS-a (443) na load balancer-u. Aplikacija sluša na portu 8080, a baza je PostgreSQL (5432).

DEO 1 – Projektovanje (svi polaznici)

Korak 1 – Izbor opsega VPC-a

Izaberite CIDR opseg VPC-a veličine /16 iz privatnog opsega 10.0.0.0/8, tako da se ne preklapa sa mrežama centrale i poslovnica. Obrazložite izbor u jednoj rečenici.

Korak 2 – Adresni plan subneta (VLSM)

Popunite tabelu, uzimajući u obzir 5 rezervisanih adresa po subnetu u AWS-u. Za svaki sloj izaberite najmanji prefiks koji zadovoljava zahtev.

SubnetZonaPotrebno adresaPrefiksCIDRUpotrebljivo (−5)
javni-aa50
javni-bb50
app-aa200
app-bb200
baza-aa20
baza-bb20

Korak 3 – Provera adresnog plana Python skriptom

Napravite fajl provera_vpc.py. Vrednosti ispod su neutralan primer (VPC 10.99.0.0/16, svi subneti /24) koji služi samo da skripta može odmah da se pokrene — zamenite VPC i rečnik SUBNETI svojim planom iz Koraka 1 i 2:

import ipaddress

VPC = "10.99.0.0/16"
LOKALNE_MREZE = {"centrala": "172.16.0.0/16", "poslovnice": "192.168.0.0/16"}
SUBNETI = {
    "javni-a": "10.99.1.0/24",
    "javni-b": "10.99.2.0/24",
    "app-a": "10.99.11.0/24",
    "app-b": "10.99.12.0/24",
    "baza-a": "10.99.21.0/24",
    "baza-b": "10.99.22.0/24",
}
REZERVISANO = 5

greske = 0
vpc = ipaddress.ip_network(VPC)
lokalne = {ime: ipaddress.ip_network(cidr) for ime, cidr in LOKALNE_MREZE.items()}

for ime, lokalna in lokalne.items():
    if vpc.overlaps(lokalna):
        print(f"GREŠKA: VPC {vpc} se preklapa sa mrežom {ime} ({lokalna})")
        greske += 1

mreze = {}
for ime, cidr in SUBNETI.items():
    try:
        mreze[ime] = ipaddress.ip_network(cidr)
    except ValueError as e:
        print(f"GREŠKA: {ime} — neispravan CIDR ({e})")
        greske += 1
        continue
    if not mreze[ime].subnet_of(vpc):
        print(f"GREŠKA: {ime} {cidr} nije unutar VPC-a {vpc}")
        greske += 1

imena = list(mreze)
for i, prvi in enumerate(imena):
    for drugi in imena[i + 1:]:
        if mreze[prvi].overlaps(mreze[drugi]):
            print(f"GREŠKA: {prvi} ({mreze[prvi]}) se preklapa sa {drugi} ({mreze[drugi]})")
            greske += 1

print(f"\n{'Subnet':10} {'CIDR':16} {'Upotrebljivo':>12}")
for ime, mreza in mreze.items():
    print(f"{ime:10} {str(mreza):16} {mreza.num_addresses - REZERVISANO:>12}")

print("\nPlan je ispravan." if greske == 0 else f"\nPronađeno grešaka: {greske}")

Pokrenite python3 provera_vpc.py sa svojim planom i proverite da skripta prijavljuje „Plan je ispravan." i da kolona „Upotrebljivo" zadovoljava zahteve scenarija. Zatim proverite da li skripta zaista hvata greške — privremeno unesite svaku od sledećih izmena, pokrenite skriptu, pa izmenu vratite:

  1. subnet app-b promenite tako da se preklapa sa app-a (npr. druga polovina mreže app-a sa prefiksom /25);
  2. za baza-a upišite adresu koja nije početak mreže (npr. .8 sa prefiksom /27);
  3. VPC = "172.16.0.0/12" (preklapanje sa centralom).

Korak 4 – Tabele ruta

Za svaku tabelu ruta napišite rute (odredište → cilj) i navedite kojim subnetima je pridružena: rt-javni, rt-app-a, rt-app-b, rt-baza. Koristite ciljeve local, igw, nat-a, nat-b i vgw (VPN ka centrali i poslovnicama).

Korak 5 – Security group-e i NACL

  1. Napišite dolazna pravila za sg-lb, sg-app i sg-baza tako da poštuju zahteve scenarija i princip najmanjih privilegija. Gde god je moguće, koristite reference na druge security group-e.
  2. Napišite NACL za subnete baze (dolazna i odlazna pravila sa rednim brojevima), imajući u vidu da je NACL stateless.
  3. Nacrtajte dijagram arhitekture (draw.io ili Mermaid) i sačuvajte ga uz plan.

DEO 2 – Izrada u AWS-u (opciono)

U Delu 2 pravite pojednostavljenu verziju plana: VPC 10.30.0.0/16, subnet javni-a sa jednim veb serverom i privatni subnet app-a bez instanci.

Korak 6 – Priprema naloga: bezbednost i budžet

  1. Prijavite se na AWS konzolu. Ako koristite root nalog, prvo uključite MFA (IAM → Security credentials). Za svakodnevni rad je preporučen poseban korisnik sa administratorskim pravima i MFA.
  2. Billing and Cost Management → Budgets → Create budget → Use a template → Zero spend budget. Upišite svoju e-poštu. Dobićete poruku čim bilo šta počne da se naplaćuje.
  3. U gornjem desnom uglu konzole izaberite region Europe (Frankfurt) eu-central-1.

Korak 7 – CloudShell i fajl sa identifikatorima

Otvorite CloudShell (ikona terminala u gornjoj traci konzole). Promenljive u CloudShell-u nestaju ako sesija istekne, pa sve identifikatore upisujte u fajl koji ostaje sačuvan u kućnom folderu:

aws sts get-caller-identity
AZ=$(aws ec2 describe-availability-zones --query 'AvailabilityZones[0].ZoneName' --output text)
echo "AZ=$AZ" > ~/kurs25.env
cat ~/kurs25.env

Ako se sesija prekine, promenljive vraćate sa source ~/kurs25.env.

Korak 8 – VPC i subneti

VPC_ID=$(aws ec2 create-vpc --cidr-block 10.30.0.0/16 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=kurs25-vpc},{Key=projekat,Value=kurs25}]' \
  --query Vpc.VpcId --output text)
echo "VPC_ID=$VPC_ID" >> ~/kurs25.env

PUB_ID=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.30.0.0/26 --availability-zone $AZ \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=kurs25-javni-a},{Key=projekat,Value=kurs25}]' \
  --query Subnet.SubnetId --output text)
echo "PUB_ID=$PUB_ID" >> ~/kurs25.env

PRIV_ID=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.30.1.0/24 --availability-zone $AZ \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=kurs25-app-a},{Key=projekat,Value=kurs25}]' \
  --query Subnet.SubnetId --output text)
echo "PRIV_ID=$PRIV_ID" >> ~/kurs25.env

aws ec2 describe-subnets --subnet-ids $PUB_ID $PRIV_ID \
  --query 'Subnets[].[Tags[?Key==`Name`]|[0].Value,CidrBlock,AvailableIpAddressCount]' --output table

Uporedite kolonu sa brojem dostupnih adresa sa svojim računom iz Dela 1 (64 − 5 i 256 − 5).

Korak 9 – Internet gateway i tabela ruta javnog subneta

IGW_ID=$(aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=kurs25-igw},{Key=projekat,Value=kurs25}]' \
  --query InternetGateway.InternetGatewayId --output text)
echo "IGW_ID=$IGW_ID" >> ~/kurs25.env
aws ec2 attach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID

RT_ID=$(aws ec2 create-route-table --vpc-id $VPC_ID \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=kurs25-rt-javni},{Key=projekat,Value=kurs25}]' \
  --query RouteTable.RouteTableId --output text)
echo "RT_ID=$RT_ID" >> ~/kurs25.env
aws ec2 create-route --route-table-id $RT_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID
aws ec2 associate-route-table --route-table-id $RT_ID --subnet-id $PUB_ID
aws ec2 modify-subnet-attribute --subnet-id $PUB_ID --map-public-ip-on-launch

Uporedite tabelu ruta javnog subneta sa main tabelom, koju koristi privatni subnet:

aws ec2 describe-route-tables --route-table-ids $RT_ID --query 'RouteTables[0].Routes' --output table
aws ec2 describe-route-tables --filters Name=vpc-id,Values=$VPC_ID Name=association.main,Values=true \
  --query 'RouteTables[0].Routes' --output table

Korak 10 – Security group za veb server

SG_ID=$(aws ec2 create-security-group --group-name kurs25-web-sg \
  --description "Samo HTTP za laboratoriju" --vpc-id $VPC_ID --query GroupId --output text)
echo "SG_ID=$SG_ID" >> ~/kurs25.env
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 80 --cidr 0.0.0.0/0

SSH port namerno nije otvoren — za ovu vežbu nije potreban.

Korak 11 – Veb server u javnom subnetu

Skripta koju instanca izvršava pri prvom pokretanju (user data):

cat > ~/web.sh << 'EOF'
#!/bin/bash
dnf install -y nginx
echo "<h1>Modul 25 - veb server u javnom subnetu</h1>" > /usr/share/nginx/html/index.html
systemctl enable --now nginx
EOF

Najnoviji Amazon Linux 2023 image i pokretanje instance:

AMI_ID=$(aws ssm get-parameters --names /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 \
  --query 'Parameters[0].Value' --output text)

INST_ID=$(aws ec2 run-instances --image-id $AMI_ID --instance-type t3.micro \
  --subnet-id $PUB_ID --security-group-ids $SG_ID --user-data file://$HOME/web.sh \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=kurs25-web},{Key=projekat,Value=kurs25}]' \
  --query 'Instances[0].InstanceId' --output text)
echo "INST_ID=$INST_ID" >> ~/kurs25.env

aws ec2 wait instance-running --instance-ids $INST_ID
WEB_IP=$(aws ec2 describe-instances --instance-ids $INST_ID \
  --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)
echo "WEB_IP=$WEB_IP" >> ~/kurs25.env
echo $WEB_IP

Ako t3.micro nije označen kao Free tier eligible za vaš nalog ili region, upotrebite tip koji konzola u EC2 → Launch instance označava kao besplatan (npr. t2.micro).

Sačekajte 2–3 minuta da se nginx instalira, pa proverite iz CloudShell-a i iz svog pregledača (http://<WEB_IP>):

curl -m 5 http://$WEB_IP

Proverite i privatnu adresu instance: aws ec2 describe-instances --instance-ids $INST_ID --query 'Reservations[0].Instances[0].PrivateIpAddress' --output text. U kom je opsegu? Da li instanca „zna" za svoju javnu adresu (Tema 7)?

Korak 12 – Network ACL za javni subnet

Napravite NACL sa pravilima iz Teme 10 i pridružite je javnom subnetu:

NACL_ID=$(aws ec2 create-network-acl --vpc-id $VPC_ID \
  --tag-specifications 'ResourceType=network-acl,Tags=[{Key=Name,Value=kurs25-nacl-javni},{Key=projekat,Value=kurs25}]' \
  --query NetworkAcl.NetworkAclId --output text)
echo "NACL_ID=$NACL_ID" >> ~/kurs25.env

aws ec2 create-network-acl-entry --network-acl-id $NACL_ID --ingress --rule-number 100 \
  --protocol tcp --port-range From=80,To=80 --cidr-block 0.0.0.0/0 --rule-action allow
aws ec2 create-network-acl-entry --network-acl-id $NACL_ID --ingress --rule-number 110 \
  --protocol tcp --port-range From=1024,To=65535 --cidr-block 0.0.0.0/0 --rule-action allow
aws ec2 create-network-acl-entry --network-acl-id $NACL_ID --egress --rule-number 100 \
  --protocol tcp --port-range From=1024,To=65535 --cidr-block 0.0.0.0/0 --rule-action allow
aws ec2 create-network-acl-entry --network-acl-id $NACL_ID --egress --rule-number 110 \
  --protocol tcp --port-range From=80,To=80 --cidr-block 0.0.0.0/0 --rule-action allow
aws ec2 create-network-acl-entry --network-acl-id $NACL_ID --egress --rule-number 120 \
  --protocol tcp --port-range From=443,To=443 --cidr-block 0.0.0.0/0 --rule-action allow

ASSOC_ID=$(aws ec2 describe-network-acls --filters Name=association.subnet-id,Values=$PUB_ID \
  --query "NetworkAcls[0].Associations[?SubnetId=='$PUB_ID'].NetworkAclAssociationId" --output text)
aws ec2 replace-network-acl-association --association-id $ASSOC_ID --network-acl-id $NACL_ID

aws ec2 describe-network-acls --network-acl-ids $NACL_ID --query 'NetworkAcls[0].Entries' --output table
curl -m 5 http://$WEB_IP

Sajt i dalje radi. U tabeli pravila pronađite i implicitna pravila * (broj 32767) koja odbijaju sve ostalo.

Korak 13 – Dijagnostička vežba: dva kvara

Kvar A. Izvršite:

aws ec2 delete-route --route-table-id $RT_ID --destination-cidr-block 0.0.0.0/0
curl -m 5 http://$WEB_IP

Sajt više ne odgovara. Bez gledanja u komandu koju ste upravo izvršili, pronađite uzrok proverom pet uslova iz Teme 7 — koristite describe-internet-gateways, describe-route-tables, describe-instances, describe-security-groups i describe-network-acls. Zatim ispravite kvar i potvrdite da sajt ponovo radi.

Kvar B. Izvršite:

aws ec2 delete-network-acl-entry --network-acl-id $NACL_ID --egress --rule-number 100
curl -m 5 http://$WEB_IP

Sajt ponovo ne odgovara, iako se security group nije menjala i iako dolazno NACL pravilo za port 80 i dalje postoji. Objasnite zašto, ispravite kvar i potvrdite da sajt radi.

Korak 14 – Brisanje svih resursa (obavezno)

Resurse brišite redosledom koji poštuje zavisnosti:

source ~/kurs25.env
aws ec2 terminate-instances --instance-ids $INST_ID
aws ec2 wait instance-terminated --instance-ids $INST_ID
aws ec2 delete-security-group --group-id $SG_ID
aws ec2 delete-subnet --subnet-id $PUB_ID
aws ec2 delete-subnet --subnet-id $PRIV_ID
aws ec2 delete-network-acl --network-acl-id $NACL_ID
aws ec2 detach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID
aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID
aws ec2 delete-route-table --route-table-id $RT_ID
aws ec2 delete-vpc --vpc-id $VPC_ID

Provera da ništa nije ostalo:

aws ec2 describe-vpcs --filters Name=tag:projekat,Values=kurs25 --query 'Vpcs[].VpcId'
aws ec2 describe-instances --filters Name=tag:projekat,Values=kurs25 Name=instance-state-name,Values=running,stopped \
  --query 'Reservations[].Instances[].InstanceId'

Oba odgovora treba da budu prazne liste ([]). Sutradan pogledajte Billing → Bills i proverite da nema neočekivanih stavki.

Komande za proveru

KomandaŠta proverava
python3 provera_vpc.pyAdresni plan: pripadnost VPC-u, preklapanja, upotrebljive adrese
aws ec2 describe-subnets --subnet-ids ...CIDR i broj dostupnih adresa subneta
aws ec2 describe-route-tables --route-table-ids ...Rute i pridruženi subneti
aws ec2 describe-internet-gateways --internet-gateway-ids ...Da li je IGW pridružen VPC-u
aws ec2 describe-security-groups --group-ids ...Pravila security group-e
aws ec2 describe-network-acls --network-acl-ids ...NACL pravila i pridruženi subneti
aws ec2 describe-instances --instance-ids ...Stanje instance, privatna i javna adresa
curl -m 5 http://<adresa>Dostupnost veb servera, sa ograničenjem od 5 sekundi

Najčešće greške

  • AZ, VPC_ID i ostale promenljive su prazne jer je CloudShell sesija istekla — izvršite source ~/kurs25.env.
  • Nije izabran region eu-central-1, pa se resursi prave (i traže) u drugom regionu.
  • Instanca nema javnu IP adresu jer map-public-ip-on-launch nije uključen pre pokretanja instance.
  • curl odmah posle pokretanja ne radi — nginx se još instalira (sačekajte 2–3 minuta).
  • Brisanje subneta ili security group-e ne uspeva jer instanca još nije potpuno ugašena — sačekajte wait instance-terminated.
  • Zaboravljeno brisanje resursa na kraju.

Postupak rešavanja problema

  1. Region i identifikatori: aws configure get region, cat ~/kurs25.env.
  2. Put ka internetu: IGW pridružen VPC-u, a tabela ruta subneta ima 0.0.0.0/0 → IGW.
  3. Adresa: instanca ima javnu IP adresu i u stanju je running.
  4. Pravila: security group (dolazno), NACL (dolazno i odlazno, uključujući efemerne portove).
  5. Servis: da li je nginx instaliran i pokrenut (EC2 → instanca → Actions → Monitor and troubleshoot → Get system log).

Završna provera

  • [ ] Deo 1: adresni plan popunjen, skripta prijavljuje „Plan je ispravan." i hvata sve tri namerne greške.
  • [ ] Deo 1: napisane su tabele ruta, security group-e, NACL za bazu i dijagram.
  • [ ] Deo 2: veb server je bio dostupan sa interneta preko javne adrese.
  • [ ] Deo 2: oba kvara iz Koraka 13 su dijagnostikovana i ispravljena.
  • [ ] Deo 2: svi resursi su obrisani i provera vraća prazne liste.

Dodatni izazov

  1. NAT gateway za privatni subnet (naplaćuje se po satu — ceo izazov uradite u jednom navratu, za manje od sat vremena, i odmah obrišite): pre Koraka 14 napravite Elastic IP adresu i NAT gateway u javnom subnetu, posebnu tabelu ruta za privatni subnet sa rutom 0.0.0.0/0 → NAT gateway, a zatim obrišite NAT gateway i oslobodite Elastic IP adresu. Napišite komande i redosled.
  2. Isti plan u Azure-u: prevedite plan iz Dela 1 u Azure pojmove (VNet, subneti, NSG, NAT Gateway, Application Gateway, VPN Gateway). Navedite jednu razliku u ponašanju koja utiče na plan.

Rešenje

Kompletno rešenje dostupno je u /resenja/modul-25/04-laboratorijska-vezba-resenje.md.

📖 Prikaži rešenje

Rešenje laboratorijske vežbe – Modul 25

DEO 1 – Projektovanje

Korak 1 – Opseg VPC-a

10.30.0.0/16 — pripada opsegu 10.0.0.0/8, ne preklapa se ni sa centralom (172.16.0.0/16) ni sa poslovnicama (192.168.0.0/16), i ostavlja prostor za druge VPC-ove (npr. testni 10.31.0.0/16). Prihvata se svaki /16 iz 10.0.0.0/8 koji se ni sa čim ne preklapa.

Korak 2 – Adresni plan (VLSM)

SubnetZonaPotrebnoPrefiksCIDRUpotrebljivo (−5)
javni-aa50/2610.30.0.0/2659
javni-bb50/2610.30.0.64/2659
app-aa200/2410.30.1.0/24251
app-bb200/2410.30.2.0/24251
baza-aa20/2710.30.3.0/2727
baza-bb20/2710.30.3.32/2727

Obrazloženje najmanjih prefiksa: za 50 adresa /27 nije dovoljan (32 − 5 = 27), pa je potreban /26 (59). Za 200 adresa /25 nije dovoljan (128 − 5 = 123), pa je potreban /24 (251). Za 20 adresa /28 nije dovoljan (16 − 5 = 11), pa je potreban /27 (27). Prostor 10.30.0.128/25 i 10.30.3.64 i dalje ostaje slobodan za rast.

Korak 3 – Izlaz skripte za ovaj plan

Subnet     CIDR             Upotrebljivo
javni-a    10.30.0.0/26               59
javni-b    10.30.0.64/26              59
app-a      10.30.1.0/24              251
app-b      10.30.2.0/24              251
baza-a     10.30.3.0/27               27
baza-b     10.30.3.32/27              27

Plan je ispravan.

Provera namernih grešaka:

IzmenaPoruka skripte
"app-b": "10.30.1.128/25"GREŠKA: app-a (10.30.1.0/24) se preklapa sa app-b (10.30.1.128/25)
"baza-a": "10.30.3.8/27"GREŠKA: baza-a — neispravan CIDR (10.30.3.8/27 has host bits set)
VPC = "172.16.0.0/12"GREŠKA: VPC 172.16.0.0/12 se preklapa sa mrežom centrala (172.16.0.0/16), plus po jedna greška za svaki subnet koji više nije unutar VPC-a (ukupno 7)

Korak 4 – Tabele ruta

rt-javni — pridružena javni-a i javni-b:

OdredišteCilj
10.30.0.0/16local
0.0.0.0/0igw

rt-app-a — pridružena app-a:

OdredišteCilj
10.30.0.0/16local
172.16.0.0/16vgw
192.168.0.0/16vgw
0.0.0.0/0nat-a

rt-app-b — pridružena app-b: isto kao rt-app-a, ali 0.0.0.0/0 → nat-b (NAT gateway u sopstvenoj zoni).

rt-baza — pridružena baza-a i baza-b:

OdredišteCilj
10.30.0.0/16local
172.16.0.0/16vgw

Baza nema rutu 0.0.0.0/0, pa nema izlaz na internet. Ruta ka centrali postoji zbog administratorske mreže 172.16.50.0/24 (može i uže: 172.16.50.0/24 → vgw). Main tabela VPC-a ostaje samo sa rutom local. Rute ka vgw mogu biti i propagirane sa VPN gateway-a (BGP), umesto statičkih.

Korak 5 – Security group-e i NACL

Security group-e:

SGProtokol/portIzvor
sg-lbTCP 4430.0.0.0/0
sg-appTCP 8080sg-lb
sg-appTCP 22172.16.50.0/24
sg-bazaTCP 5432sg-app
sg-bazaTCP 5432172.16.50.0/24 (administracija baze iz centrale)

(Poslednje pravilo je prihvatljivo i bez njega, ako administratori baze pristupaju preko aplikacionog servera. SSH ka bazi nije potreban ako je baza upravljana usluga.)

NACL za subnete baze:

SmerBr.ProtokolPortoviIzvor/odredišteAkcija
Dolazno100TCP543210.30.1.0/24Dozvoli
Dolazno110TCP543210.30.2.0/24Dozvoli
Dolazno120TCP5432172.16.50.0/24Dozvoli
Dolazno*SveSve0.0.0.0/0Odbij
Odlazno100TCP1024–6553510.30.1.0/24Dozvoli
Odlazno110TCP1024–6553510.30.2.0/24Dozvoli
Odlazno120TCP1024–65535172.16.50.0/24Dozvoli
Odlazno*SveSve0.0.0.0/0Odbij

Ako se baza replicira između zona, dodaju se i pravila za saobraćaj između 10.30.3.0/27 i 10.30.3.32/27.

Dijagram (Mermaid):

graph TB
    INET["Internet"] --> IGW["IGW"]
    subgraph VPC["VPC 10.30.0.0/16 (eu-central-1)"]
        subgraph A["Zona a"]
            JA["javni-a 10.30.0.0/26<br/>LB, NAT-a"]
            AA["app-a 10.30.1.0/24"]
            BA["baza-a 10.30.3.0/27"]
        end
        subgraph B["Zona b"]
            JB["javni-b 10.30.0.64/26<br/>LB, NAT-b"]
            AB["app-b 10.30.2.0/24"]
            BB["baza-b 10.30.3.32/27"]
        end
    end
    IGW --> JA
    IGW --> JB
    JA --> AA --> BA
    JB --> AB --> BB
    VGW["VPN gateway"] --- AA
    VGW --- AB
    VGW --- BA
    CEN["Centrala 172.16.0.0/16<br/>Poslovnice 192.168.0.0/16"] --- VGW

DEO 2 – AWS

Korak 8 – Očekivani izlaz describe-subnets

-------------------------------------------------
|                DescribeSubnets                |
+-----------------+----------------+------------+
|  kurs25-javni-a |  10.30.0.0/26  |  59        |
|  kurs25-app-a   |  10.30.1.0/24  |  251       |
+-----------------+----------------+------------+

Broj dostupnih adresa se poklapa sa računom iz Dela 1 (64 − 5 i 256 − 5).

Korak 9 – Tabele ruta

rt-javni ima dve rute: 10.30.0.0/16 → local i 0.0.0.0/0 → igw-.... Main tabela, koju koristi privatni subnet app-a, ima samo local — zato je app-a privatni.

Korak 11 – Veb server

curl vraća <h1>Modul 25 - veb server u javnom subnetu</h1>, a isti sadržaj se vidi u pregledaču. Privatna adresa instance je iz opsega 10.30.0.0/26 (npr. 10.30.0.37). Instanca „ne zna" za svoju javnu adresu — u operativnom sistemu (ip addr) postoji samo privatna, jer internet gateway radi statički 1:1 NAT (Tema 7).

Korak 12 – NACL

Sajt i dalje radi, jer NACL dozvoljava dolazni TCP 80 i odlazne odgovore ka efemernim portovima. U tabeli pravila postoje i implicitna pravila broj 32767 sa akcijom deny za oba smera.

Korak 13 – Dijagnostika

Kvar A — obrisana podrazumevana ruta.

ProveraRezultat
describe-internet-gatewaysIGW je pridružen VPC-u (available)
describe-route-tables --route-table-ids $RT_IDPostoji samo local; nema 0.0.0.0/0 → igw
describe-instancesInstanca running, ima javnu IP adresu
describe-security-groupsTCP 80 iz 0.0.0.0/0 dozvoljen
describe-network-aclsPravila nepromenjena

Uzrok: subnet nema rutu ka internetu. Paketi od klijenta stižu do instance, ali odgovori nemaju kuda da se vrate, pa curl ističe posle 5 sekundi. Ispravka:

aws ec2 create-route --route-table-id $RT_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID

Kvar B — obrisano odlazno NACL pravilo 100.

Dolazni zahtev na port 80 prolazi (dolazno pravilo 100), a security group je stateful i dozvoljava odgovor. Ali NACL je stateless: odgovor servera ide sa porta 80 ka efemernom portu klijenta (npr. 51734). Posle brisanja pravila 100 nijedno odlazno pravilo ne dozvoljava TCP ka portovima 1024–65535 (pravila 110 i 120 dozvoljavaju samo odredišne portove 80 i 443), pa implicitno pravilo * odbacuje odgovor. Ispravka:

aws ec2 create-network-acl-entry --network-acl-id $NACL_ID --egress --rule-number 100 \
  --protocol tcp --port-range From=1024,To=65535 --cidr-block 0.0.0.0/0 --rule-action allow

Pouka: simptom je u oba slučaja isti (istek vremena), ali je uzrok na različitom mestu. Sistematska provera pet uslova (Tema 7) i razumevanje stateful naspram stateless filtriranja (Modul 16) vode do uzroka bez nagađanja.

Korak 14 – Brisanje

Obe provere vraćaju []. Ako delete-security-group ili delete-subnet prijave DependencyViolation, mrežni interfejs instance još nije uklonjen — sačekajte nekoliko sekundi i ponovite komandu.


Rešenje dodatnog izazova

1. NAT gateway za privatni subnet

Izvršava se pre Koraka 14, u jednom navratu:

EIP_ALLOC=$(aws ec2 allocate-address --domain vpc --query AllocationId --output text)
NAT_ID=$(aws ec2 create-nat-gateway --subnet-id $PUB_ID --allocation-id $EIP_ALLOC \
  --query NatGateway.NatGatewayId --output text)
aws ec2 wait nat-gateway-available --nat-gateway-ids $NAT_ID

PRIV_RT_ID=$(aws ec2 create-route-table --vpc-id $VPC_ID --query RouteTable.RouteTableId --output text)
aws ec2 create-route --route-table-id $PRIV_RT_ID --destination-cidr-block 0.0.0.0/0 --nat-gateway-id $NAT_ID
aws ec2 associate-route-table --route-table-id $PRIV_RT_ID --subnet-id $PRIV_ID
aws ec2 describe-route-tables --route-table-ids $PRIV_RT_ID --query 'RouteTables[0].Routes' --output table

Brisanje, odmah posle provere:

aws ec2 delete-nat-gateway --nat-gateway-id $NAT_ID
aws ec2 wait nat-gateway-deleted --nat-gateway-ids $NAT_ID
aws ec2 release-address --allocation-id $EIP_ALLOC

Zatim Korak 14 kao i inače, uz dodatnu komandu posle brisanja subneta:

aws ec2 delete-route-table --route-table-id $PRIV_RT_ID

Redosled i razlozi:

  1. NAT gateway se pravi u javnom subnetu, jer mu je potreban put ka IGW-u.
  2. Privatni subnet dobija sopstvenu tabelu ruta; main tabela se ne menja.
  3. Elastic IP se oslobađa tek kada je NAT gateway obrisan, jer je adresa za njega vezana. Zauzeta, a neiskorišćena Elastic IP adresa se takođe naplaćuje.

Napomena o NACL-u: saobraćaj privatnih instanci ka NAT gateway-u ulazi u javni subnet. Uz NACL iz Koraka 12, dolazni HTTPS iz 10.30.1.0/24 bio bi odbijen. Da bi privatne instance preuzimale ažuriranja preko HTTPS-a, dodaje se dolazno pravilo, npr. br. 120: TCP 443 iz 10.30.1.0/24. Uz to, već postojeća pravila moraju pokrivati i odgovore u oba smera.

2. Plan u Azure-u

AWS (Deo 1)Azure
VPC 10.30.0.0/16Virtual Network (VNet) 10.30.0.0/16
Subneti javni/app/bazaSubneti (npr. snet-javni, snet-app, snet-baza)
Tabele rutaRoute table (UDR) pridružene subnetima
Security group-eNetwork Security Group (NSG) na NIC-ovima ili subnetima; umesto referenci na SG koriste se Application Security Groups
NACL za bazuNSG pridružena subnetu baze (stateful)
NAT gateway po zoniAzure NAT Gateway (zonski) pridružen subnetima
Application Load BalancerApplication Gateway (L7)
Virtual private gatewayVPN Gateway (aktivno-aktivni, sa BGP-om)

Razlika koja utiče na plan: Azure subneti su regionalni i obuhvataju sve zone. Za dve zone zato nisu potrebni posebni subneti po zoni — dovoljni su javni, aplikacioni i subnet baze, a zone se biraju na nivou resursa (VM, NAT Gateway, Application Gateway). Druga razlika: Azure NSG je stateful, pa se NACL pravila za efemerne portove ne prenose.