The AI-sandbox VPC has nine subnets and nine route tables (one per subnet). Three of the tables have no default route to the internet by design — that is the lockbox isolation guarantee, expressed in routing rather than in policy. This document walks each table, shows what it routes where, and explains why the route table layer is the strongest place to enforce "lockbox cannot reach the internet."
Lockbox subnets have no 0.0.0.0/0 route in any route table. The internet is not unreachable because of a policy decision — it is unreachable because there is no route to take. Firewalls, security groups, and IAM are layered on top, but the routing layer is the floor.
Each route table belongs to exactly one of three patterns. The pattern is determined by the subnet it is associated with.
| Tier | Subnets (3 AZs) | Default route | Internet reachable from workloads here? |
|---|---|---|---|
| Agent | ai-sandbox-agent-private-us-east-1a...-1b...-1c | 0.0.0.0/0 → NFW endpoint | Yes — via NFW → NAT → IGW |
| Lockbox | ai-sandbox-lockbox-private-us-east-1a...-1b...-1c | (no default route) | No. Structurally impossible. |
| Egress | ai-sandbox-egress-us-east-1a...-1b...-1c | 0.0.0.0/0 → IGW | Yes — directly. This is the only tier with an IGW route. |
| Destination | Target | What it does |
|---|---|---|
10.0.0.0/16 | local (implicit) | Traffic inside the VPC stays inside; never leaves. |
0.0.0.0/0 | vpce-0119843d5454e1ed0 (NFW endpoint) | Default route. Every packet not bound for the VPC itself goes to the Network Firewall first. |
| S3 prefix list | vpce-04ccfcc0152402128 (S3 gateway endpoint) | S3 traffic skips NFW, goes private via the gateway endpoint. Free. |
| DDB prefix list | vpce-0675c4f8582974d54 (DDB gateway endpoint) | DynamoDB traffic skips NFW, goes private via the gateway endpoint. Free. |
Without the gateway endpoint routes, S3 and DDB traffic would match 0.0.0.0/0 and route through NFW → NAT → IGW — paying NAT data charges, generating NFW alerts, and traversing the public internet to reach an AWS service. Adding the prefix-list routes keeps the traffic private and cheap.
| Destination | Target | What it does |
|---|---|---|
10.0.0.0/16 | local (implicit) | Traffic inside the VPC stays inside. |
0.0.0.0/0 | (no entry — intentional) | No default route. Packets destined for the internet have no target. |
| S3 prefix list | vpce-04ccfcc0152402128 (S3 gateway endpoint) | S3 traffic goes private. |
| DDB prefix list | vpce-0675c4f8582974d54 (DDB gateway endpoint) | DDB traffic goes private. |
0.0.0.0/0 entry exists. A packet from a lockbox workload destined for the public internet has nowhere to route. The internet is unreachable at the routing layer.Three independent failure modes are eliminated by removing the route rather than blocking at the firewall:
*:* IAM permissions and still cannot egress.Every one of those layers exists too — defense in depth — but each could in principle be misconfigured. The routing layer is what is left when every other layer is bypassed: there is simply no path for the packet.
When the doctrine says "lockbox cannot reach the internet," this is what it means. Not "the firewall blocks it." Not "the SG denies it." There is no route. Bypassing every other control still leaves you with a packet that has no next hop.
| Destination | Target | What it does |
|---|---|---|
10.0.0.0/16 | local (implicit) | Traffic inside the VPC stays inside. |
0.0.0.0/0 | igw-0c71813f4d0c94a01 (Internet Gateway) | Default route. This is the only tier that points 0.0.0.0/0 at the IGW. |
S3 and DDB traffic originating from the egress subnet should be vanishingly rare (NFW endpoint is the only workload). If it does happen (NFW or NAT making AWS API calls), it goes through the public path. Adding gateway endpoint routes here would be unused complexity.
api.salesforce.com (allowed in alert mode, allowed in drop mode)Agent ENI in agent-private subnet
|
v
Agent route table: 0.0.0.0/0 → NFW endpoint
|
v
NFW endpoint ENI in egress subnet, us-east-1a
| (TLS SNI inspected: matches stateful allowlist for *.salesforce.com)
v
Egress route table: 0.0.0.0/0 → IGW (after NFW forwards)
| (but actually, NFW post-inspection traffic goes through NAT first)
v
NAT Gateway in egress subnet
| (source-NAT to EIP)
v
IGW
|
v
Public internet → api.salesforce.com
httpbin.org (alert mode: succeeds; drop mode: blocked)Agent ENI → NFW endpoint
| (TLS SNI inspected: does NOT match allowlist)
|
| ALERT MODE: stateful default action = alert_strict
| — alert log entry created
| — traffic still forwarded to NAT
|
| DROP MODE: stateful default action = drop_strict + alert_strict
| — alert log entry created
| — packet dropped at NFW endpoint
| — TCP timeout from caller's perspective
api.gitbook.comLockbox ENI in lockbox-private subnet
|
v
Lockbox route table: 10.0.0.0/16 → local
| (no other route matches the destination IP)
|
v
Packet has no next hop. Dropped at the VPC level.
This is independent of NFW, SG, IAM. There is no path.
Agent ENI → bedrock-runtime endpoint ENI (in same agent subnet)
|
v
Bedrock VPC endpoint
|
v
AWS Bedrock service plane (private; no internet hop)
Agent ENI in agent-private subnet
|
v
Agent route table: DDB prefix list → DDB gateway endpoint
|
v
DDB gateway endpoint policy: "may access table/ai-sandbox-agent-*"
|
v
DynamoDB service plane
Lockbox table: agent attempting this path gets AccessDenied from the
gateway endpoint policy, before the DDB API is even consulted.
See Step.3.db-access-boundaries.html for the full layer stack.
┌─────────────────────────────── ai-sandbox VPC (10.0.0.0/16) ───────────────────────────┐
│ │
│ ┌─ AGENT TIER (3 AZs) ────────┐ ┌─ LOCKBOX TIER (3 AZs) ───┐ ┌─ EGRESS TIER ──┐ │
│ │ agent-private-1a (/22) │ │ lockbox-private-1a (/24) │ │ egress-1a │ │
│ │ agent-private-1b (/22) │ │ lockbox-private-1b (/24) │ │ egress-1b │ │
│ │ agent-private-1c (/22) │ │ lockbox-private-1c (/24) │ │ egress-1c │ │
│ │ │ │ │ │ │ │
│ │ routes: │ │ routes: │ │ routes: │ │
│ │ • 10.0.0.0/16 → local │ │ • 10.0.0.0/16 → local │ │ • 10.0.0.0/16│ │
│ │ • 0.0.0.0/0 → NFW endpoint │ │ • (no 0.0.0.0/0) │ │ → local │ │
│ │ • S3 prefix → S3 GW EP │ │ • S3 prefix → S3 GW EP │ │ • 0.0.0.0/0 │ │
│ │ • DDB prefix → DDB GW EP │ │ • DDB prefix → DDB GW EP │ │ → IGW │ │
│ └─────────────────────────────┘ └───────────────────────────┘ └───────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
│
┌─ Internet Gateway (igw-0c71813f4d0c94a01)
│ reached only from egress route tables
▼
Public internet
The route tables are the strongest single artifact of the lockbox isolation doctrine. They are also one of the easiest things to read in the Console — each table is a short list of destination/target rows.
| What | Where to look | What to see |
|---|---|---|
| All 9 route tables in the VPC | VPC → Route tables → filter by VPC vpc-0ed3a16a8b82f7a34 |
Nine rows. Names match the pattern ai-sandbox-rt-{tier}-{az}. Three each of agent, lockbox, egress. |
| The structural lockbox isolation | Filter Name = ai-sandbox-rt-lockbox → click any one → Routes tab |
Three or four entries total: local route, S3 prefix list, DDB prefix list. No 0.0.0.0/0 entry. Compare to any agent or egress route table where 0.0.0.0/0 appears prominently. This is the visual proof that lockbox cannot reach the internet at the routing layer. |
| The agent default route to NFW | Filter Name = ai-sandbox-rt-agent → click any one → Routes tab |
0.0.0.0/0 destination, target column shows vpce-0119843d5454e1ed0 (the NFW endpoint ID). Hovering on the target shows the endpoint name. |
| The egress direct IGW route | Filter Name = ai-sandbox-rt-egress → click any one → Routes tab |
0.0.0.0/0 destination, target column shows the IGW igw-0c71813f4d0c94a01. Only the egress tables have this. Confirms the egress tier is the only subnet that can directly reach the internet. |
| Subnet associations | Any route table → Subnet associations tab | Each route table is associated to exactly one subnet. Confirms the per-subnet routing model — no subnet falls back to the main route table or shares a route table with a different tier. |
VPC → click ai-sandbox-vpc → Resource map tab. AWS draws the entire VPC graph. Route tables appear between subnets and their downstream targets (IGW, NFW endpoint, NAT). The visual is reading-time-equivalent to reading the table rows above, but easier to absorb. The lockbox subnets visibly do not have an arrow leading to the IGW — the doctrine, as a picture.
Someone reports "a lockbox workload reached out to an unauthorized external endpoint." First place to check: the lockbox route table for the affected AZ. If 0.0.0.0/0 is still absent (the structural property is intact), then either the traffic was misattributed, or it went through a different mechanism (an interface endpoint, a service-link path), or someone has been editing route tables manually. The Console's route table page is the first stop in that triage.
# All 9 route tables in this VPC
AWS_PROFILE=ai-sandbox aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-0ed3a16a8b82f7a34" \
--query 'RouteTables[].{Name:Tags[?Key==`Name`].Value|[0],Routes:Routes}' \
--output json
# Verify lockbox tables have NO 0.0.0.0/0 entry
AWS_PROFILE=ai-sandbox aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-0ed3a16a8b82f7a34" \
--query 'RouteTables[?Tags[?Key==`Name`&&starts_with(Value, `ai-sandbox-rt-lockbox`)]].Routes[?DestinationCidrBlock==`0.0.0.0/0`]' \
--output text
# Expected: empty (no routes returned). If any rows print, that is a doctrine violation.
# Verify agent tables route 0.0.0.0/0 to the NFW endpoint
AWS_PROFILE=ai-sandbox aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-0ed3a16a8b82f7a34" \
--query 'RouteTables[?Tags[?Key==`Name`&&starts_with(Value, `ai-sandbox-rt-agent`)]].Routes[?DestinationCidrBlock==`0.0.0.0/0`].GatewayId' \
--output text
# Expected: three lines (one per AZ), all matching the NFW endpoint vpce-* ID.