ЁЯПл The SchoolтА║ЁЯПл VPCтА║ЁЯФО рдзрдбрд╛ 11 тАФ Flow logs & Reachability Analyzer: A рд▓рд╛ B рдкрд░реНрдпрдВрдд рдХрд╛ рдкреЛрд╣реЛрдЪрддрд╛ рдпреЗрдд рдирд╛рд╣реА?
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯФО рдзрдбрд╛ 11 тАФ Flow logs & Reachability Analyzer: A рд▓рд╛ B рдкрд░реНрдпрдВрдд рдХрд╛ рдкреЛрд╣реЛрдЪрддрд╛ рдпреЗрдд рдирд╛рд╣реА?

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 11 ┬╖ рдорд╛рдЧрдЪрд╛: lesson-10-transit-gateway ┬╖ рдкреБрдврдЪрд╛: lesson-12-production-design


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

рдзрдбреЗ 01тАУ10, рдЖрдгрд┐ рдЧреБрдкреНрддрд╣реЗрд░рд╛рдЪреЗ рдХрд╛рдо: vpc/demo.py рдордзрд▓реЗ troubleshoot() рддреАрди flow-log records рд╡рд╛рдЪрддреЗ, рдордЧ Campus.walk() рдиреЗ web тЖТ db :5432 hop by hop рдЪрд╛рд▓реВрди рдкрд╛рд╣рддреЗ тАФ рдЬрд╕реЗ Reachability Analyzer рдХрд░рддреЛ тАФ рдЖрдгрд┐ рдиреЗрдордХрд╛ рдЕрдбрдерд│рд╛ рд╕рд╛рдВрдЧрддреЗ.

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

рдПрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдореНрд╣рдгрддреЗ: "рдореА рдкрд░реАрдХреНрд╖рд╛ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рд▓рд╛ рдкрддреНрд░ рдкрд╛рдард╡рд▓реЗ рдЖрдгрд┐ рдХреБрдгреАрдЪ рдЙрддреНрддрд░ рджрд┐рд▓реЗ рдирд╛рд╣реА!" ЁЯУи

рдХрд╛рд│рдЬреАрд╡рд╛рд╣рд┐рдХреЗрдХрдбреЗ рдкреНрд░рддреНрдпреЗрдХ desk рд╡рд░ рдПрдХ рдиреЛрдВрджрд╡рд╣реА ЁЯУУ рдЕрд╕рддреЗ: рдкрддреНрд░ рдХреЛрдгреА рдкрд╛рдард╡рд▓реЗ, рдХреЛрдгрд╛рд▓рд╛, рдХреЛрдгрддреНрдпрд╛ рдЦреЛрд▓реАрдд, рдХрд┐рддреА рдкрд╛рдиреЗ тАФ рдЖрдгрд┐ рд╢реЗрд╡рдЯреА рдПрдХ рд╢рдмреНрдж: ACCEPT рдХрд┐рдВрд╡рд╛ REJECT. рдиреЛрдВрджрд╡рд╣реА рджрд╛рдЦрд╡рддреЗ рдХреА рдкрддреНрд░ рдкрд░реАрдХреНрд╖рд╛ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдд рдирд╛рдХрд╛рд░рд▓реЗ рдЧреЗрд▓реЗ.

рдкрдг рддреЗ рдирд╛рдХрд╛рд░рд▓реЗ рдХреЛрдгреА? рдореНрд╣рдгреВрди рдХрд╛рд│рдЬреАрд╡рд╛рд╣рд┐рдХрд╛ рдкрддреНрд░ рдШреЗрдКрди рдорд╛рд░реНрдЧрд╛рд╡рд░реВрди рдЪрд╛рд▓рдд рдЬрд╛рддреЗ: рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдЪреА рд╕реНрд╡рддрдГрдЪреА рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА тАФ рдареАрдХ. рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдЪреНрдпрд╛ wing рдЪреЗ рджрд╛рд░ тАФ рдареАрдХ. Corridor рдЪреА рдкрд╛рдЯреА тАФ рдареАрдХ. рдкрд░реАрдХреНрд╖рд╛ wing рдЪреЗ рджрд╛рд░ тАФ рдареАрдХ. рдкрд░реАрдХреНрд╖рд╛ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдЪреА рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА тАФ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдЪреЗ рдирд╛рд╡ рддреНрдпрд╛рдд рдирд╛рд╣реА. рддреЛрдЪ рдЕрдбрдерд│рд╛ рдЖрд╣реЗ. рдлрдХреНрдд рддреА рдПрдХ рдЧреЛрд╖реНрдЯ рджреБрд░реБрд╕реНрдд рдХрд░рд╛, рд╕рдЧрд│реЗ рдирд╛рд╣реА.

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

flowchart LR
    log["ЁЯУУ flow log<br/>10.20.0.10 тЖТ 10.20.96.15:5432 REJECT"]
    s1["ЁЯзН sg-web out тЬУ"]
    n1["ЁЯЪж acl-open 100 тЬУ"]
    rt["ЁЯкз rt-public local тЬУ"]
    n2["ЁЯЪж acl-data 110 тЬУ"]
    s2["тЫФ sg-db in<br/>THE BLOCKER"]
    log --> s1 --> n1 --> rt --> n2 --> s2

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

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг "network рдмрд┐рдШрдбрд▓реЗ рдЖрд╣реЗ" рд╣реЗ рдирд┐рджрд╛рди рдирд╛рд╣реА. Packet рдерд╛рдВрдмрд╡рд▓рд╛ рдЬрд╛рдК рд╢рдХрддреЛ рдЕрд╢рд╛ рдХрд┐рдорд╛рди рдкрд╛рдЪ рдЬрд╛рдЧрд╛ рдЖрд╣реЗрдд, рдЖрдгрд┐ "рд╕реБрд░рдХреНрд╖рд┐рдд рд░рд╛рд╣рдгреНрдпрд╛рд╕рд╛рдареА" рддреНрдпрд╛ рд╕рдЧрд│реНрдпрд╛ рдмрджрд▓рд▓реНрдпрд╛ рддрд░ рдЕрд╢реА рднреЛрдХреЗ рдкрдбрддрд╛рдд рдЬреА рддреБрдореНрд╣реА рдХрдзреАрдЪ рдмрдВрдж рдХрд░рдгрд╛рд░ рдирд╛рд╣реА. Flow logs рддреБрдореНрд╣рд╛рд▓рд╛ рд╕рд╛рдВрдЧрддрд╛рдд рдХреА рддреЗ рдирд╛рдХрд╛рд░рд▓реЗ рдЧреЗрд▓реЗ; рдЪрд╛рд▓реВрди рдкрд╛рд╣рдгреЗ рд╕рд╛рдВрдЧрддреЗ рдХреБрдареЗ.

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

vpc/demo.py рдордзрд▓реЗ troubleshoot() рдкреНрд░рддреНрдпреЗрдХ log рдУрд│ spaces рд╡рд░ рддреЛрдбрддреЗ рдЖрдгрд┐ fields 3, 4, 6 рдЖрдгрд┐ 12 (srcaddr, dstaddr, dstport, action) рдЫрд╛рдкрддреЗ. рдордЧ рддреЗ campus().walk("web", "10.20.96.15", "tcp", 5432) рдмреЛрд▓рд╛рд╡рддреЗ. walk() рдкрд╣рд┐рд▓реНрдпрд╛ рдЕрдкрдпрд╢реА рддрдкрд╛рд╕рдгреАрд╡рд░ рдерд╛рдВрдмрддреЗ, рдореНрд╣рдгреВрди рд╢реЗрд╡рдЯрдЪреА рдкрд╛рдпрд░реА рд╣рд╛рдЪ рдЕрдбрдерд│рд╛ тАФ vpc/test_vpc.py рдордзрд▓реА test L11 рддреА тЫФ sg-db рдиреЗ рд╕реБрд░реВ рд╣реЛрддреЗ рд╣реЗ рддрдкрд╛рд╕рддреЗ.

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

python3 vpc/demo.py troubleshoot
python3 - <<'EOF'
import sys; sys.path.insert(0, "vpc"); from network import SG
from demo import campus
FIELDS = "version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status".split()
line = "2 111122223333 eni-0web 10.20.0.10 10.20.96.15 49152 5432 6 3 180 1790000000 1790000060 REJECT OK"
rec = dict(zip(FIELDS, line.split()))
print({k: rec[k] for k in ("interface-id", "srcaddr", "dstaddr", "dstport", "protocol", "action")})
c = campus()
print("before:", c.walk("web", "10.20.96.15", "tcp", 5432)[1][-1])
c.sgs["sg-db"] = SG("sg-db", [("tcp", (5432, 5432), "10.20.48.0/20"), ("tcp", (5432, 5432), "10.20.0.10/32")])
ok, steps = c.walk("web", "10.20.96.15", "tcp", 5432)
print("after: ", ok, steps[-1])
print("no host:", c.walk("app", "10.20.96.99", "tcp", 5432)[1][-1])
EOF

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

troubleshoot рд╣реЗ рдЫрд╛рдкрддреЗ:

   10.20.48.25    тЖТ 10.20.96.15   :5432  ACCEPT
   10.20.0.10     тЖТ 10.20.96.15   :5432  REJECT
   198.51.100.9   тЖТ 10.20.0.10    :22    REJECT
тФАтФА why is web тЖТ db :5432 rejected? walk it like Reachability Analyzer:
   ЁЯзН sg-web out тЬУ
   ЁЯЪж acl-open rule 100 ALLOW
   ЁЯкз rt-public: 10.20.0.0/16 тЖТ local
   ЁЯЪж acl-data rule 110 ALLOW (destination subnet, in)
   тЫФ sg-db in тАФ not on the guest list

рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ {'interface-id': 'eni-0web', 'srcaddr': '10.20.0.10', 'dstaddr': '10.20.96.15', 'dstport': '5432', 'protocol': '6', 'action': 'REJECT'}, рдордЧ before: тЫФ sg-db in тАФ not on the guest list, after: True ЁЯзН sg-db in тЬУ (рдПрдХ /32 rule, рдмрд╛рдХреА рдХрд╛рд╣реАрдЪ рдмрджрд▓рд▓реЗ рдирд╛рд╣реА), рдЖрдгрд┐ no host: тЭУ no host at that address.

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

рддреБрдореНрд╣реА flow-log рдЪреА рдУрд│ field by field рд╡рд╛рдЪреВ рд╢рдХрддрд╛, рдорд╛рд░реНрдЧ hop by hop рдЪрд╛рд▓реВрди рдкрд╛рд╣реВ рд╢рдХрддрд╛, рдЖрдгрд┐ рдЕрдбрд╡рдгрд╛рд░рд╛ рдиреЗрдордХрд╛ рдПрдХрдЪ component рджреБрд░реБрд╕реНрдд рдХрд░реВ рд╢рдХрддрд╛.

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

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

рдкреНрд░рддреНрдпреЗрдХ VPC рд╡рд░ flow logs, S3 рдХрдбреЗ (рдореЛрдареНрдпрд╛ рдкреНрд░рдорд╛рдгрд╛рд╕рд╛рдареА рд╕реНрд╡рд╕реНрдд) рдХрд┐рдВрд╡рд╛ CloudWatch Logs рдХрдбреЗ (query рдХрд░рд╛рдпрд▓рд╛ рдЬрд▓рдж), рд╣рд╛ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп security baseline рдЖрд╣реЗ. Ticket рдордзреНрдпреЗ "A рд▓рд╛ B рдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪрддрд╛ рдпреЗрдд рдирд╛рд╣реА" рдЕрд╕реЗ рдЖрд▓реЗ рдХреА Reachability Analyzer рд╣реЗ рдкрд╣рд┐рд▓реЗ tool рдЕрд╕рддреЗ.

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

aws ec2 create-flow-logs --resource-type VPC --resource-ids vpc-0123456789abcdef0 \
    --traffic-type ALL --log-destination-type s3 --log-destination arn:aws:s3:::school-flow-logs
aws ec2 create-network-insights-path --source i-0web0000000000000 --destination i-0db00000000000000 \
    --protocol tcp --destination-port 5432
aws ec2 start-network-insights-analysis --network-insights-path-id nip-0123456789abcdef0
aws ec2 describe-network-insights-analyses --network-insights-analysis-ids nia-0123456789abcdef0 \
    --query 'NetworkInsightsAnalyses[0].[NetworkPathFound,Explanations]'

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

рддреБрдореНрд╣реА campus рдмрд╛рдВрдзреВ рд╢рдХрддрд╛, рдЬреЛрдбреВ рд╢рдХрддрд╛ рдЖрдгрд┐ debug рдХрд░реВ рд╢рдХрддрд╛. рд╢реЗрд╡рдЯрдЪреА рдкрд╛рдпрд░реА: рдЯрд┐рдХрдгрд╛рд░рд╛ campus рдмрд╛рдВрдзрд╛. Production VPC design.

git checkout lesson-12-production-design

ЁЯФО Lesson 11 тАФ Flow logs & Reachability Analyzer: why can't A reach B?

ЁЯУН You are here: Lesson 11 of 12 ┬╖ Previous: lesson-10-transit-gateway ┬╖ Next: lesson-12-production-design


ЁЯУж What's in this branch

Lessons 01тАУ10, plus the detective work: troubleshoot() in vpc/demo.py reads three flow-log records, then walks web тЖТ db :5432 hop by hop with Campus.walk() тАФ the way Reachability Analyzer does тАФ and names the exact blocker.

ЁЯзТ Explain like I'm 5

A pupil says: "I sent a letter to the exam office and nobody answered!" ЁЯУи

The caretaker has a logbook ЁЯУУ at every desk: who sent a letter, to whom, which room, how many pages тАФ and one word at the end: ACCEPT or REJECT. The logbook shows the letter was rejected at the exam office.

But who rejected it? So the caretaker walks the path with the letter: the pupil's own guest list тАФ fine. The pupil's wing door тАФ fine. The corridor sign тАФ fine. The exam wing's door тАФ fine. The exam office's guest list тАФ the pupil is not on it. That is the blocker. Fix that one thing, not everything.

ЁЯЧ║я╕П Diagram

flowchart LR
    log["ЁЯУУ flow log<br/>10.20.0.10 тЖТ 10.20.96.15:5432 REJECT"]
    s1["ЁЯзН sg-web out тЬУ"]
    n1["ЁЯЪж acl-open 100 тЬУ"]
    rt["ЁЯкз rt-public local тЬУ"]
    n2["ЁЯЪж acl-data 110 тЬУ"]
    s2["тЫФ sg-db in<br/>THE BLOCKER"]
    log --> s1 --> n1 --> rt --> n2 --> s2

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

тЭУ What

ЁЯдФ Why

Because "the network is broken" is not a diagnosis. There are at least five places a packet can be stopped, and changing all of them "to be safe" opens holes you will never close. Flow logs tell you that it was rejected; the walk tells you where.

ЁЯФз How (in this repo)

troubleshoot() in vpc/demo.py splits each log line on spaces and prints fields 3, 4, 6 and 12 (srcaddr, dstaddr, dstport, action). Then it calls campus().walk("web", "10.20.96.15", "tcp", 5432). walk() stops at the first failing check, so the last step is the blocker тАФ test L11 in vpc/test_vpc.py checks it starts with тЫФ sg-db.

ЁЯзк Try it

python3 vpc/demo.py troubleshoot
python3 - <<'EOF'
import sys; sys.path.insert(0, "vpc"); from network import SG
from demo import campus
FIELDS = "version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status".split()
line = "2 111122223333 eni-0web 10.20.0.10 10.20.96.15 49152 5432 6 3 180 1790000000 1790000060 REJECT OK"
rec = dict(zip(FIELDS, line.split()))
print({k: rec[k] for k in ("interface-id", "srcaddr", "dstaddr", "dstport", "protocol", "action")})
c = campus()
print("before:", c.walk("web", "10.20.96.15", "tcp", 5432)[1][-1])
c.sgs["sg-db"] = SG("sg-db", [("tcp", (5432, 5432), "10.20.48.0/20"), ("tcp", (5432, 5432), "10.20.0.10/32")])
ok, steps = c.walk("web", "10.20.96.15", "tcp", 5432)
print("after: ", ok, steps[-1])
print("no host:", c.walk("app", "10.20.96.99", "tcp", 5432)[1][-1])
EOF

тЬЕ Verify тАФ what you should see

troubleshoot prints:

   10.20.48.25    тЖТ 10.20.96.15   :5432  ACCEPT
   10.20.0.10     тЖТ 10.20.96.15   :5432  REJECT
   198.51.100.9   тЖТ 10.20.0.10    :22    REJECT
тФАтФА why is web тЖТ db :5432 rejected? walk it like Reachability Analyzer:
   ЁЯзН sg-web out тЬУ
   ЁЯЪж acl-open rule 100 ALLOW
   ЁЯкз rt-public: 10.20.0.0/16 тЖТ local
   ЁЯЪж acl-data rule 110 ALLOW (destination subnet, in)
   тЫФ sg-db in тАФ not on the guest list

Your snippet prints {'interface-id': 'eni-0web', 'srcaddr': '10.20.0.10', 'dstaddr': '10.20.96.15', 'dstport': '5432', 'protocol': '6', 'action': 'REJECT'}, then before: тЫФ sg-db in тАФ not on the guest list, after: True ЁЯзН sg-db in тЬУ (one /32 rule, nothing else changed), and no host: тЭУ no host at that address.

ЁЯПБ What you just proved

You can read a flow-log line field by field, walk a path hop by hop, and fix exactly the one component that blocks it.

тЪая╕П Common mistakes

ЁЯПн In production

Flow logs on every VPC, to S3 (cheaper for volume) or CloudWatch Logs (quicker to query), are a standard security baseline. Reachability Analyzer is the first tool when a ticket says "A cannot reach B".

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

aws ec2 create-flow-logs --resource-type VPC --resource-ids vpc-0123456789abcdef0 \
    --traffic-type ALL --log-destination-type s3 --log-destination arn:aws:s3:::school-flow-logs
aws ec2 create-network-insights-path --source i-0web0000000000000 --destination i-0db00000000000000 \
    --protocol tcp --destination-port 5432
aws ec2 start-network-insights-analysis --network-insights-path-id nip-0123456789abcdef0
aws ec2 describe-network-insights-analyses --network-insights-analysis-ids nia-0123456789abcdef0 \
    --query 'NetworkInsightsAnalyses[0].[NetworkPathFound,Explanations]'

тПня╕П Next

You can build, connect and debug a campus. Last step: build one that lasts. Production VPC design.

git checkout lesson-12-production-design
тЖР Previoustransit gatewayNext тЖТproduction design

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