Essay · Cloud Security

A Private Subnet Is a Routing Concept, Not a Security Boundary

Put a workload in a private subnet and the diagram feels safer. But "private" is a statement about routing — no direct route to an internet gateway — not a security boundary. The boundary is the reachable graph: the paths, identities, and policies the label never draws.

Published September 21, 2026 Topic Cloud routing vs. security boundaries

Put an application server in a private subnet and the architecture diagram immediately feels safer. The box moves behind the public tier, the address space is private, there is no direct route to the internet gateway, and another boundary line appears between the workload and the outside world.

There is good reason for that. Removing direct internet exposure is useful. Workloads that do not need public addresses should not have them, and application or data tiers rarely benefit from being directly reachable from the internet. The problem begins when the word private starts carrying more meaning than the routing table actually provides.

AWS's VPC User Guide defines the terms plainly. A public subnet has a direct route to an internet gateway. A private subnet does not. AWS separately defines an isolated subnet as one with no routes to destinations outside its VPC, whose resources can only reach or be reached by other resources in the same VPC. Those definitions are worth reading closely, because they tell you what each label actually describes. A private subnet is a statement about routing. It is not, by itself, a security boundary.

What private actually tells you

Consider a simple EC2 workload in a subnet with no route directly to an internet gateway. By AWS's definition, that subnet is private. Now add a default route to a NAT gateway. Nothing about the classification changes. The subnet is still private, because the instances inside it have no direct route through an internet gateway, and a system on the public internet cannot use the NAT gateway to initiate a connection inward.

The workload, however, can initiate connections outward. That is one of the normal reasons to run a NAT gateway. A server can retrieve packages, contact an external API, send telemetry, or reach another internet service while staying unreachable from unsolicited inbound connections along that path. Those are useful properties, and they are different properties. Not directly reachable from the internet does not mean unable to reach the internet. The first is about ingress. The second is about reachability, and the word private only ever promised the first.

Remove the NAT gateway and the picture still does not become simple. The workload can communicate through the VPC's local routes. Add peering and another VPC becomes reachable. Add a transit gateway and the topology may extend across VPCs, accounts, regions, or an on-premises environment. Add gateway endpoints and the workload can reach services such as S3 or DynamoDB without touching the public internet at all. Add interface endpoints and PrivateLink and the set of privately reachable services expands again. An application in a private subnet can also sit behind an internet-facing load balancer, so the instances stay private by the routing definition while outside users interact with the application through the balancer. None of this contradicts the definition. A private subnet never promised that none of these paths would exist.

The diagram is where the trouble starts

I have spent enough time building and troubleshooting AWS environments that the word private on a diagram no longer tells me much on its own. The first thing I want is the route table. The next thing I want is the identity the workload carries, because cloud security does not stop at network reachability. An EC2 instance with an attached role can act on AWS services through APIs even when its packet-level exposure looks tightly constrained. A workload with access to an S3 endpoint may not need any general internet connectivity to move data into a bucket, and whether that move succeeds depends on the IAM role, the endpoint policy, and the bucket policy, not on the subnet label.

This is where cloud diagrams become misleading without being wrong. They show network placement well and show consequence poorly. A box inside a green area marked PRIVATE looks contained, but the question I actually care about is not whether the subnet carries that label. It is what a workload placed there can reach or cause, using the network paths and identities available to it. That question takes longer to answer, and it is the one that matters after something goes wrong.

Walk the graph from the compromised workload

Suppose an application server in a private subnet is compromised. It is tempting to call the blast radius limited because the server is private. That may turn out to be true, but the subnet label does not establish it.

Start with egress. If the host can reach a NAT gateway, the compromised process may be able to open outbound internet sessions, which creates room for command and control, retrieval of more tooling, or data movement depending on the other controls in place. If NAT is absent, ask what private paths remain: internal databases, shared services, a management network, an internal proxy, a peered VPC, a transit gateway, a service endpoint. Then look at identity. Does the instance have an IAM role, what APIs can it call, and over which resources? Permissions on S3, Secrets Manager, Systems Manager, or KMS can matter far more than ordinary packet reachability.

Credentials change what a path is worth. Reaching an internal service is uninteresting if the service strongly authenticates and authorizes the caller, and a narrow network path can become very powerful if the workload identity is allowed to perform sensitive operations once the connection succeeds. The reverse holds too. A broad network route does not mean every reachable resource is compromised, because security groups, service authentication, resource policies, and application authorization can still constrain what happens. That is why I have stopped reading the boxes as the architecture. What I read now is the edges, the paths and identities that let a workload reach or cause something.

Network reachability is only one plane

Traditional network architecture trains us to think in paths between systems, and those paths still matter enormously in the cloud. The cloud adds additional planes of consequence on top of network reachability. A workload can act on infrastructure through service APIs, role credentials, endpoints, control planes, managed services, and resource policies, so its security emerges from several controls working together. Route tables answer where packets are directed. Security groups and network ACLs constrain packet flows. IAM answers what an identity may request. Endpoint and resource policies narrow what certain service paths will accept. Application authorization decides what the service permits once the request arrives. These are different controls answering different questions, and a subnet classification cannot stand in for all of them.

This is why a workload can be well designed from a routing perspective and still carry excessive consequence. The network team can correctly remove public ingress while an IAM role still grants broad access to storage. The IAM team can correctly constrain a role while an internal network path exposes a sensitive service that trusts its source network too broadly. Neither finding means the other control failed. The boundary was never a single control that one team owned. It was composed from several controls that only hold when they hold together.

Private still matters

None of this is an argument against private subnets. Removing unnecessary public exposure is one of the easiest architectural decisions to defend, there is little reason to give a workload a public address or direct internet path it does not need, and layering public ingress, application processing, and data services across appropriate tiers is still good architecture. A private subnet removes a class of paths that often should not exist. The mistake is treating the removal of that class as proof of isolation.

Even isolated should be read carefully. AWS's definition is stronger than private, but it is still a statement about routing. It does not tell you the permissions, services, credentials, or consequences available to the workloads inside. Precision keeps the architecture honest. There is a real difference between claiming a workload has no direct internet route, claiming it has no outbound internet path, and claiming it cannot reach anything outside its application tier. Each claim is stronger than the last and needs more to back it: the first is a line in the route table, the last requires peering, endpoints, and DNS to all agree. And isolated means nothing until I say which isolation I mean, network, service, or identity.

The reason I run these same questions in a design review, before anything has gone wrong, is that the review and the compromise walk are the same walk. In both I am asking what a workload here could reach or cause if it stopped behaving the way the application intended. A green PRIVATE box does not answer that. The route table, the identity, and the policies do. The label is still useful, as metadata about one part of the graph, but it is not a summary of the whole thing.

The boundary is the reachable graph

This is not only an AWS lesson. We draw systems as boxes because boxes make architecture legible, and networks, containers, namespaces, accounts, and trust zones all become clean shapes with lines around them. The risk is starting to believe the line is the boundary. The boundary is the set of capabilities allowed to cross that line and the controls that decide what happens when they do. Cloud infrastructure only makes it obvious, because the paths multiply so quickly: a workload can have no public IP and still have internet egress, no internet access and still reach powerful cloud services, or a private subnet and still serve application traffic that originated on the public internet through another tier.

None of that makes private subnets useless. A private subnet is a real and useful statement about routing, and it is only that. The security boundary is the rest of the graph, the paths and identities and policies the label was never able to draw, and establishing it is the part of the job the diagram hands back to you.


Subnet definitions are from the Amazon VPC User Guide, "Subnets for your VPC".