Ask anyone whether their desk on the 14th floor is accessible directly from the street and they’ll say no. Nobody can enter from outside and walk straight to your desk. But that’s a different question from whether your desk can be reached at all. Getting there just means passing a series of checks, a door, a front desk, an elevator, each one deciding whether to let you through. Every one of them is a route to your desk, whether they’re supposed to be or not.
This situation shows up in cloud and Kubernetes environments, and why “private” keeps getting mistaken for “safe.” Not sitting directly on the internet gets treated the same way as your desk not opening straight onto the street, sealed off like a vault rather than sitting somewhere a determined enough route could still reach. It seems like a safe assumption until someone finds the path in. Old-school security worked like this was true.
Scanners were producing hundreds of CVEs, with severity scores that rarely lined up with the real risk, so teams started asking if attackers could actually reach their code. Reachability analysis cut the noise significantly, but fully answering the question has proved more difficult.
Why k8s makes the checkbox lie
Most reachability checks collapse to one question: does this resource have a public IP? 0.0.0.0/0 on the resource itself. If not, a "private subnet" gets treated as the full answer: not reachable. That catches an open SSH port on a public virtual machine (VM). It says nothing about how traffic actually enters a cluster.
This current approach to reachability falls apart in Kubernetes, where traffic enters through several layered components, rather than hitting one machine directly.
Take the example path: Internet → cloud LB → Ingress or Gateway API → ClusterIP Service → Pod → something the pod can talk to (RDS, Redis, another ns)
A request from the internet passes through a chain of handoffs before reaching anything.
The pod itself has no public IP. In fact, every single link in the chain looks self-contained. But only tracing the whole thing end-to-end reveals an entry path.
Then there is inherited trust. For instance, a private database that doesn’t have a public IP and sits in a network segment without internet access. It’s reachable from the app because the database’s firewall rule explicitly permits traffic from the app’s own firewall group. Say the app is running a container image with a known, unpatched CVE, exactly the kind of finding that gets exploited to gain a foothold.
The database is like a locked room down the hall. Its door admits people arriving from the app’s office, but not from the street. If an attacker takes control of the app, they can get as far as that door; accessing the data may still require a separate key. Typical analysis would show that this database is not internet-facing, and therefore safe, but since the app can reach it, so can an attacker exploiting the app's compromise. What's actually worth worrying about is the CVE in the app, not whether the database has a public IP.
And finally, there’s forgotten permission. If a team locked down the LoadBalancer Service and left an Ingress with a broad host rule, think of it as bolting down the front entrance and never noticing a backdoor had been propped open from a delivery earlier that week. ClusterIP looks safe in kubectl get svc, even though traffic is still arriving via the Ingress that wasn’t checked.
All three of these examples show that reachability, while useful, only goes so far in its current guise. There needs to be more depth built into it.
A reachability test
Take any entry point (a load balancer, an Ingress rule, a function URL) and ask what it leads to two hops in. If that's not already known, whatever's doing the reachability analysis stopped short.
The same test applies to ports. For the highest-severity CVEs, does the path actually reach the port the vulnerability needs, or just a port on the same machine? Just saying "yes, it's reachable" doesn’t provide the context.
Concluding thoughts
Reachability was the right idea, but depth should be the focus now: hops, ports, and what sits behind the workload. It’s a zero-trust principle that getting through one door shouldn’t give you a free pass through the next. A tool that only checks for a public IP is still asking whether your desk on the fourteenth floor is accessible directly from the street. It can’t tell you whether the locked room down the hall trusts whoever got past your desk, or whether the backdoor was left open.
KubeCon + CloudNativeCon is taking place in Salt Lake City from November 9 to 12. Register Now!
Comments