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

ЁЯЪЗ рдзрдбрд╛ 07 тАФ VPC endpoints: AWS services рдкрд░реНрдпрдВрддрдЪрд╛ рдЦрд╛рдЬрдЧреА рдмреЛрдЧрджрд╛

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 07 ┬╖ рдорд╛рдЧрдЪрд╛: lesson-06-sg-vs-nacl ┬╖ рдкреБрдврдЪрд╛: lesson-08-dns


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

рднрд╛рдЧ 1 рдордзрд▓рд╛ рд╕рдВрдкреВрд░реНрдг campus, рдЖрдгрд┐ рджрд░рд╡рд╛рдЬрд╛ рдирд╕рд▓реЗрд▓рд╛ рдкрд╣рд┐рд▓рд╛ рдмрд╛рд╣реЗрд░рдЪрд╛ рдорд╛рд░реНрдЧ: S3 рд╕рд╛рдареА рдПрдХ gateway endpoint. campus() (vpc/demo.py) рдордзреНрдпреЗ рджреЛрдиреНрд╣реА private route tables рдордзреНрдпреЗ pl-s3 тЖТ vpce-s3 рдЖрд╣реЗ; endpoints() рджрд╛рдЦрд╡рддреЗ рдХреА S3 traffic app wing рдордзреВрди (рдЬреНрдпрд╛рд▓рд╛ NAT рд╕реБрджреНрдзрд╛ рдЖрд╣реЗ) рдЖрдгрд┐ data wing рдордзреВрди (рдЬреНрдпрд╛рд▓рд╛ рджреБрд╕рд░реЗ рдХрд╛рд╣реАрдЪ рдирд╛рд╣реА) рдХреБрдареЗ рдЬрд╛рддреЗ.

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

рд╢рд╛рд│рд╛ рдЖрдкрд▓реНрдпрд╛ рдЬреБрдиреНрдпрд╛ рдкрд░реАрдХреНрд╖реЗрдЪреНрдпрд╛ рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рдПрдХрд╛ рдореЛрдареНрдпрд╛ рд╢рд╣рд░рд╛рддреАрд▓ рд╕рдВрдЧреНрд░рд╣рд╛рд▓рдпрд╛рдд ЁЯЧДя╕П рдареЗрд╡рддреЗ тАФ рддреЗрдЪ S3. рд╣реЗ рд╕рдВрдЧреНрд░рд╣рд╛рд▓рдп campus рдЪреНрдпрд╛ рдХреБрдВрдкрдгрд╛рдмрд╛рд╣реЗрд░ рдЖрд╣реЗ.

App wing рдПрдЦрд╛рджреНрдпрд╛ рдирд┐рд░реЛрдкреНрдпрд╛рд▓рд╛ рдмрд╛рдЬреВрдЪреНрдпрд╛ рджрд╛рд░рд╛рддреВрди (NAT) рдмрд╛рд╣реЗрд░, рд╢рд╣рд░рд╛рдЪреНрдпрд╛ рд░рд╕реНрддреНрдпрд╛рд╡рд░реВрди, рд╕рдВрдЧреНрд░рд╣рд╛рд▓рдпрд╛рдкрд░реНрдпрдВрдд рдкрд╛рдард╡реВ рд╢рдХрддреЛ. рд╣реЗ рдЪрд╛рд▓рддреЗ тАФ рдкрдг рдкреНрд░рддреНрдпреЗрдХ рдлреЗрд░реАрд▓рд╛ рдЯреЛрд▓ рд▓рд╛рдЧрддреЛ, рдЖрдгрд┐ рдирд┐рд░реЛрдкреНрдпрд╛ рд░рд╕реНрддреНрдпрд╛рд╡рд░ рдЙрдШрдбреНрдпрд╛рд╡рд░ рдЕрд╕рддреЛ.

рдореНрд╣рдгреВрди рд╢рд╛рд│рд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ campus рдордзреВрди рдереЗрдЯ рд╕рдВрдЧреНрд░рд╣рд╛рд▓рдпрд╛рдд рдПрдХ рдЦрд╛рдЬрдЧреА рдмреЛрдЧрджрд╛ ЁЯЪЗ рдЦрдгрддреЗ. Corridor рд╡рд░рдЪреНрдпрд╛ рдкрд╛рдЯреАрд╡рд░ рдПрдХ рдирд╡реА рдУрд│ рдпреЗрддреЗ: "рд╕рдВрдЧреНрд░рд╣рд╛рд▓рдп тЖТ рдмреЛрдЧрджрд╛". рдЖрддрд╛ рдирд┐рд░реЛрдкреНрдпрд╛ рдХрдзреАрдЪ AWS рдмрд╛рд╣реЗрд░ рдЬрд╛рдд рдирд╛рд╣реА, рдЖрдгрд┐ рд╣рд╛ рдмреЛрдЧрджрд╛ рдореЛрдлрдд рдЖрд╣реЗ. рдЬреНрдпрд╛ data wing рд▓рд╛ рдХреЛрдгрддреЗрдЪ рджрд╛рд░ рдирд╛рд╣реА, рддреЛрд╕реБрджреНрдзрд╛ рдпрд╛ рдмреЛрдЧрджреНрдпрд╛рддреВрди рд╕рдВрдЧреНрд░рд╣рд╛рд▓рдпрд╛рдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪреВ рд╢рдХрддреЛ.

рд╢рд╣рд░рд╛рддрд▓реНрдпрд╛ рдЗрддрд░ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдВрд╕рд╛рдареА (рд░рд╛рдВрдЧрд╛, рдЧреБрдкрд┐рддреЗ, container images) рд╢рд╛рд│рд╛ рдЖрдкрд▓реНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ wing рдордзреНрдпреЗрдЪ рдПрдХ рдЫреЛрдЯреА рдЦрд╛рдЬрдЧреА рдЦрд┐рдбрдХреА ЁЯкЯ рдмрд╕рд╡реВ рд╢рдХрддреЗ тАФ campus рдЪрд╛ рдирдВрдмрд░ рдЕрд╕рд▓реЗрд▓реЗ рдПрдХ desk, рдЬреЗ рдереЗрдЯ рддреНрдпрд╛ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рд╢реА рдмреЛрд▓рддреЗ. рддреНрдпрд╛ рдЦрд┐рдбрдХреАрдЪреЗ рднрд╛рдбреЗ рддрд╛рд╕рд╛рдкреНрд░рдорд╛рдгреЗ рд▓рд╛рдЧрддреЗ.

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

flowchart LR
    app["ЁЯЦея╕П app wing<br/>rt-private-a"]
    data["ЁЯЧДя╕П data wing<br/>rt-data"]
    nat["ЁЯЪк nat-a<br/>paid per GB"]
    vpce["ЁЯЪЗ vpce-s3<br/>gateway endpoint ┬╖ free"]
    s3["ЁЯкг S3 52.219.40.10"]
    app -->|"pl-s3 beats 0.0.0.0/0"| vpce
    data -->|"pl-s3 тАФ the only way out"| vpce
    vpce --> s3
    app -.->|"without the endpoint"| nat -.-> s3

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

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг private wing рдордзрд▓реЗ рд╕рд░реНрд╡рд╛рдд рдореЛрдареЗ traffic рд╕рд╣рд╕рд╛ S3 рдЪреЗ рдЕрд╕рддреЗ тАФ backups, logs, data files тАФ рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ GB рд╡рд░ NAT рдЪрд╛ рдЯреЛрд▓ рднрд░рдгреЗ рд╢рд╛рдВрддрдкрдгреЗ рд╡рд╛рдврдд рдЬрд╛рддреЗ. рдЖрдгрд┐ рдХрд╛рд░рдг internet route рдЕрдЬрд┐рдмрд╛рдд рдирд╕рд▓реЗрд▓реНрдпрд╛ data wing рд▓рд╛ рд╕реБрджреНрдзрд╛ S3 рдЖрдгрд┐ рдХрд╛рд╣реА AWS APIs рд▓рд╛рдЧрддрд╛рдд: endpoints рддреНрдпрд╛рд▓рд╛ рдиреЗрдордХреЗ рддреЗрд╡рдвреЗрдЪ рджреЗрддрд╛рдд, рдЖрдгрд┐ рджреБрд╕рд░реЗ рдХрд╛рд╣реАрдЪ рдирд╛рд╣реА.

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

vpc/demo.py рдордзрд▓реЗ PL = {"pl-s3": ["52.219.0.0/16", "3.5.0.0/16"]} рд╣реЗ S3 prefix list рдЪреЗ рдПрдХ model рдЖрд╣реЗ (рдЙрджрд╛рд╣рд░рдгрд╛рджрд╛рдЦрд▓ ranges). RouteTable.lookup() pl-s3 рд▓рд╛ рддреНрдпрд╛рдЪреНрдпрд╛ ranges рдордзреНрдпреЗ рдЙрд▓рдЧрдбрддреЗ, рдореНрд╣рдгреВрди 52.219.40.10 рд╣рд╛ 52.219.0.0/16 рд╢реА рдЬреБрд│рддреЛ тАФ рдПрдХ /16, рдЬреЛ 0.0.0.0/0 рдкреЗрдХреНрд╖рд╛ рдЕрдзрд┐рдХ specific рдЖрд╣реЗ тАФ рдЖрдгрд┐ endpoint NAT рд╡рд░ рдЬрд┐рдВрдХрддреЛ. рд╣реЗ рдзрдбрд╛ 04 рдордзрд▓реЗ longest-prefix match рдЪ рдЖрд╣реЗ, рдирд╡реАрди рдХрд╛рд╣реАрдЪ рдирд╛рд╣реА.

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

python3 vpc/demo.py endpoints
python3 - <<'EOF'
import sys; sys.path.insert(0, "vpc")
from demo import campus, PL
c = campus()
for rt in ("rt-private-a", "rt-data"):
    c.rts[rt].routes = [r for r in c.rts[rt].routes if r[0] != "pl-s3"]   # delete the endpoint route
    print(rt.ljust(13), "S3 via", c.rts[rt].lookup("52.219.40.10", PL))
EOF

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

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

   rt-private-a  тЖТ S3 52.219.40.10 via pl-s3 тЖТ vpce-s3
   rt-data       тЖТ S3 52.219.40.10 via pl-s3 тЖТ vpce-s3

рддреБрдордЪрд╛ snippet рдмреЛрдЧрджрд╛ рдХрд╛рдвреВрди рдЯрд╛рдХрддреЛ рдЖрдгрд┐ rt-private-a S3 via ('0.0.0.0/0', 'nat-a') рдЫрд╛рдкрддреЛ тАФ app wing рдЕрдЬреВрдирд╣реА S3 рдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪрддреЛ, рдкрдг рдЖрддрд╛ рдкреИрд╕реЗ рдШреЗрдгрд╛рд▒реНрдпрд╛ рдмрд╛рдЬреВрдЪреНрдпрд╛ рджрд╛рд░рд╛рддреВрди тАФ рдЖрдгрд┐ rt-data S3 via (None, None) тАФ data wing S3 рдкрд░реНрдпрдВрдд рдЕрдЬрд┐рдмрд╛рдд рдкреЛрд╣реЛрдЪреВ рд╢рдХрдд рдирд╛рд╣реА.

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

Endpoint рдореНрд╣рдгрдЬреЗ corridor рдЪреНрдпрд╛ рдкрд╛рдЯреАрд╡рд░рдЪреА рдлрдХреНрдд рдПрдХ рдЕрдзрд┐рдХ specific рдУрд│. рддреА рдЕрд╕реЗрд▓ рддрд░ S3 traffic NAT рдЯрд╛рд│рддреЗ; рддреА рдирд╕реЗрд▓ рддрд░ app wing рдЯреЛрд▓ рднрд░рддреЛ рдЖрдгрд┐ data wing рддреБрдЯрддреЛ.

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

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

рдЬрд╡рд│рдЬрд╡рд│ рдкреНрд░рддреНрдпреЗрдХ VPC рд▓рд╛ рдкрд╣рд┐рд▓реНрдпрд╛рдЪ рджрд┐рд╡рд╢реА S3 рдЖрдгрд┐ DynamoDB gateway endpoints рдорд┐рд│рддрд╛рдд тАФ рдореЛрдлрдд, рдЖрдгрд┐ рддреЗ NAT рдЪреЗ рдмрд┐рд▓ рдХрдореА рдХрд░рддрд╛рдд. рдлрдХреНрдд private рдЕрд╕рд▓реЗрд▓реЗ VPCs ECR, STS, CloudWatch Logs рдЖрдгрд┐ Secrets Manager рд╕рд╛рдареА interface endpoints рдЬреЛрдбрддрд╛рдд, рдХрдзреА рдХрдзреА рддрд╛рд╕рд╛рдЪрд╛ рдЦрд░реНрдЪ рд╡рд╛рдЪрд╡рдгреНрдпрд╛рд╕рд╛рдареА рдПрдХрд╛ рдордзреНрдпрд╡рд░реНрддреА VPC рдордзреВрди share рдХрд░реВрди.

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

aws ec2 create-vpc-endpoint --vpc-id vpc-0123456789abcdef0 --vpc-endpoint-type Gateway \
    --service-name com.amazonaws.ap-south-1.s3 \
    --route-table-ids rtb-0app000000000000a rtb-0data00000000000a
aws ec2 create-vpc-endpoint --vpc-id vpc-0123456789abcdef0 --vpc-endpoint-type Interface \
    --service-name com.amazonaws.ap-south-1.ecr.api \
    --subnet-ids subnet-0a subnet-0b subnet-0c --security-group-ids sg-0endpoints00000a \
    --private-dns-enabled
aws ec2 describe-prefix-lists --query 'PrefixLists[].[PrefixListId,PrefixListName]' --output table

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

Interface endpoint рдЪрд╛рд▓рд▓рд╛ рдХрд╛рд░рдг рдПрдХрд╛ рдирд╛рд╡рд╛рдЪреЗ private рдкрддреНрддреНрдпрд╛рдд рд░реВрдкрд╛рдВрддрд░ рдЭрд╛рд▓реЗ. рддреА рдирд╛рд╡реЗ рдХреЛрдг рд╕рд╛рдВрдЧрддреЗ? VPC рдордзрд▓реЗ DNS тАФ campus рдЪреА phone book.

git checkout lesson-08-dns

ЁЯЪЗ Lesson 07 тАФ VPC endpoints: a private tunnel to AWS services

ЁЯУН You are here: Lesson 07 of 12 ┬╖ Previous: lesson-06-sg-vs-nacl ┬╖ Next: lesson-08-dns


ЁЯУж What's in this branch

The whole campus of Part 1, plus the first way out that is not a gate: a gateway endpoint for S3. In campus() (vpc/demo.py) both private route tables carry pl-s3 тЖТ vpce-s3; endpoints() shows where S3 traffic goes from the app wing (which also has a NAT) and from the data wing (which has nothing else).

ЁЯзТ Explain like I'm 5

The school keeps its old exam papers in a giant city archive ЁЯЧДя╕П тАФ that is S3. The archive is outside the campus fence.

The app wing could send a runner out through the side gate (the NAT), down the city street, to the archive. It works тАФ but every trip costs a toll, and the runner is out on the street.

So the school digs a private tunnel ЁЯЪЗ from its own campus straight into the archive. The corridor sign gets one new line: "archive тЖТ the tunnel". Now the runner never leaves AWS, and this tunnel is free. Even the data wing, which has no gate at all, can reach the archive through it.

For other offices in the city (queues, secrets, container images) the school can put a small private window ЁЯкЯ right inside its own wing тАФ a desk with a campus number that talks straight to that office. That window has a rent, by the hour.

ЁЯЧ║я╕П Diagram

flowchart LR
    app["ЁЯЦея╕П app wing<br/>rt-private-a"]
    data["ЁЯЧДя╕П data wing<br/>rt-data"]
    nat["ЁЯЪк nat-a<br/>paid per GB"]
    vpce["ЁЯЪЗ vpce-s3<br/>gateway endpoint ┬╖ free"]
    s3["ЁЯкг S3 52.219.40.10"]
    app -->|"pl-s3 beats 0.0.0.0/0"| vpce
    data -->|"pl-s3 тАФ the only way out"| vpce
    vpce --> s3
    app -.->|"without the endpoint"| nat -.-> s3

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

тЭУ What

ЁЯдФ Why

Because S3 is usually the biggest traffic from a private wing тАФ backups, logs, data files тАФ and paying the NAT toll on every GB adds up quietly. And because a data wing with no internet route at all still needs S3 and a few AWS APIs: endpoints give it exactly that, and nothing else.

ЁЯФз How (in this repo)

PL = {"pl-s3": ["52.219.0.0/16", "3.5.0.0/16"]} in vpc/demo.py is a model of the S3 prefix list (example ranges). RouteTable.lookup() expands pl-s3 into its ranges, so 52.219.40.10 matches 52.219.0.0/16 тАФ a /16, more specific than 0.0.0.0/0 тАФ and the endpoint wins over the NAT. That is longest-prefix match from lesson 04, nothing new.

ЁЯзк Try it

python3 vpc/demo.py endpoints
python3 - <<'EOF'
import sys; sys.path.insert(0, "vpc")
from demo import campus, PL
c = campus()
for rt in ("rt-private-a", "rt-data"):
    c.rts[rt].routes = [r for r in c.rts[rt].routes if r[0] != "pl-s3"]   # delete the endpoint route
    print(rt.ljust(13), "S3 via", c.rts[rt].lookup("52.219.40.10", PL))
EOF

тЬЕ Verify тАФ what you should see

endpoints prints:

   rt-private-a  тЖТ S3 52.219.40.10 via pl-s3 тЖТ vpce-s3
   rt-data       тЖТ S3 52.219.40.10 via pl-s3 тЖТ vpce-s3

Your snippet removes the tunnel and prints rt-private-a S3 via ('0.0.0.0/0', 'nat-a') тАФ the app wing still reaches S3, but now through the paid side gate тАФ and rt-data S3 via (None, None) тАФ the data wing cannot reach S3 at all.

ЁЯПБ What you just proved

An endpoint is just a more specific line on the corridor sign. With it, S3 traffic skips the NAT; without it, the app wing pays the toll and the data wing is cut off.

тЪая╕П Common mistakes

ЁЯПн In production

Almost every VPC gets the S3 and DynamoDB gateway endpoints on day one тАФ free, and they cut NAT bills. Private-only VPCs add interface endpoints for ECR, STS, CloudWatch Logs and Secrets Manager, sometimes shared from one central VPC to save the hourly cost.

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

aws ec2 create-vpc-endpoint --vpc-id vpc-0123456789abcdef0 --vpc-endpoint-type Gateway \
    --service-name com.amazonaws.ap-south-1.s3 \
    --route-table-ids rtb-0app000000000000a rtb-0data00000000000a
aws ec2 create-vpc-endpoint --vpc-id vpc-0123456789abcdef0 --vpc-endpoint-type Interface \
    --service-name com.amazonaws.ap-south-1.ecr.api \
    --subnet-ids subnet-0a subnet-0b subnet-0c --security-group-ids sg-0endpoints00000a \
    --private-dns-enabled
aws ec2 describe-prefix-lists --query 'PrefixLists[].[PrefixListId,PrefixListName]' --output table

тПня╕П Next

The interface endpoint worked because a name turned into a private address. Who answers those names? DNS inside the VPC тАФ the campus phone book.

git checkout lesson-08-dns
тЖР Previoussg vs naclNext тЖТdns

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