Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions _posts/2026-05-25-enforced-trust-zones-microsegmentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
---
title: "Enforced Trust Zones: Microsegmentation for When Identity Is Not Enough"
description: "Identity-based Zero Trust verifies who is talking. It does not stop a compromised host from talking to everything. Network-segmented trust zones, NACLs at every boundary, and protocol break at an edge control zone are the defense-in-depth layer that contains lateral movement when an identity is already inside."
date: 2026-05-25 12:00:00 +0000
categories: [Security, Zero Trust]
tags: [zero-trust, microsegmentation, network-segmentation, trust-zones, security, networking]
image:
path: /assets/img/posts/enforced-trust-zones/hero.svg
alt: "A flat network where one compromised host reaches everything, contrasted with segmented trust zones whose boundaries are guarded by NACLs and an edge control zone that breaks and re-originates traffic"
---

There is a sentence I hear in almost every security review, and it makes me nervous every time: **"we moved to Zero Trust, so the network does not matter anymore."** The idea is seductive. If every call is authenticated and authorized on identity, why care which subnet a packet came from? I made a version of this argument myself, on stage at [RSAC 2026](/2026/03/30/rsac-2026-beyond-zero-trust.html). And then I spent the back half of that talk walking it back, because the room kept asking the same uncomfortable question: what happens after one host is already compromised?

This post is the technical companion to the network-segmentation half of that talk. The earlier writing on building a Zero Trust enforcement point with a [reverse proxy](/2025/08/03/zero-trust-with-reverse-proxy.html) and the [control plane that backs it](/2025/10/20/zero-trust-control-plane-and-sessions.html) was about who is allowed to talk to what. This one is about the layer underneath: the network itself refusing to carry traffic it was never asked to carry, so that an attacker who wins one box does not inherit the whole estate.

## The Flat Network Is the Silent Failure Mode

Start with the architecture almost everyone actually runs, whatever the slide deck says. One large network. Every host can reach every other host on every port that a firewall did not explicitly close. Identity is checked at the application layer, which feels like enough.

It is not enough, and the reason is the gap between **authentication** and **reachability**. Identity tells you who is making a request. It says nothing about whether two machines should be able to exchange a single packet in the first place. On a flat network, reachability is total by default, and identity is the only thing standing between an attacker and the rest of your fleet.

So picture the failure. A single host falls: a vulnerable dependency, a phished credential, a misconfigured service. On a flat network, that host can now scan every other host, knock on every open port, and pivot. The attacker does not need to beat your identity layer everywhere at once. They need one foothold, and then the network itself hands them the map.

<div style="border-radius:8px;overflow:hidden;margin:1.5em 0;box-shadow:0 1px 6px rgba(0,0,0,0.15);">
<div style="padding:7px 14px;background:#0f172a;display:flex;align-items:center;gap:8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
<span style="font-family:system-ui,sans-serif;font-size:11px;color:#94a3b8;font-weight:500;letter-spacing:0.3px;">lateral movement on a flat network</span>
</div>
<pre style="margin:0;padding:16px 18px;background:#1e293b;overflow-x:auto;"><code style="font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;font-size:13px;color:#e2e8f0;line-height:1.65;"><span style="color:#64748b;"># attacker owns one web host: 10.0.4.17</span>
<span style="color:#64748b;"># every other host is one hop away, because nothing forbids it</span>

attacker@web-01 $ nmap -sS 10.0.0.0/16 -p 22,3306,6379,5432
Nmap scan report for db-primary.internal (<span style="color:#a3e635;">10.0.9.3</span>)
3306/tcp <span style="color:#f87171;">open</span> mysql <span style="color:#64748b;"># reachable. should it be?</span>
Nmap scan report for cache-01.internal (<span style="color:#a3e635;">10.0.9.8</span>)
6379/tcp <span style="color:#f87171;">open</span> redis <span style="color:#64748b;"># no auth, no segmentation, no limit</span>
Nmap scan report for secrets.internal (<span style="color:#a3e635;">10.0.2.5</span>)
22/tcp <span style="color:#f87171;">open</span> ssh

<span style="color:#64748b;"># identity was never the thing keeping these apart. nothing was.</span></code></pre>
</div>

This is the part identity-based Zero Trust does not address, and the part its loudest advocates sometimes wave away. A stolen identity is a real threat, but so is a workload that was never compromised at the identity layer at all, just reachable. Microsegmentation is the answer to reachability, and reachability is a network property.

## Trust Zones: L2/L3 Isolation as the Baseline

The fix is to stop treating the network as one space. You carve it into **trust zones**, where a zone is a group of workloads that share a security posture and a blast-radius budget. The web tier is one zone. The data tier is another. Admin and management planes are their own zones. The principle is simple: a compromise in one zone should not automatically become a compromise in another.

Crucially, a trust zone is not a tag or a label that lives only in policy. It is enforced at L2 and L3. Each zone gets its own **dedicated VLAN** and a **unique, non-overlapping subnet**. That isolation is what makes the boundary real rather than aspirational. Two workloads in different zones are not on the same broadcast domain, and traffic between their subnets has to be routed, which means it has to pass a point where you can inspect and deny it.

<div style="border-radius:8px;overflow:hidden;margin:1.5em 0;box-shadow:0 1px 6px rgba(0,0,0,0.15);">
<div style="padding:7px 14px;background:#0f172a;display:flex;align-items:center;gap:8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span style="font-family:system-ui,sans-serif;font-size:11px;color:#94a3b8;font-weight:500;letter-spacing:0.3px;">trust-zone layout</span>
</div>
<pre style="margin:0;padding:16px 18px;background:#1e293b;overflow-x:auto;"><code style="font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;font-size:13px;color:#e2e8f0;line-height:1.65;">zone: edge-control vlan: <span style="color:#f0abfc;">10</span> subnet: <span style="color:#a3e635;">10.10.0.0/24</span>
zone: web vlan: <span style="color:#f0abfc;">20</span> subnet: <span style="color:#a3e635;">10.20.0.0/22</span>
zone: app vlan: <span style="color:#f0abfc;">30</span> subnet: <span style="color:#a3e635;">10.30.0.0/22</span>
zone: data vlan: <span style="color:#f0abfc;">40</span> subnet: <span style="color:#a3e635;">10.40.0.0/24</span>
zone: management vlan: <span style="color:#f0abfc;">50</span> subnet: <span style="color:#a3e635;">10.50.0.0/24</span>

<span style="color:#64748b;"># separate VLAN + unique subnet per zone:</span>
<span style="color:#64748b;"># no shared broadcast domain, every cross-zone hop is routed,</span>
<span style="color:#64748b;"># and every routed hop is a place you get to say "no".</span></code></pre>
</div>

The mental model I keep is this: **identity decides who you are, segmentation decides where you can even knock.** A flat network lets everyone knock on every door and relies on the locks. Trust zones take most of the doors away.

## Default-Deny at Every Boundary: NACLs and Host Firewalls

A zone boundary is only worth something if it denies by default. The rule is that **cross-domain access is denied unless explicitly allowed**, and it is enforced in two places, on purpose.

The first is the network boundary: a **NACL** (network access control list) at every zone edge. The NACL is stateless and coarse, evaluated at the subnet boundary, and it encodes the few flows that are supposed to exist between zones. Web may reach app on one port. App may reach data on one port. Everything else, including the lateral scan from the flat-network example, is dropped before it ever reaches a host.

<div style="border-radius:8px;overflow:hidden;margin:1.5em 0;box-shadow:0 1px 6px rgba(0,0,0,0.15);">
<div style="padding:7px 14px;background:#0f172a;display:flex;align-items:center;gap:8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
<span style="font-family:system-ui,sans-serif;font-size:11px;color:#94a3b8;font-weight:500;letter-spacing:0.3px;">NACL at the data-zone boundary</span>
</div>
<pre style="margin:0;padding:16px 18px;background:#1e293b;overflow-x:auto;"><code style="font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;font-size:13px;color:#e2e8f0;line-height:1.65;"><span style="color:#64748b;"># data zone (10.40.0.0/24): explicit allow, then deny all</span>
<span style="color:#f0abfc;">100</span> allow src=<span style="color:#a3e635;">10.30.0.0/22</span> dst=<span style="color:#a3e635;">10.40.0.0/24</span> proto=tcp port=<span style="color:#f0abfc;">5432</span>
<span style="color:#f0abfc;">110</span> allow src=<span style="color:#a3e635;">10.10.0.0/24</span> dst=<span style="color:#a3e635;">10.40.0.0/24</span> proto=tcp port=<span style="color:#f0abfc;">5432</span> <span style="color:#64748b;"># via edge control only</span>
<span style="color:#f0abfc;">900</span> deny src=<span style="color:#a3e635;">0.0.0.0/0</span> dst=<span style="color:#a3e635;">10.40.0.0/24</span> proto=all <span style="color:#64748b;"># default deny</span>

<span style="color:#64748b;"># the web zone (10.20.0.0/22) is not in any allow line.</span>
<span style="color:#64748b;"># a compromised web host simply cannot reach the database.</span></code></pre>
</div>

The second is the **host-level firewall** on every workload, which scopes inbound traffic to exactly the ports that host serves and the sources it expects. This is deliberate redundancy. The NACL guards the boundary between zones; the host firewall guards the host even against its own zone neighbors. If an attacker lands on one app server, a tight host firewall keeps them from freely pivoting to the app server next to it. Two independent layers have to fail before lateral movement succeeds, which is the whole point of defense in depth.

The honest tradeoff: default-deny at this granularity generates real operational work. Every legitimate new flow is a deliberate allow rule, reviewed and recorded. That friction is not a bug. It is the system forcing you to know, and to justify, every path that exists. A flat network has zero friction precisely because it has zero answers to "who is allowed to reach this."

## Protected Lateral Movement: Protocol Break at the Edge Control Zone

Default-deny raises an obvious question: real systems do need some cross-zone traffic. A web request genuinely has to reach data eventually. If you simply punch a NACL hole from web straight to data, you have quietly rebuilt a piece of the flat network: a direct path an attacker can ride.

The answer in the talk was the one I care most about here: **do not let zones talk directly. Route protected flows through an edge control zone, and break the protocol there.** The edge control zone is a thin, hardened, heavily monitored zone whose entire job is to be the only place where two other zones meet. And it does not forward packets. It **terminates** the incoming connection and **re-originates** a brand new one toward the destination.

That distinction, protocol break versus packet passthrough, is the load-bearing idea. A passthrough device forwards the attacker's bytes, framing, and any protocol-level tricks straight through. A protocol break terminates the session, parses it back up to the application layer, applies policy against a fully reconstructed request, and then opens a separate, clean connection it originates itself. The attacker's TCP session dies at the edge. Nothing they crafted at the transport or framing layer survives the gap.

<div style="border-radius:8px;overflow:hidden;margin:1.5em 0;box-shadow:0 1px 6px rgba(0,0,0,0.15);">
<div style="padding:7px 14px;background:#0f172a;display:flex;align-items:center;gap:8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
<span style="font-family:system-ui,sans-serif;font-size:11px;color:#94a3b8;font-weight:500;letter-spacing:0.3px;">protocol break vs passthrough</span>
</div>
<pre style="margin:0;padding:16px 18px;background:#1e293b;overflow-x:auto;"><code style="font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;font-size:13px;color:#e2e8f0;line-height:1.65;"><span style="color:#f87171;">passthrough (bad):</span>
web-host ===== one TCP session, packets forwarded =====&gt; database
attacker framing + payload reaches the DB untouched

<span style="color:#a3e635;">protocol break (good):</span>
web-host --- TCP session A ---&gt; [ EDGE CONTROL ZONE ]
1. terminate session A
2. parse + authorize request
3. re-originate session B
--- TCP session B (new) ---&gt; database

<span style="color:#64748b;"># two separate sessions. session A never touches the database.</span>
<span style="color:#64748b;"># the edge re-originates; the source IP the DB sees is the edge.</span></code></pre>
</div>

This is the same enforcement-point pattern from the [reverse-proxy Zero Trust post](/2025/08/03/zero-trust-with-reverse-proxy.html), turned sideways: instead of standing only at the perimeter facing the internet, the enforcement point also stands between internal zones. Every protected cross-zone flow is mediated, terminated, inspected, and re-originated by something you control and watch closely.

## Policy Enforcement Lives at the Zone Edge

Putting the edge control zone in the path gives you a natural, single place to enforce policy on cross-zone traffic. Because the edge terminates and reconstructs each request, it can apply full policy: identity of the caller, sensitivity of the destination, the specific operation requested, and live risk signals. This is exactly where network segmentation and identity-based Zero Trust meet. The network got the packet to a place it is allowed to be; the policy engine at that place decides whether the actual request is allowed to proceed.

<div style="border-radius:8px;overflow:hidden;margin:1.5em 0;box-shadow:0 1px 6px rgba(0,0,0,0.15);">
<div style="padding:7px 14px;background:#0f172a;display:flex;align-items:center;gap:8px;">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<span style="font-family:system-ui,sans-serif;font-size:11px;color:#94a3b8;font-weight:500;letter-spacing:0.3px;">zone-edge policy decision</span>
</div>
<pre style="margin:0;padding:16px 18px;background:#1e293b;overflow-x:auto;"><code style="font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;font-size:13px;color:#e2e8f0;line-height:1.65;">on cross_zone_request(req):
allow_zone = nacl_permits(req.src_zone, req.dst_zone) <span style="color:#64748b;"># network layer</span>
allow_ident = identity_authorized(req.caller, req.action) <span style="color:#64748b;"># identity layer</span>
allow_risk = risk_score(req.session) &lt; THRESHOLD <span style="color:#64748b;"># live signal</span>

if allow_zone <span style="color:#c4b5fd;">and</span> allow_ident <span style="color:#c4b5fd;">and</span> allow_risk:
return re_originate(req) <span style="color:#a3e635;"># new clean session to dst</span>
return deny(req) <span style="color:#f87171;"># default deny wins ties</span>

<span style="color:#64748b;"># segmentation and identity are AND-ed, not OR-ed.</span>
<span style="color:#64748b;"># both must say yes. either can say no.</span></code></pre>
</div>

The boolean AND in that snippet is the entire thesis. Network segmentation and identity are not competing models where you pick one. They are independent layers that both have to agree, and either of which can refuse. That is what "defense in depth" actually means when you stop using it as a slogan.

## Segmentation Complements Identity, It Does Not Replace It

So let me retract the sentence I started with, carefully. The network does still matter, and "we did Zero Trust" is not a reason to flatten it. But the inverse error is just as real: segmentation alone, without strong identity, gives you rigid zones that trust anything already inside them, which is how the breaches of the perimeter era happened. Neither layer is sufficient. Each covers the other's blind spot.

Identity-based Zero Trust answers "is this caller who they claim to be, and are they allowed to do this." Network segmentation answers "should these two machines be able to exchange a packet at all, and if a host is compromised, how far can it reach." The first contains stolen credentials. The second contains compromised hosts. An attacker has to defeat both, in sequence, at every boundary, and you have given yourself a place to see them try. That is the layered posture I argued for at RSAC, and it is the one I keep coming back to: continuous validation of identity over time, as in the [control-plane post](/2025/10/20/zero-trust-control-plane-and-sessions.html), riding on top of a network that was never flat to begin with.

<p style="font-family: Georgia, serif; font-style: italic; font-size: 1.05em; border-left: 3px solid #c7d2fe; padding-left: 1em; margin-top: 2em; color: #1e293b;">Identity tells you who is knocking. Segmentation decides whether there is a door there at all. Zero Trust needs both, because an attacker only needs one of them to be missing.</p>

---

*This is the network-segmentation companion to my [RSAC 2026 talk write-up](/2026/03/30/rsac-2026-beyond-zero-trust.html), and it builds on my two-part series on Zero Trust with a [reverse proxy](/2025/08/03/zero-trust-with-reverse-proxy.html) and the [control plane and sessions](/2025/10/20/zero-trust-control-plane-and-sessions.html) behind it.*

*Building trust zones, wiring up an edge control zone, or arguing about whether the network still matters? I am on [LinkedIn](https://www.linkedin.com/in/singhsanjay12) or reachable by [email](mailto:hello@singh-sanjay.com).*
Loading
Loading