ЁЯПл The SchoolтА║ЁЯЦея╕П EC2тА║ЁЯзН рдзрдбрд╛ 05 тАФ Networking тАФ security groups рдЖрдгрд┐ NACLs: рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА рдЖрдгрд┐ рд╡рд┐рдВрдЧрдЪреЗ рджрд╛рд░
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯзН рдзрдбрд╛ 05 тАФ Networking тАФ security groups рдЖрдгрд┐ NACLs: рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА рдЖрдгрд┐ рд╡рд┐рдВрдЧрдЪреЗ рджрд╛рд░

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 05 ┬╖ рдорд╛рдЧреЗ: lesson-04-storage ┬╖ рдкреБрдвреЗ: lesson-06-connecting


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ04, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ packet рд▓рд╛ рднреЗрдЯрдгрд╛рд▒реНрдпрд╛ рджреЛрди firewalls: security group (рдбреЗрд╕реНрдХрд╡рд░рдЪреА рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА тАФ stateful) рдЖрдгрд┐ network ACL (рд╡рд┐рдВрдЧрдЪреНрдпрд╛ рджрд╛рд░рд╛рд╡рд░рдЪреЗ рдирд┐рдпрдо тАФ stateless), рджреЛрдиреНрд╣реА ec2/sg.py рдордзреНрдпреЗ code рдореНрд╣рдгреВрди, рдЬреНрдпрд╛рддреВрди рддреБрдореНрд╣реА packets рдкрд╛рдард╡реВрди рдкрд╛рд╣реВ рд╢рдХрддрд╛.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдбреЗрд╕реНрдХ рдЗрдорд╛рд░рддреАрдЪреНрдпрд╛ рдПрдХрд╛ рд╡рд┐рдВрдЧ рдордзреНрдпреЗ рдмрд╕рд▓реЗрд▓реЗ рдЕрд╕рддрд╛рдд (рдПрдХ subnet), рд╢рд╛рд│реЗрдЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рдЖрд╡рд╛рд░рд╛рдд (VPC).

рд╡рд┐рдВрдЧрдЪреНрдпрд╛ рджрд╛рд░рд╛рд╡рд░ ЁЯЪк рдПрдХ рдирд┐рдпрдо-рдлрд▓рдХ рдЕрд╕рддреЛ (network ACL). рддреЛ рдЖрдд рдпреЗрдгрд╛рд▒реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддреАрд▓рд╛ рдЖрдгрд┐ рдмрд╛рд╣реЗрд░ рдЬрд╛рдгрд╛рд▒реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддреАрд▓рд╛рд╣реА рддрдкрд╛рд╕рддреЛ, рд╡рд░реВрди рдирд┐рдпрдо рд╡рд╛рдЪрдд тАФ rule 90, rule 100, rule 110 тАФ рдЖрдгрд┐ рдЬреБрд│рдгрд╛рд░рд╛ рдкрд╣рд┐рд▓рд╛ рдирд┐рдпрдо рдирд┐рд░реНрдгрдп рдШреЗрддреЛ. рддреНрдпрд╛рдЪреА рд╕реНрдорд░рдгрд╢рдХреНрддреА рдЕрдЧрджреА рд╡рд╛рдИрдЯ рдЖрд╣реЗ: рдПрдЦрд╛рджрд╛ рдкрд╛рд╣реБрдгрд╛ рдорд┐рдирд┐рдЯрд╛рдкреВрд░реНрд╡реА рдЖрдд рдЖрд▓рд╛ рдЖрдгрд┐ рддреНрдпрд╛рдЪреЗ рдЙрддреНрддрд░ рдмрд╛рд╣реЗрд░ рдЬрд╛рдпрд▓рд╛ рдирд┐рдШрд╛рд▓реЗ, рддрд░ рдлрд▓рдХ рддреНрдпрд╛ рдЙрддреНрддрд░рд╛рд▓рд╛ рдЕрдиреЛрд│рдЦреА рдореНрд╣рдгреВрди рддрдкрд╛рд╕рддреЛ. рддреНрдпрд╛рд╕рд╛рдареА рдирд┐рдпрдо рдирд╛рд╣реА? рдЕрдбрд╡рд▓реЗ.

рдкреНрд░рддреНрдпреЗрдХ рдбреЗрд╕реНрдХрд╡рд░ рдПрдХ monitor рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА ЁЯзН рдШреЗрдКрди рдЙрднреА рдЕрд╕рддреЗ (security group). рдпрд╛рджреАрдд рдлрдХреНрдд рдХреЛрдг рдЖрдд рдпреЗрдК рд╢рдХрддреЗ рддреЗрдЪ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЕрд╕рддреЗ тАФ "443 рд╡рд░рдЪреНрдпрд╛ web page рд╕рд╛рдареА рдХреЛрдгреАрд╣реА", "22 рд╕рд╛рдареА office рдЪрд╛ laptop". рддрд┐рдЪреА рд╕реНрдорд░рдгрд╢рдХреНрддреА рдкрд░рд┐рдкреВрд░реНрдг рдЖрд╣реЗ: рддрд┐рдиреЗ рдкрд╛рд╣реБрдгреНрдпрд╛рд▓рд╛ рдЖрдд рдпреЗрдК рджрд┐рд▓реЗ рдЕрд╕реЗрд▓, рддрд░ рдЙрддреНрддрд░ рдХреЛрдгрддрд╛рд╣реА рдкреНрд░рд╢реНрди рди рд╡рд┐рдЪрд╛рд░рддрд╛ рдмрд╛рд╣реЗрд░ рдЬрд╛рддреЗ. рдЖрдгрд┐ рддреА рдХрдзреАрдЪ "рдЪрд╛рд▓рддреЗ рд╡реНрд╣рд╛" рдЕрд╕реЗ рдУрд░рдбрдд рдирд╛рд╣реА тАФ рдЕрдиреЛрд│рдЦреА рд╡реНрдпрдХреНрддреАрдХрдбреЗ рд╕рд░рд│ рджреБрд░реНрд▓рдХреНрд╖ рдХреЗрд▓реЗ рдЬрд╛рддреЗ, рдЖрдгрд┐ рддреА рдХрдВрдЯрд╛рд│реВрди рдирд┐рдШреВрди рдЬрд╛рдИрдкрд░реНрдпрдВрдд рдерд╛рдВрдмрддреЗ (timeout).

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    visitor["ЁЯМН 198.51.100.9:51000"]
    nacl["ЁЯЪк NACL on the subnet тАФ stateless<br/>100 ALLOW 443 ┬╖ 200 DENY 22 ┬╖ * DENY"]
    sg["ЁЯзН security group on the desk тАФ stateful<br/>443 from anywhere ┬╖ 22 from 203.0.113.5/32"]
    desk["ЁЯЦея╕П web desk :443"]
    visitor -->|"1 in :443"| nacl -->|"2"| sg -->|"3"| desk
    desk -->|"4 reply to :51000"| sg
    sg -->|"5 remembered тЖТ allowed"| nacl
    back["NACL outbound needs 1024тАУ65535<br/>without it тЖТ * DENY тЖТ the page hangs"]
    nacl -.->|"6"| back

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l05

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг network рд╣реЗ рдкреНрд░рддреНрдпреЗрдХ рдбреЗрд╕реНрдХрдЪреЗ рдкреБрдврдЪреЗ рджрд╛рд░ рдЖрд╣реЗ, рдЖрдгрд┐ EC2 рдордзрд▓реНрдпрд╛ рдмрд╣реБрддреЗрдХ рдШреБрд╕рдЦреЛрд▒реНрдпрд╛ "port 22 from 0.0.0.0/0" рд╕рд╛рд░рдЦреНрдпрд╛ рдирд┐рдпрдорд╛рдиреЗ рд╕реБрд░реВ рд╣реЛрддрд╛рдд. рдЖрдгрд┐ рдХрд╛рд░рдг рд╣реЗ рджреЛрди рд╕реНрддрд░ рдЙрд▓рдЯ рдкрджреНрдзрддреАрдиреЗ рдЕрдкрдпрд╢реА рдард░рддрд╛рдд: SGs рдмрд░реЛрдмрд░ рдХрд░рд╛рдпрд▓рд╛ рд╕реЛрдкреЗ рдЖрдгрд┐ рдЦреВрдк рдЙрдШрдбреЗ рдареЗрд╡рд╛рдпрд▓рд╛рд╣реА рд╕реЛрдкреЗ; NACLs рд╡рд┐рд╕рд░рд╛рдпрд▓рд╛ рд╕реЛрдкреЗ, рдЖрдгрд┐ reply рдЪрд╛ рдирд┐рдпрдо рдирд╕рд▓реНрдпрд╛рдиреЗ pages рдХреБрдареЗрд╣реА error рди рджрд╛рдЦрд╡рддрд╛ рдЕрдбрдХрддрд╛рдд.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

ec2/sg.py рдордзреНрдпреЗ SecurityGroup (receive() рд╕рд╣, рдЬреЗ рд╕рдВрднрд╛рд╖рдг рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рддреЗ, рдЖрдгрд┐ reply()) рдЖрдгрд┐ NetworkACL (рдХреНрд░рдорд╛рдВрдХрд╛рдиреБрд╕рд╛рд░ рд▓рд╛рд╡рд▓реЗрд▓реЗ рдирд┐рдпрдо, рдкрд╣рд┐рд▓рд╛ рдЬреБрд│рдгрд╛рд░рд╛ рдЬрд┐рдВрдХрддреЛ, рдордЧ рд╢реЗрд╡рдЯрдЪрд╛ deny) рдЖрд╣реЗрдд. ec2/demo.py рдордзрд▓реЗ network() web рдбреЗрд╕реНрдХрдЪреНрдпрд╛ SG рдХрдбреЗ рддреАрди рдкрд╛рд╣реБрдгреЗ рдкрд╛рдард╡рддреЗ, рдПрдХ reply рдмрд╛рд╣реЗрд░ рдЬрд╛рдК рджреЗрддреЗ, рдордЧ рддреАрдЪ request ephemeral-port рдирд┐рдпрдорд╛рд╕рд╣ рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп NACL рдордзреВрди рдЪрд╛рд▓рд╡рддреЗ. ec2/test_ec2.py рдордзрд▓реЗ tests L05 рд╣реЗ рддрд┐рдиреНрд╣реА рд╡рд░реНрддрди рдкрдХреНрдХреЗ рдХрд░рддрд╛рдд. рд╣реЗ рд╢рд┐рдХрд╡рдгреНрдпрд╛рд╕рд╛рдареАрдЪреЗ model рдЖрд╣реЗ: рдЦрд░реЗ SGs рдЖрдгрд┐ NACLs ICMP рд╕рд╛рд░рдЦреЗ protocols, IPv6 ranges рдЖрдгрд┐ prefix lists рд╕реБрджреНрдзрд╛ рдЬреБрд│рд╡рддрд╛рдд.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 ec2/demo.py network
python3 - <<'EOF'
import sys; sys.path.insert(0, "ec2")
from sg import SecurityGroup, NetworkACL
# the web desk only takes port 80, and only from inside the VPC (where the load balancer lives)
web = SecurityGroup("sg-web", [("tcp", (80, 80), "10.0.0.0/16", "80 from the VPC")])
for src in ("10.0.1.25", "198.51.100.9"):
    print(web.receive("tcp", src, 40000, 80))
# NACL rules are checked lowest number first тАФ a DENY at 90 beats the ALLOW at 100
acl = NetworkACL("acl-public",
    [(90, "deny", "all", (0, 65535), "198.51.100.0/24"), (100, "allow", "tcp", (443, 443), "0.0.0.0/0")],
    [(100, "allow", "tcp", (1024, 65535), "0.0.0.0/0")])
for src in ("198.51.100.9", "192.0.2.44"):
    print(src, acl.inbound_ok("tcp", 443, src))
print("port 8080 from anyone:", acl.inbound_ok("tcp", 8080, "192.0.2.44"))
EOF

рдЦрд▒реНрдпрд╛ account рд╡рд░ (AWS credentials рд▓рд╛рдЧрддрд╛рдд; рддреБрдордЪреЗ рд╕реНрд╡рддрдГрдЪреЗ VPC, SG рдЖрдгрд┐ NACL IDs рд╡рд╛рдкрд░рд╛):

aws ec2 create-security-group --group-name school-web --description "web desks" --vpc-id vpc-0123456789abcdef0
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 --protocol tcp --port 443 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 --protocol tcp --port 80 --source-group sg-0fedcba9876543210
aws ec2 create-network-acl-entry --network-acl-id acl-0123456789abcdef0 --egress --rule-number 110 \
    --protocol tcp --port-range From=1024,To=65535 --cidr-block 0.0.0.0/0 --rule-action allow

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

SG рдЪрд╛ рднрд╛рдЧ рдЫрд╛рдкрддреЛ тЬЕ 198.51.100.9 тЖТ :443, ЁЯЪл 198.51.100.9 тЖТ :22 тАж no inbound rule matches тАФ dropped (the sender sees a timeout), тЬЕ 203.0.113.5 тЖТ :22 (office рдЪрд╛ laptop), рдЖрдгрд┐ тЬЕ reply 443 тЖТ 198.51.100.9:51000 sg-web: reply to a remembered conversation тАФ stateful, no rule needed. NACL рдЪрд╛ рднрд╛рдЧ: without an ephemeral-port rule тЖТ request рдЖрдд тЬЕ, reply рдмрд╛рд╣реЗрд░ ЁЯЪл (acl-public outbound: no rule matches тЖТ the final * DENY); with 1024тАУ65535 out тЖТ reply рдмрд╛рд╣реЗрд░ тЬЕ (acl-public outbound rule 110: ALLOW). рддреБрдордЪрд╛ snippet 10.0.1.25 рд╕рд╛рдареА (True, "sg-web: inbound rule '80 from the VPC'") рдЖрдгрд┐ рдмрд╛рд╣реЗрд░рдЪреНрдпрд╛ address рд╕рд╛рдареА drop рдЫрд╛рдкрддреЛ; рдордЧ 198.51.100.9 (False, 'acl-public inbound rule 90: DENY'), 192.0.2.44 (True, 'acl-public inbound rule 100: ALLOW') рдЖрдгрд┐, 8080 рд╕рд╛рдареА, the final * DENY.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рддреБрдореНрд╣реА рдкреНрд░рддреНрдпреЗрдХ packet рдЪреЗ рднрд╛рдХреАрдд рдХреЗрд▓реЗ: рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА рд╕рдВрднрд╛рд╖рдгреЗ рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рддреЗ рдЖрдгрд┐ рд╡рд┐рдВрдЧрдЪреЗ рджрд╛рд░ рдареЗрд╡рдд рдирд╛рд╣реА, NACL рдЪрд╛ рдирд┐рд░реНрдгрдп рдирд┐рдпрдорд╛рдВрдЪрд╛ рдХреНрд░рдо рдард░рд╡рддреЛ, рдЖрдгрд┐ рди рдЬреБрд│рд▓реЗрд▓реЗ рд╕рдЧрд│реЗ рд╢рд╛рдВрддрдкрдгреЗ drop рд╣реЛрддреЗ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: security reviews рдЖрдгрд┐ AWS Security Hub рдЬрдЧрд╛рд╕рд╛рдареА administrative ports рдЙрдШрдбреЗ рдЕрд╕рд▓реЗрд▓рд╛ рдХреЛрдгрддрд╛рд╣реА SG рджрд╛рдЦрд╡реВрди рджреЗрддрд╛рдд. рдард░рд▓реЗрд▓реА рд░рдЪрдирд╛: load balancer рдЪрд╛ SG internet рдХрдбреВрди 443 рдШреЗрддреЛ, рдбреЗрд╕реНрдХрдЪрд╛ SG рдлрдХреНрдд load balancer рдЪреНрдпрд╛ SG рдХрдбреВрди traffic рдШреЗрддреЛ, рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг subnet рд╕рд╛рдареА block рд▓рд╛рдЧрдд рдирд╕реЗрд▓ рддрд░ NACLs default рдЪреНрдпрд╛ рдЬрд╡рд│рдЪ рд░рд╛рд╣рддрд╛рдд.

тПня╕П рдкреБрдвреЗ

рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА рдард░рд▓реА. рдЖрддрд╛: рдХрд╛рд╣реА рджреБрд░реБрд╕реНрдд рдХрд░рд╛рдпрд▓рд╛ рддреБрдореНрд╣реА рдбреЗрд╕реНрдХрдкрд░реНрдпрдВрдд рдХрд╕реЗ рдкреЛрд╣реЛрдЪрддрд╛? рдПрдХ рдЪрд╛рд╡реА, рдПрдХрд╛ рдорд┐рдирд┐рдЯрд╛рдЪрд╛ рдкрд╛рд╕, рдХрд┐рдВрд╡рд╛ рджрд╛рд░рдЪ рдирд╛рд╣реА тАФ connecting.

git checkout lesson-06-connecting

ЁЯзН Lesson 05 тАФ Networking тАФ security groups & NACLs: the guest list and the wing door

ЁЯУН You are here: Lesson 05 of 12 ┬╖ Previous: lesson-04-storage ┬╖ Next: lesson-06-connecting


ЁЯУж What's in this branch

Lessons 01тАУ04, plus the two firewalls every packet meets: the security group (the guest list at the desk тАФ stateful) and the network ACL (the rules on the wing door тАФ stateless), both as code in ec2/sg.py that you can send packets through.

ЁЯзТ Explain like I'm 5

The desks sit in a wing of the building (a subnet), inside the school's own grounds (the VPC).

At the wing door ЁЯЪк stands a rule board (the network ACL). It checks every person walking in and every person walking out, reading the rules from the top тАФ rule 90, rule 100, rule 110 тАФ and the first rule that matches decides. It has a terrible memory: if a visitor walked in a minute ago, and their answer comes walking out, the board checks the answer as a stranger. No rule for it? Stopped.

At each desk stands a monitor with a guest list ЁЯзН (the security group). The list only says who may come in тАФ "anyone for the web page on 443", "the office laptop for 22". It has a perfect memory: if it let a visitor in, the reply goes back out, no questions asked. And it never shouts "go away" тАФ a stranger is simply ignored, and waits until they give up (a timeout).

ЁЯЧ║я╕П Diagram

flowchart LR
    visitor["ЁЯМН 198.51.100.9:51000"]
    nacl["ЁЯЪк NACL on the subnet тАФ stateless<br/>100 ALLOW 443 ┬╖ 200 DENY 22 ┬╖ * DENY"]
    sg["ЁЯзН security group on the desk тАФ stateful<br/>443 from anywhere ┬╖ 22 from 203.0.113.5/32"]
    desk["ЁЯЦея╕П web desk :443"]
    visitor -->|"1 in :443"| nacl -->|"2"| sg -->|"3"| desk
    desk -->|"4 reply to :51000"| sg
    sg -->|"5 remembered тЖТ allowed"| nacl
    back["NACL outbound needs 1024тАУ65535<br/>without it тЖТ * DENY тЖТ the page hangs"]
    nacl -.->|"6"| back

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l05

тЭУ What

ЁЯдФ Why

Because the network is the front door to every desk, and most EC2 break-ins start with a rule like "port 22 from 0.0.0.0/0". And because the two layers fail in opposite ways: SGs are easy to get right and easy to open too wide; NACLs are easy to forget, and a missing reply rule makes pages hang with no error anywhere.

ЁЯФз How (in this repo)

ec2/sg.py has SecurityGroup (with receive(), which remembers the conversation, and reply()) and NetworkACL (rules sorted by number, first match wins, then the final deny). network() in ec2/demo.py sends three visitors to a web desk's SG, lets one reply out, then runs the same request through a NACL with and without the ephemeral-port rule. Tests L05 in ec2/test_ec2.py pin all three behaviours. It is a teaching model: real SGs and NACLs also match protocols like ICMP, IPv6 ranges and prefix lists.

ЁЯзк Try it

python3 ec2/demo.py network
python3 - <<'EOF'
import sys; sys.path.insert(0, "ec2")
from sg import SecurityGroup, NetworkACL
# the web desk only takes port 80, and only from inside the VPC (where the load balancer lives)
web = SecurityGroup("sg-web", [("tcp", (80, 80), "10.0.0.0/16", "80 from the VPC")])
for src in ("10.0.1.25", "198.51.100.9"):
    print(web.receive("tcp", src, 40000, 80))
# NACL rules are checked lowest number first тАФ a DENY at 90 beats the ALLOW at 100
acl = NetworkACL("acl-public",
    [(90, "deny", "all", (0, 65535), "198.51.100.0/24"), (100, "allow", "tcp", (443, 443), "0.0.0.0/0")],
    [(100, "allow", "tcp", (1024, 65535), "0.0.0.0/0")])
for src in ("198.51.100.9", "192.0.2.44"):
    print(src, acl.inbound_ok("tcp", 443, src))
print("port 8080 from anyone:", acl.inbound_ok("tcp", 8080, "192.0.2.44"))
EOF

On a real account (needs AWS credentials; use your own VPC, SG and NACL IDs):

aws ec2 create-security-group --group-name school-web --description "web desks" --vpc-id vpc-0123456789abcdef0
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 --protocol tcp --port 443 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 --protocol tcp --port 80 --source-group sg-0fedcba9876543210
aws ec2 create-network-acl-entry --network-acl-id acl-0123456789abcdef0 --egress --rule-number 110 \
    --protocol tcp --port-range From=1024,To=65535 --cidr-block 0.0.0.0/0 --rule-action allow

тЬЕ Verify тАФ what you should see

The SG block prints тЬЕ 198.51.100.9 тЖТ :443, ЁЯЪл 198.51.100.9 тЖТ :22 тАж no inbound rule matches тАФ dropped (the sender sees a timeout), тЬЕ 203.0.113.5 тЖТ :22 (the office laptop), and тЬЕ reply 443 тЖТ 198.51.100.9:51000 sg-web: reply to a remembered conversation тАФ stateful, no rule needed. The NACL block: without an ephemeral-port rule тЖТ request in тЬЕ, reply out ЁЯЪл (acl-public outbound: no rule matches тЖТ the final * DENY); with 1024тАУ65535 out тЖТ reply out тЬЕ (acl-public outbound rule 110: ALLOW). Your snippet prints (True, "sg-web: inbound rule '80 from the VPC'") for 10.0.1.25 and a drop for the outside address; then 198.51.100.9 (False, 'acl-public inbound rule 90: DENY'), 192.0.2.44 (True, 'acl-public inbound rule 100: ALLOW') and, for 8080, the final * DENY.

ЁЯПБ What you just proved

You predicted every packet: the guest list remembers conversations and the wing door does not, rule order decides a NACL, and anything unmatched is silently dropped.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: security reviews and AWS Security Hub flag any SG with administrative ports open to the world. The standard shape: the load balancer's SG takes 443 from the internet, the desks' SG takes traffic only from the load balancer's SG, and NACLs stay close to default unless you need a subnet-wide block.

тПня╕П Next

The guest list is set. Now: how do you get to the desk to fix something? A key, a one-minute pass, or no door at all тАФ connecting.

git checkout lesson-06-connecting
тЖР PreviousstorageNext тЖТconnecting

This page is the lesson's README from the lesson-05-networking branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.