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

ЁЯПв рдзрдбрд╛ 04 тАФ рдкреНрд░рддреНрдпреЗрдХ AZ рд▓рд╛ рдПрдХ рдлрд╛рдЯрдХ

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 8 рдкреИрдХреА рдзрдбрд╛ 04 ┬╖ рдорд╛рдЧреЗ: lesson-03-gateway-vs-instance ┬╖ рдкреБрдвреЗ: lesson-05-elastic-ips


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

рдзрдбреЗ 01тАУ03, рдЖрдгрд┐ рдЯрд┐рдХрд╛рдК рд░рдЪрдирд╛: рдкреНрд░рддреНрдпреЗрдХ Availability Zone рдордзреНрдпреЗ рдПрдХ NAT gateway, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ AZ рдЪреА private route table рддреНрдпрд╛рдЪ AZ рдордзреАрд▓ NAT рдХрдбреЗ рдирд┐рд░реНрджреЗрд╢ рдХрд░рддреЗ. nat/demo.py рдордзреАрд▓ peraz() рджреЛрдиреНрд╣реА рд░рдЪрдирд╛рдВрдордзреНрдпреЗ рдПрдХ AZ рдмрдВрдж рдкрд╛рдбреВрди рдкрд╛рд╣рддреЗ.

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

рд╢рд╛рд│реЗрдЪреНрдпрд╛ рддреАрди рдЗрдорд╛рд░рддреА рдЖрд╣реЗрдд ЁЯПвЁЯПвЁЯПв: A, B рдЖрдгрд┐ C. рдкреНрд░рддреНрдпреЗрдХреАрдЪреА рд╕реНрд╡рддрдГрдЪреА рд╡реАрдЬ рдЖрд╣реЗ.

рдЖрд░рд╛рдЦрдбрд╛ 1: рдлрдХреНрдд рдЗрдорд╛рд░рдд A рд▓рд╛ рдлрд╛рдЯрдХ рдЖрд╣реЗ. B рдЖрдгрд┐ C рдордзреАрд▓ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдореИрджрд╛рди рдУрд▓рд╛рдВрдбреВрди A рдЪреНрдпрд╛ рдлрд╛рдЯрдХрд╛рдХрдбреЗ рдЬрд╛рддрд╛рдд. рдордЧ A рдЪреА рд╡реАрдЬ рдЬрд╛рддреЗ. рдкреНрд░рддреНрдпреЗрдХ рдЗрдорд╛рд░рддреАрддреАрд▓ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдЖрдд рдЕрдбрдХрддреЗ тАФ рдЖрдгрд┐ рдореИрджрд╛рди рдУрд▓рд╛рдВрдбрдгреНрдпрд╛рдЪреНрдпрд╛ рд▓рд╛рдВрдмрдЪреНрдпрд╛ рдЪрд╛рд▓реАрдд рд░реЛрдЬ рд╡реЗрд│рд╣реА рдЬрд╛рдд рд╣реЛрддрд╛.

рдЖрд░рд╛рдЦрдбрд╛ 2: рдкреНрд░рддреНрдпреЗрдХ рдЗрдорд╛рд░рддреАрд▓рд╛ рд╕реНрд╡рддрдГрдЪреЗ рдлрд╛рдЯрдХ рдЖрдгрд┐ рд╕реНрд╡рддрдГрдЪрд╛ рд░рдЦрд╡рд╛рд▓рджрд╛рд░ рдЖрд╣реЗ. A рдЪреА рд╡реАрдЬ рдЬрд╛рддреЗ. A рдордзреАрд▓ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдЕрдбрдХрддрд╛рдд (рддреНрдпрд╛рдВрдЪреА рдЗрдорд╛рд░рдд рддрд╢реАрд╣реА рдЕрдВрдзрд╛рд░рд╛рдд рдЖрд╣реЗ). B рдЖрдгрд┐ C рдордзреАрд▓ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдиреЗрд╣рдореАрдкреНрд░рдорд╛рдгреЗ рдЖрдкрд╛рдкрд▓реНрдпрд╛ рдлрд╛рдЯрдХрд╛рдВрддреВрди рдмрд╛рд╣реЗрд░ рдЬрд╛рддрд╛рдд.

AWS рдпрд╛ рдЗрдорд╛рд░рддреАрдВрдирд╛ Availability Zones рдореНрд╣рдгрддреЗ. рдореИрджрд╛рди рдУрд▓рд╛рдВрдбреВрди рдЬрд╛рдгреЗ рдореНрд╣рдгрдЬреЗ cross-AZ traffic, рдЖрдгрд┐ рддреНрдпрд╛рдЪреА рдХрд┐рдВрдордд рдореЛрдЬрд╛рд╡реА рд▓рд╛рдЧрддреЗ.

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

flowchart TB
    subgraph A["ЁЯПв AZ a ЁЯТе"]
      pa["private-a"] --> na["nat-a"]
    end
    subgraph B["ЁЯПв AZ b"]
      pb["private-b"] --> nb["nat-b"]
    end
    subgraph C["ЁЯПв AZ c"]
      pc["private-c"] --> nc["nat-c"]
    end
    na -.->|"1 down with its AZ"| x["ЁЯЪл"]
    nb -->|"2 still out"| net["ЁЯМР internet"]
    nc -->|"2 still out"| net

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

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг AZs рдЦрд░реЛрдЦрд░ рдмрдВрдж рдкрдбрддрд╛рдд тАФ рд╡реАрдЬ, cooling, network тАФ рдЖрдгрд┐ multi-AZ apps рдЕрд╢рд╛рдЪ рдмрд╛рдВрдзрд▓реНрдпрд╛ рдЬрд╛рддрд╛рдд рдХреА рдПрдЦрд╛рджрд╛ AZ рдЧреЗрд▓рд╛ рддрд░реА рдЪрд╛рд▓реЗрд▓. рдПрдХрдЪ shared NAT, multi-AZ рд░рдЪрдирд╛ рдЬреЛ single point of failure рдХрд╛рдврдгреНрдпрд╛рд╕рд╛рдареА рд╣реЛрддреА, рддреЛрдЪ рдЧреБрдкрдЪреВрдк рдкрд░рдд рдЖрдгрддреЛ: AZ b рдЖрдгрд┐ c рдордзреАрд▓ app servers рдЯрд┐рдХрддрд╛рдд, рдкрдг рддреЗ payment API рдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪреВ рд╢рдХрдд рдирд╛рд╣реАрдд.

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

nat/gateway.py рдордзреАрд▓ route_for() "рд╣реЗ private subnet рдХреЛрдгрддрд╛ NAT рд╡рд╛рдкрд░рддреЗ?" рдпрд╛рдЪреЗ рдЙрддреНрддрд░ рджреЗрддреЗ тАФ рдкреНрд░рддреНрдпреЗрдХ AZ рд▓рд╛ рдПрдХ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рд░рдЪрдиреЗрдд nat_by_az[az], рдХрд┐рдВрд╡рд╛ рддреБрдореНрд╣реА рджрд┐рд▓рд╛ рддрд░ shared. reachable() рд╕рд╛рдВрдЧрддреЗ рдХреА рддреЛ NAT up рдЖрд╣реЗ рдХрд╛. nat/demo.py рдордзреАрд▓ peraz() nat-a рдмрдВрдж рдХрд░рддреЗ рдЖрдгрд┐ рджреЛрдиреНрд╣реА рд░рдЪрдирд╛рдВрдордзреНрдпреЗ рддрд┐рдиреНрд╣реА AZs рддрдкрд╛рд╕рддреЗ.

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

python3 nat/demo.py peraz
python3 - <<'EOF'
import sys; sys.path.insert(0, "nat"); from gateway import NatGateway, route_for, reachable, monthly_cost
gws = {n: NatGateway(n, [ip], az) for n, ip, az in (("nat-a", "13.232.10.20", "a"), ("nat-b", "13.232.10.21", "b"), ("nat-c", "13.232.10.22", "c"))}
by_az = {"a": "nat-a", "b": "nat-b", "c": "nat-c"}
print("routes per AZ:", [route_for(az, by_az) for az in "abc"], "┬╖ shared:", [route_for(az, by_az, "nat-a") for az in "abc"])
gws["nat-b"].up = False
print("nat-b down, one per AZ :", [az for az in "abc" if reachable(az, by_az, gws)])
print("nat-b down, shared nat-a:", [az for az in "abc" if reachable(az, by_az, gws, "nat-a")])
print("hours only: 3 NATs", monthly_cost(3, 0), "┬╖ 1 NAT", monthly_cost(1, 0))
EOF

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

peraz рд╣реЗ ЁЯТе AZ a goes down (nat-a with it) рдЫрд╛рдкрддреЗ, рдордЧ private-b: one-per-AZ тЖТ тЬЕ ┬╖ one shared nat-a тЖТ ЁЯЪл cut off (рдЖрдгрд┐ private-c рд╕рд╛рдареАрд╣реА рддрд╕реЗрдЪ). рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:

routes per AZ: ['nat-a', 'nat-b', 'nat-c'] ┬╖ shared: ['nat-a', 'nat-a', 'nat-a']
nat-b down, one per AZ : ['a', 'c']
nat-b down, shared nat-a: ['a', 'b', 'c']
hours only: 3 NATs 98.55 ┬╖ 1 NAT 32.85

рддрд┐рд╕рд░реА рдУрд│ рдиреАрдЯ рд╡рд╛рдЪрд╛. AZ b рдмрдВрдж рдкрдбрддреЛ рддреЗрд╡реНрд╣рд╛ shared рд░рдЪрдирд╛ рдареАрдХ рджрд┐рд╕рддреЗ тАФ рдлрд╛рдЯрдХ AZ a рдордзреНрдпреЗ рдЖрд╣реЗ. Shared рд░рдЪрдирд╛ рд░реЛрдЬ рдмрд┐рдШрдбрд▓реЗрд▓реА рдирд╕рддреЗ; рддреА рддреНрдпрд╛рдЪ рджрд┐рд╡рд╢реА рдмрд┐рдШрдбрддреЗ рдЬреНрдпрд╛ рджрд┐рд╡рд╢реА рдмрдВрдж рдкрдбрдгрд╛рд░рд╛ AZ рдлрд╛рдЯрдХ рдЕрд╕рд▓реЗрд▓рд╛рдЪ рдЕрд╕рддреЛ. рдХреЛрдгрддрд╛ AZ рдмрдВрдж рдкрдбреЗрд▓ рд╣реЗ рддреБрдореНрд╣реА рдирд┐рд╡рдбреВ рд╢рдХрдд рдирд╛рд╣реА. рд╢реЗрд╡рдЯрдЪреА рдУрд│ рдореНрд╣рдгрдЬреЗ рд╕реБрд░рдХреНрд╖рд┐рддрддреЗрдЪреА рдХрд┐рдВрдордд: рдПрдХрд╛ рдРрд╡рдЬреА рддреАрди рддрд╛рд╕рд╛рдЪреЗ рдореАрдЯрд░ (рдЙрджрд╛рд╣рд░рдг рдХрд┐рдорддреА, рдХреЛрдгрддреНрдпрд╛рд╣реА GB рдЖрдзреА).

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

рдкреНрд░рддреНрдпреЗрдХ AZ рд▓рд╛ рдПрдХ NAT рдЕрд╕реЗрд▓ рддрд░ AZ рдЪрд╛ рдмрд┐рдШрд╛рдб рддреНрдпрд╛ AZ рдЪреНрдпрд╛ рдЖрддрдЪ рд░рд╛рд╣рддреЛ; рдПрдХрдЪ shared NAT рдЕрд╕реЗрд▓ рддрд░ рддреЗ рдирд╢рд┐рдмрд╛рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдЕрд╕рддреЗ тАФ рдЖрдгрд┐ рд╕реБрд░рдХреНрд╖рд┐рдд рд░рдЪрдиреЗрд╕рд╛рдареА рджреЛрди рдЬрд╛рд╕реНрддреАрдЪреЗ рддрд╛рд╕рд╛рдЪреЗ charges рд▓рд╛рдЧрддрд╛рдд.

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

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

рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ рдкреНрд░рддреНрдпреЗрдХ AZ рд╕рд╛рдареА рдПрдХ NAT gateway рдЖрдгрд┐ рдПрдХ private route рдпрд╛рд╕рд╛рдареА Terraform:

locals { azs = ["a", "b", "c"] }

resource "aws_eip" "nat" {
  for_each = toset(local.azs)
  domain   = "vpc"
}

resource "aws_nat_gateway" "this" {
  for_each      = toset(local.azs)
  allocation_id = aws_eip.nat[each.key].id
  subnet_id     = aws_subnet.public[each.key].id
  tags          = { Name = "nat-${each.key}" }
}

resource "aws_route" "private_default" {
  for_each               = toset(local.azs)
  route_table_id         = aws_route_table.private[each.key].id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.this[each.key].id
}

рдкреНрд░рддреНрдпреЗрдХ private route table рддреНрдпрд╛рдЪреНрдпрд╛рдЪ AZ рдордзреАрд▓ NAT рдХрдбреЗ рдирд┐рд░реНрджреЗрд╢ рдХрд░рддреЗ рд╣реЗ рддрдкрд╛рд╕рд╛:

aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-0abc --query 'RouteTables[].[RouteTableId,Associations[0].SubnetId,Routes[?DestinationCidrBlock==`0.0.0.0/0`].NatGatewayId|[0]]' --output table
aws ec2 describe-nat-gateways --filter Name=vpc-id,Values=vpc-0abc --query 'NatGateways[].[NatGatewayId,SubnetId]' --output table

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: "рдПрдХ AZ рдЧреЗрд▓рд╛ рддрд░ рдХрд╛рдп рд╣реЛрддреЗ?" рд╣рд╛ рдкреНрд░рддреНрдпреЗрдХ architecture review рдордзреАрд▓ рдкрд╣рд┐рд▓рд╛ рдкреНрд░рд╢реНрди рдЕрд╕рддреЛ. Egress рд╕рд╛рдареА рдмрд░реЛрдмрд░ рдЙрддреНрддрд░ рдЖрд╣реЗ "рдкреНрд░рддреНрдпреЗрдХ AZ рдЪрд╛ рд╕реНрд╡рддрдГрдЪрд╛ NAT рдЖрд╣реЗ; рдЖрдкрдг рддреЛ AZ рдЧрдорд╛рд╡рддреЛ, рдмрд╛рдХреА рдХрд╛рд╣реА рдирд╛рд╣реА".

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

рдмрд╛рд╣реЗрд░ рдЬрд╛рдгрд╛рд░реА рдкреНрд░рддреНрдпреЗрдХ рдлреЗрд░реА рдлрд╛рдЯрдХрд╛рдЪрд╛ рдкрддреНрддрд╛ рдШреЗрдКрди рдмрд╛рд╣реЗрд░ рдкрдбрддреЗ. Partners рддреНрдпрд╛ рдкрддреНрддреНрдпрд╛рд╡рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡реВ рд╢рдХрддрд╛рдд тАФ рдкрдг рддреНрдпрд╛рдВрдиреА рдлрдХреНрдд рддреНрдпрд╛рд╡рд░рдЪ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рд╛рд╡рд╛ рдХрд╛? Elastic IPs рдЖрдгрд┐ allow-listing.

git checkout lesson-05-elastic-ips

ЁЯПв Lesson 04 тАФ One gate per AZ

ЁЯУН You are here: Lesson 04 of 8 ┬╖ Previous: lesson-03-gateway-vs-instance ┬╖ Next: lesson-05-elastic-ips


ЁЯУж What's in this branch

Lessons 01тАУ03, plus the resilient design: one NAT gateway in each Availability Zone, and each AZ's private route table pointing at the NAT in the same AZ. peraz() in nat/demo.py fails one AZ under both designs.

ЁЯзТ Explain like I'm 5

The school has three buildings ЁЯПвЁЯПвЁЯПв: A, B and C. Each has its own power.

Plan 1: only building A has a gate. Pupils in B and C walk across the yard to A's gate. Then A has a power cut. Every pupil in every building is stuck inside тАФ and the long walk across the yard cost time every day too.

Plan 2: each building has its own gate with its own guard. A has a power cut. Pupils in A are stuck (their building is dark anyway). Pupils in B and C walk out of their own gates as usual.

AWS calls the buildings Availability Zones. The walk across the yard is cross-AZ traffic, and it has a price.

ЁЯЧ║я╕П Diagram

flowchart TB
    subgraph A["ЁЯПв AZ a ЁЯТе"]
      pa["private-a"] --> na["nat-a"]
    end
    subgraph B["ЁЯПв AZ b"]
      pb["private-b"] --> nb["nat-b"]
    end
    subgraph C["ЁЯПв AZ c"]
      pc["private-c"] --> nc["nat-c"]
    end
    na -.->|"1 down with its AZ"| x["ЁЯЪл"]
    nb -->|"2 still out"| net["ЁЯМР internet"]
    nc -->|"2 still out"| net

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

тЭУ What

ЁЯдФ Why

Because AZs do fail тАФ power, cooling, network тАФ and multi-AZ apps are built so that one AZ can go away. A single shared NAT quietly brings back the single point of failure that the multi-AZ design was meant to remove: the app servers in AZ b and c survive, but they can no longer reach the payment API.

ЁЯФз How (in this repo)

route_for() in nat/gateway.py answers "which NAT does this private subnet use?" тАФ nat_by_az[az] in the one-per-AZ design, or shared if you pass one. reachable() says whether that NAT is up. peraz() in nat/demo.py sets nat-a down and checks all three AZs under both designs.

ЁЯзк Try it

python3 nat/demo.py peraz
python3 - <<'EOF'
import sys; sys.path.insert(0, "nat"); from gateway import NatGateway, route_for, reachable, monthly_cost
gws = {n: NatGateway(n, [ip], az) for n, ip, az in (("nat-a", "13.232.10.20", "a"), ("nat-b", "13.232.10.21", "b"), ("nat-c", "13.232.10.22", "c"))}
by_az = {"a": "nat-a", "b": "nat-b", "c": "nat-c"}
print("routes per AZ:", [route_for(az, by_az) for az in "abc"], "┬╖ shared:", [route_for(az, by_az, "nat-a") for az in "abc"])
gws["nat-b"].up = False
print("nat-b down, one per AZ :", [az for az in "abc" if reachable(az, by_az, gws)])
print("nat-b down, shared nat-a:", [az for az in "abc" if reachable(az, by_az, gws, "nat-a")])
print("hours only: 3 NATs", monthly_cost(3, 0), "┬╖ 1 NAT", monthly_cost(1, 0))
EOF

тЬЕ Verify тАФ what you should see

peraz prints ЁЯТе AZ a goes down (nat-a with it), then private-b: one-per-AZ тЖТ тЬЕ ┬╖ one shared nat-a тЖТ ЁЯЪл cut off (and the same for private-c). Your snippet prints:

routes per AZ: ['nat-a', 'nat-b', 'nat-c'] ┬╖ shared: ['nat-a', 'nat-a', 'nat-a']
nat-b down, one per AZ : ['a', 'c']
nat-b down, shared nat-a: ['a', 'b', 'c']
hours only: 3 NATs 98.55 ┬╖ 1 NAT 32.85

Read the third line carefully. When AZ b fails, the shared design looks fine тАФ the gate is in AZ a. The shared design is not broken every day; it is broken on the day the failing AZ is the one holding the gate. You cannot choose which AZ fails. The last line is the price of safety: three hourly meters instead of one (example prices, before any GB).

ЁЯПБ What you just proved

With one NAT per AZ, an AZ failure stays inside that AZ; with one shared NAT, it depends on luck тАФ and the safe design costs two extra hourly charges.

тЪая╕П Common mistakes

ЁЯПн In production

On a real account тАФ Terraform for one NAT gateway and one private route per AZ:

locals { azs = ["a", "b", "c"] }

resource "aws_eip" "nat" {
  for_each = toset(local.azs)
  domain   = "vpc"
}

resource "aws_nat_gateway" "this" {
  for_each      = toset(local.azs)
  allocation_id = aws_eip.nat[each.key].id
  subnet_id     = aws_subnet.public[each.key].id
  tags          = { Name = "nat-${each.key}" }
}

resource "aws_route" "private_default" {
  for_each               = toset(local.azs)
  route_table_id         = aws_route_table.private[each.key].id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.this[each.key].id
}

Check that every private route table points at a NAT in its own AZ:

aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-0abc --query 'RouteTables[].[RouteTableId,Associations[0].SubnetId,Routes[?DestinationCidrBlock==`0.0.0.0/0`].NatGatewayId|[0]]' --output table
aws ec2 describe-nat-gateways --filter Name=vpc-id,Values=vpc-0abc --query 'NatGateways[].[NatGatewayId,SubnetId]' --output table

ЁЯПн Why this matters in production: "what happens when one AZ goes away?" is the first question in every architecture review. For egress, the correct answer is "each AZ has its own NAT; we lose that AZ and nothing else".

тПня╕П Next

Every trip out leaves with the gate's address on it. Partners can trust that address тАФ but should they trust only that? Elastic IPs and allow-listing.

git checkout lesson-05-elastic-ips
тЖР Previousgateway vs instanceNext тЖТelastic ips

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