ЁЯПл The SchoolтА║ЁЯПл VPCтА║ЁЯкз рдзрдбрд╛ 04 тАФ Route tables: corridor рдЪреНрдпрд╛ рдкрд╛рдЯреНрдпрд╛
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯкз рдзрдбрд╛ 04 тАФ Route tables: corridor рдЪреНрдпрд╛ рдкрд╛рдЯреНрдпрд╛

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 04 ┬╖ рдорд╛рдЧреЗ: lesson-03-subnets-azs ┬╖ рдкреБрдвреЗ: lesson-05-igw-public


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

рдзрдбреЗ 01тАУ03, рдЖрдгрд┐ рдкрд╛рдЯреНрдпрд╛: vpc/network.py рдордзреАрд▓ RouteTable routes (destination тЖТ target) рдареЗрд╡рддреЛ, рдиреЗрд╣рдореА local route рдиреЗ рд╕реБрд░реВ рд╣реЛрддреЛ, рдЖрдгрд┐ lookup() рдЬреБрд│рдгрд╛рд▒реНрдпрд╛рдВрдкреИрдХреА рд╕рд░реНрд╡рд╛рдд рдиреЗрдордХрд╛ route рдирд┐рд╡рдбрддреЛ. vpc/demo.py рдордзреАрд▓ routes() рдПрдХрд╛ рдкрд╛рдЯреАрд╡рд░реВрди рдЪрд╛рд░ рдкрддреНрддреЗ рдкрд╛рдард╡реВрди рдкрд╛рд╣рддреЛ.

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

рдкреНрд░рддреНрдпреЗрдХ wing рдЪреНрдпрд╛ рджрд╛рд░рд╛рд╡рд░ рдПрдХ corridor рдЪреА рдкрд╛рдЯреА ЁЯкз рд▓рдЯрдХрд▓реЗрд▓реА рдЕрд╕рддреЗ. рддрд┐рдЪреНрдпрд╛рд╡рд░ рдЕрд╢рд╛ рдУрд│реА рдЕрд╕рддрд╛рдд:

10.20.96.15 рд╕рд╛рдареАрдЪреЗ рдкрддреНрд░ рджреЛрди рдУрд│реАрдВрд╢реА рдЬреБрд│рддреЗ: "10.20.x.x" рдЖрдгрд┐ "рдмрд╛рдХреА рд╕рдЧрд│реЗ". рдирд┐рдпрдо рд╕реЛрдкрд╛ рдЖрд╣реЗ: рд╕рд░реНрд╡рд╛рдд рдиреЗрдордХреА рдУрд│ рдЬрд┐рдВрдХрддреЗ. "10.20.x.x" рд╣реА "рдмрд╛рдХреА рд╕рдЧрд│реЗ" рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдиреЗрдордХреА рдЖрд╣реЗ, рдореНрд╣рдгреВрди рдкрддреНрд░ рдЖрддрдЪ рд░рд╛рд╣рддреЗ.

рдПрдХрд╣реА рдУрд│ рдЬреБрд│рд▓реА рдирд╛рд╣реА, рддрд░ рдкрддреНрд░ drop рд╣реЛрддреЗ. рдХреЛрдгреА рдУрд░рдбрдд рдирд╛рд╣реА. рддреЗ рдлрдХреНрдд рдХрдзреАрдЪ рдкреЛрд╣реЛрдЪрдд рдирд╛рд╣реА.

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

flowchart LR
    pkt["ЁЯУи packet to 52.219.40.10"]
    subgraph rt["ЁЯкз rt-private-a"]
        r1["10.20.0.0/16 тЖТ local"]
        r2["10.30.0.0/16 тЖТ pcx-partner"]
        r3["pl-s3 тЖТ vpce-s3"]
        r4["0.0.0.0/0 тЖТ nat-a"]
    end
    pkt --> rt
    rt -->|"most specific match wins"| win["тЖТ vpce-s3<br/>52.219.0.0/16 beats 0.0.0.0/0"]

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

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг "public", "private" рдЖрдгрд┐ "isolated" рд╣реА subnet рд╡рд░ рдЪрд┐рдХрдЯрд╡рд▓реЗрд▓реА рд▓реЗрдмрд▓реЗ рдирд╛рд╣реАрдд тАФ рддреА рддреНрдпрд╛рдЪреНрдпрд╛ рдкрд╛рдЯреАрд╡рд░ рдХрд╛рдп рд▓рд┐рд╣рд┐рд▓реЗ рдЖрд╣реЗ рддреНрдпрд╛рдЪрд╛ рдкрд░рд┐рдгрд╛рдо рдЖрд╣реЗрдд. Route table рд╡рд╛рдЪрд╛, рдЖрдгрд┐ wing рдХреБрдареЗ рдЬрд╛рдК рд╢рдХрддреЛ рддреЗ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд│рддреЗ.

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

RouteTable.__init__ рд╕рд░реНрд╡рд╛рдд рдЖрдзреА (vpc_cidr, "local") рдареЗрд╡рддреЛ. lookup(dst_ip, prefix_lists) рдкреНрд░рддреНрдпреЗрдХ route рддрдкрд╛рд╕рддреЛ; рдЕрдВрдХрд╛рдиреЗ рд╕реБрд░реВ рди рд╣реЛрдгрд╛рд░реЗ destination рд╣реЗ prefix-list рдЪреЗ рдирд╛рд╡ рдЕрд╕рддреЗ рдЖрдгрд┐ рддреЗ prefix_lists рдордзреВрди рд╡рд┐рд╕реНрддрд╛рд░рд▓реЗ рдЬрд╛рддреЗ. рддреЛ рд╕рд░реНрд╡рд╛рдд рдореЛрдард╛ prefixlen рдЕрд╕рд▓реЗрд▓рд╛ рдЬреБрд│рдгрд╛рд░рд╛ route рдареЗрд╡рддреЛ рдЖрдгрд┐ (destination, target), рдХрд┐рдВрд╡рд╛ (None, None) рдкрд░рдд рдХрд░рддреЛ. vpc/demo.py рдордзреАрд▓ routes() NAT, peering route рдЖрдгрд┐ S3 prefix list pl-s3 (рдЙрджрд╛рд╣рд░рдгрд╛рджрд╛рдЦрд▓ ranges 52.219.0.0/16 рдЖрдгрд┐ 3.5.0.0/16) рдЕрд╕рд▓реЗрд▓реА private wing рдЪреА рдкрд╛рдЯреА рдмрдирд╡рддреЛ.

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

python3 vpc/demo.py routes
python3 - <<'EOF'
import sys; sys.path.insert(0, "vpc"); from network import RouteTable
from demo import VPC, PL
rt = RouteTable("rt-app", VPC, [("0.0.0.0/0", "nat-a"), ("10.20.96.0/20", "firewall")])
for ip in ("10.20.96.15", "10.20.1.1", "93.184.216.34"):
    print(ip.ljust(14), rt.lookup(ip, PL))
bare = RouteTable("rt-empty", VPC)
print("no default route:", bare.lookup("93.184.216.34", PL))
EOF

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

routes рдЫрд╛рдкрддреЛ:

тФАтФА the corridor sign: the MOST SPECIFIC route that matches wins; 'local' is always there
   тЖТ 10.20.96.15    matches 10.20.0.0/16  тЖТ local
   тЖТ 10.30.4.7      matches 10.30.0.0/16  тЖТ pcx-partner
   тЖТ 52.219.40.10   matches pl-s3         тЖТ vpce-s3
   тЖТ 93.184.216.34  matches 0.0.0.0/0     тЖТ nat-a

рддреБрдордЪрд╛ snippet 10.20.96.15 ('10.20.96.0/20', 'firewall') рдЫрд╛рдкрддреЛ тАФ /20 рдиреЗ local рдЪреНрдпрд╛ /16 рд▓рд╛ рд╣рд░рд╡рд▓реЗ тАФ рдЖрдгрд┐ рдордЧ 10.20.1.1 ('10.20.0.0/16', 'local'), 93.184.216.34 ('0.0.0.0/0', 'nat-a') рдЖрдгрд┐ no default route: (None, None).

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

VPC router рд╡рд╛рдЪрддреЛ рддрд╕рд╛ рддреБрдореНрд╣реА route table рд╡рд╛рдЪреВ рд╢рдХрддрд╛: рдЬреБрд│рдгрд╛рд░реЗ рд╕рдЧрд│реЗ рдЧреЛрд│рд╛ рдХрд░рд╛, рд╕рд░реНрд╡рд╛рдд рдиреЗрдордХрд╛ рдШреНрдпрд╛, рдЖрдгрд┐ рдХрд╢рд╛рд╢реАрдЪ рди рдЬреБрд│рдгрд╛рд░реЗ drop рдХрд░рд╛.

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

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

рдкреНрд░рддреНрдпреЗрдХ AZ рдордзреНрдпреЗ рдкреНрд░рддреНрдпреЗрдХ tier рд╕рд╛рдареА рдПрдХ route table рд╣реА рдиреЗрд╣рдореАрдЪреА рдкрджреНрдзрдд рдЖрд╣реЗ: public table рд╕рд╛рдорд╛рдпрд┐рдХ рдЕрд╕рддреЛ, рдкреНрд░рддреНрдпреЗрдХ private table рддреНрдпрд╛рдЪреНрдпрд╛рдЪ AZ рдордзрд▓реНрдпрд╛ NAT gateway рдХрдбреЗ рдирд┐рд░реНрджреЗрд╢ рдХрд░рддреЛ (рдзрдбрд╛ 12).

рдЦрд▒реНрдпрд╛ account рд╡рд░ (AWS CLI рдЖрдгрд┐ credentials рд▓рд╛рдЧрддрд╛рдд; IDs рдЙрджрд╛рд╣рд░рдгрд╛рджрд╛рдЦрд▓ рдЖрд╣реЗрдд):

aws ec2 create-route-table --vpc-id vpc-0123456789abcdef0
aws ec2 create-route --route-table-id rtb-0123456789abcdef0 \
    --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0123456789abcdef0
aws ec2 associate-route-table --route-table-id rtb-0123456789abcdef0 --subnet-id subnet-0123456789abcdef0
aws ec2 describe-route-tables --route-table-ids rtb-0123456789abcdef0 --query 'RouteTables[].Routes[]'

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

рдкрд╛рдЯреАрд╡рд░рдЪреА рдПрдХ рдУрд│ wing рд▓рд╛ public wing рдмрдирд╡рддреЗ: 0.0.0.0/0 тЖТ igw. рдкреБрдвреЗ, internet gateway тАФ рдореБрдЦреНрдп рджрд░рд╡рд╛рдЬрд╛.

git checkout lesson-05-igw-public

ЁЯкз Lesson 04 тАФ Route tables: the corridor signs

ЁЯУН You are here: Lesson 04 of 12 ┬╖ Previous: lesson-03-subnets-azs ┬╖ Next: lesson-05-igw-public


ЁЯУж What's in this branch

Lessons 01тАУ03, plus the signs: RouteTable in vpc/network.py holds routes (destination тЖТ target), always starts with the local route, and lookup() picks the most specific route that matches. routes() in vpc/demo.py sends four addresses past one sign.

ЁЯзТ Explain like I'm 5

At the door of every wing hangs a corridor sign ЁЯкз. It has lines like:

A letter for 10.20.96.15 matches two lines: "10.20.x.x" and "everything else". The rule is simple: the most exact line wins. "10.20.x.x" is more exact than "everything else", so the letter stays inside.

If no line matches at all, the letter is dropped. Nobody shouts. It just never arrives.

ЁЯЧ║я╕П Diagram

flowchart LR
    pkt["ЁЯУи packet to 52.219.40.10"]
    subgraph rt["ЁЯкз rt-private-a"]
        r1["10.20.0.0/16 тЖТ local"]
        r2["10.30.0.0/16 тЖТ pcx-partner"]
        r3["pl-s3 тЖТ vpce-s3"]
        r4["0.0.0.0/0 тЖТ nat-a"]
    end
    pkt --> rt
    rt -->|"most specific match wins"| win["тЖТ vpce-s3<br/>52.219.0.0/16 beats 0.0.0.0/0"]

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

тЭУ What

ЁЯдФ Why

Because "public", "private" and "isolated" are not labels you stick on a subnet тАФ they are the result of what its sign says. Read the route table and you know where a wing can go.

ЁЯФз How (in this repo)

RouteTable.__init__ puts (vpc_cidr, "local") first. lookup(dst_ip, prefix_lists) checks every route; a destination that does not start with a digit is a prefix-list name and is expanded from prefix_lists. It keeps the match with the largest prefixlen and returns (destination, target), or (None, None). routes() in vpc/demo.py builds a private-wing sign with a NAT, a peering route and the S3 prefix list pl-s3 (example ranges 52.219.0.0/16 and 3.5.0.0/16).

ЁЯзк Try it

python3 vpc/demo.py routes
python3 - <<'EOF'
import sys; sys.path.insert(0, "vpc"); from network import RouteTable
from demo import VPC, PL
rt = RouteTable("rt-app", VPC, [("0.0.0.0/0", "nat-a"), ("10.20.96.0/20", "firewall")])
for ip in ("10.20.96.15", "10.20.1.1", "93.184.216.34"):
    print(ip.ljust(14), rt.lookup(ip, PL))
bare = RouteTable("rt-empty", VPC)
print("no default route:", bare.lookup("93.184.216.34", PL))
EOF

тЬЕ Verify тАФ what you should see

routes prints:

тФАтФА the corridor sign: the MOST SPECIFIC route that matches wins; 'local' is always there
   тЖТ 10.20.96.15    matches 10.20.0.0/16  тЖТ local
   тЖТ 10.30.4.7      matches 10.30.0.0/16  тЖТ pcx-partner
   тЖТ 52.219.40.10   matches pl-s3         тЖТ vpce-s3
   тЖТ 93.184.216.34  matches 0.0.0.0/0     тЖТ nat-a

Your snippet prints 10.20.96.15 ('10.20.96.0/20', 'firewall') тАФ the /20 beat local's /16 тАФ then 10.20.1.1 ('10.20.0.0/16', 'local'), 93.184.216.34 ('0.0.0.0/0', 'nat-a') and no default route: (None, None).

ЁЯПБ What you just proved

You can read a route table like the VPC router does: collect every match, take the most specific, and drop what matches nothing.

тЪая╕П Common mistakes

ЁЯПн In production

One route table per tier per AZ is common: the public table is shared, each private table points at the NAT gateway in its own AZ (lesson 12).

On a real account (needs the AWS CLI and credentials; IDs are examples):

aws ec2 create-route-table --vpc-id vpc-0123456789abcdef0
aws ec2 create-route --route-table-id rtb-0123456789abcdef0 \
    --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0123456789abcdef0
aws ec2 associate-route-table --route-table-id rtb-0123456789abcdef0 --subnet-id subnet-0123456789abcdef0
aws ec2 describe-route-tables --route-table-ids rtb-0123456789abcdef0 --query 'RouteTables[].Routes[]'

тПня╕П Next

One line on the sign turns a wing into a public wing: 0.0.0.0/0 тЖТ igw. Next, the internet gateway тАФ the front gate.

git checkout lesson-05-igw-public
тЖР Previoussubnets azsNext тЖТigw public

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