Zero Trust Architecture
On this page
Never Trust, Always Verify#
Perimeter security assumed a castle wall: anything inside the corporate network was trusted, anything outside was not. That model breaks the moment one laptop inside the wall is compromised, because the attacker inherits all the trust the network grants. It also fits badly with a world of cloud services, remote staff and partner access, where "inside" no longer means much.
Zero Trust replaces location-based trust with a simpler rule: no request is trusted because of where it comes from. Every access, whether from the office Wi-Fi, a home network or another microservice, has to prove who is asking, from what device, for what resource, and is checked against policy at that moment.
The Three Core Principles#
- Verify explicitly. Every request is authenticated and authorised using all available signals: user identity, device health, service identity, location, time and the sensitivity of the resource.
- Least privilege. Access is scoped to a specific resource, at the minimum level, for a limited time. Standing admin rights become just-in-time elevation that expires.
- Assume breach. Design as if an attacker is already inside. Segment so a compromised host cannot reach everything, encrypt internal traffic, and log every decision so you can reconstruct what happened.
The Moving Parts#
NIST SP 800-207, the most widely cited reference architecture, describes three logical components:
- Policy Enforcement Point (PEP): sits in the request path and allows or blocks. In practice this is an identity-aware proxy, an API gateway, a service mesh sidecar or the application itself.
- Policy Engine (PE): makes the decision from policy plus signals such as the identity provider, device management and threat intelligence.
- Policy Administrator (PA): acts on the decision, for example by issuing a short-lived session credential to the PEP.
The key design point is that the decision happens per request or per session, using live signals, not once when someone connects to a VPN.
A Worked Example: A Policy Decision in Code#
Real deployments use a product or a policy language, but writing a toy policy engine makes the logic concrete:
from dataclasses import dataclass
from datetime import datetime, timezone
@dataclass
class Request:
user: str
groups: set
mfa_age_minutes: int
device_managed: bool
device_patched: bool
resource: str
action: str
# resource -> (allowed groups, sensitivity)
POLICY = {
"payroll-db": ({"finance"}, "high"),
"wiki": ({"staff"}, "low"),
"prod-console": ({"sre"}, "high"),
}
def decide(req: Request) -> tuple[bool, str]:
groups, sensitivity = POLICY.get(req.resource, (set(), "high")) # unknown = deny
if not groups & req.groups:
return False, "not in an allowed group"
if sensitivity == "high":
if not (req.device_managed and req.device_patched):
return False, "high-sensitivity resource needs a managed, patched device"
if req.mfa_age_minutes > 60:
return False, "step-up MFA required (last MFA over 60 min ago)"
if req.action == "write" and datetime.now(timezone.utc).hour not in range(6, 22):
return False, "writes outside working hours need a break-glass approval"
return True, "allowed"
r = Request("dana", {"staff", "finance"}, 240, True, True, "payroll-db", "read")
print(decide(r))
Output:
(False, 'step-up MFA required (last MFA over 60 min ago)')
Things worth noticing: an unknown resource defaults to deny; the same user gets different answers for the wiki and the payroll database; and a stale MFA does not end the session, it triggers a step-up challenge. Every decision and its reason should be logged, which gives you the audit trail that "assume breach" requires.
Identity Is the New Perimeter#
If identity decides every access, the identity system becomes your most valuable asset:
- Phishing-resistant MFA (passkeys, FIDO2 security keys) for everyone, not just admins. Push-notification MFA is vulnerable to "fatigue" attacks where the attacker spams prompts until someone taps approve. See authentication concepts.
- Device trust: is the device enrolled in management, encrypted, patched, running EDR? A valid login from an unmanaged, out-of-date laptop is still a risk and can get reduced access.
- Continuous evaluation: sessions are re-checked when signals change, such as a user being disabled, a device falling out of compliance or an impossible-travel login, rather than staying valid for their full lifetime.
- Workload identity: services need identities too. Long-lived API keys in config files are the service equivalent of a shared password.
Service-to-Service: Mutual TLS#
Inside a zero trust network, service A cannot reach service B just because they share a subnet. B demands a client certificate proving A's identity. With Python's ssl module, the server side looks like this:
import ssl, http.server
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain("orders.crt", "orders.key")
ctx.load_verify_locations("internal-ca.pem")
ctx.verify_mode = ssl.CERT_REQUIRED # no client cert, no connection
srv = http.server.HTTPServer(("0.0.0.0", 8443), http.server.SimpleHTTPRequestHandler)
srv.socket = ctx.wrap_socket(srv.socket, server_side=True)
srv.serve_forever()
And the client:
import requests
r = requests.get("https://orders.internal:8443/",
cert=("billing.crt", "billing.key"), # proves "I am billing"
verify="internal-ca.pem") # proves "you are orders"
A client without a certificate signed by the internal CA fails during the handshake (curl reports an SSL alert such as "certificate required"). In production, service meshes and workload-identity systems such as SPIFFE issue and rotate these certificates automatically, often every few hours, because manual certificate management does not scale. mTLS proves identity; the service must still authorise: billing may call GET /orders, not DELETE /orders.
Micro-Segmentation#
Traditional segmentation carved zones (the DMZ, the server VLAN). Micro-segmentation carves per workload: the web tier may reach the API, the API may reach the database on port 5432, and nothing else is permitted. In practice that is Kubernetes network policies, cloud security groups that reference other security groups rather than CIDR ranges, and host firewalls managed centrally. The container and Kubernetes security and cloud security lessons show concrete policies.
A network rule alone is not zero trust. It limits which paths exist; identity-aware authorisation decides what may travel along them.
VPN vs Zero Trust Network Access#
| Traditional VPN | ZTNA / identity-aware proxy | |
|---|---|---|
| Unit of access | A network segment | A single application |
| When checked | At connect time | Every request or session |
| Device posture | Often ignored | Part of the decision |
| Lateral movement after compromise | Easy, the whole segment is reachable | Limited to authorised apps |
| Apps exposed to the internet | VPN concentrator | Only the proxy; apps stay private |
| Legacy protocols (SMB, thick clients) | Work unchanged | May need connectors or remain on VPN |
Google's BeyondCorp was the influential early example: employees reach internal apps without a VPN, with every request passing through an access proxy that checks user and device. The market now packages the same idea as ZTNA and as part of SASE offerings. The underlying tunnelling technology is covered in VPN and tunneling.
How Zero Trust Programs Fail#
- Buying a label. A product called "zero trust" in front of a flat network with shared admin accounts changes little.
- VPN left running alongside. If the old VPN still grants full network access, attackers use that instead.
- Service accounts forgotten. Human logins get MFA and device checks while a CI token with owner rights lives forever in a pipeline variable.
- No break-glass path. When the identity provider is down, nobody can log in to fix it. Keep a documented, monitored emergency access route.
- Policy nobody can read. Hundreds of ad-hoc exceptions become a new, invisible perimeter.
Getting Started#
Zero trust is a migration, not a switch. A practical order:
- Inventory applications, identities (human and service) and the flows between them. Threat modeling is the tool for mapping flows.
- Consolidate on one identity provider with phishing-resistant MFA.
- Put the highest-value applications (admin consoles, finance, source control) behind an identity-aware proxy with device checks.
- Replace long-lived service credentials with workload identity and short-lived tokens.
- Segment east-west traffic, starting around the crown jewels.
- Retire broad VPN access application by application, and log every access decision centrally.
Check your understanding
4 quick questions on this lesson. Get them all right and the lesson is marked complete.