For decades, security was modeled like a castle with a moat: a strong perimeter defense with trusted actors inside. The Zero Trust model throws that idea away. It operates on a simple but powerful principle: **never trust, always verify**.
This means we assume that threats can exist both outside and *inside* the network. Every single request to access a resource must be authenticated and authorized, regardless of where it originates.
🔑 Core Tenets of Zero Trust
- Verify Explicitly: Always authenticate and authorize based on all available data points, including user identity, location, device health, and more.
- Use Least Privilege Access: Grant users the minimum level of access they need to perform their job functions.
- Assume Breach: Minimize the "blast radius" of an attack by segmenting networks and assuming an attacker is already inside.
Policy as Code: The Engine for Zero Trust
A Zero Trust architecture is defined by its policies. Policy as Code (PaC) is the perfect mechanism to enforce these principles because it allows you to define fine-grained, automated, and auditable access rules. With a policy engine like Open Policy Agent (OPA), you can externalize authorization logic and make dynamic decisions for every request.
Example 1: Identity-Based Access Control
In a Zero Trust model, we don't just check if a user is logged in; we validate the details of their session, often provided by a JSON Web Token (JWT).
Sample Input: API Request and Decoded JWT
// API Request
{
"path": "/api/v1/billing",
"method": "POST",
"token": "eyJhbGciOiJSUzI1NiIsImtpZCI6InB1YmxpYzo..."
}
// Decoded JWT Payload from the token
{
"iss": "https://auth.policyascode.dev/",
"sub": "user-123",
"aud": ["billing-api", "reporting-api"],
"scope": "billing:write",
"is_mfa": true
} Rego Policy: JWT Validation
This policy verifies the token's signature and checks specific claims before allowing access.
package api.authz
import future.keywords.if
# Decode and verify the JWT signature.
decoded_token := io.jwt.decode_verify(input.token, {
"cert": data.auth.jwt_public_key,
"iss": "https://auth.policyascode.dev/",
"aud": "billing-api"
})[1]
# Rule to check for write access
has_write_permission if {
"billing:write" in split(decoded_token.scope, " ")
}
# Rule to enforce MFA for critical operations
is_mfa_compliant if {
input.method == "POST"
decoded_token.is_mfa == true
} else if {
input.method != "POST"
}
# Main allow rule
allow if {
has_write_permission
is_mfa_compliant
} Example 2: Device & Location-Based Access
Zero Trust goes beyond user identity to include device posture and context. The policy engine can receive data from endpoint management tools and geolocation services to make even smarter decisions.
Sample Input: Context-Rich Request
{
"user": { "id": "user-123", "groups": ["developers"] },
"device": { "id": "dev-456", "is_managed": true, "disk_encrypted": true },
"location": { "ip": "1.2.3.4", "country": "US" },
"resource": "source-code-repository"
} Rego Policy: Context-Aware Access
This policy denies access if the device is not managed by the company or if it's coming from a non-approved country.
package zero_trust.context
# Deny if the device is not managed by the company
deny[msg] if {
input.device.is_managed == false
msg := "Access denied: Unmanaged devices are not permitted."
}
# Deny if disk encryption is not enabled
deny[msg] if {
input.device.disk_encrypted == false
msg := "Access denied: Device disk must be encrypted."
}
# Deny access from non-approved countries
deny[msg] if {
approved_countries := {"US", "CA", "GB"}
not approved_countries[input.location.country]
msg := sprintf("Access denied: Access from country '%v' is not allowed.", [input.location.country])
} By combining identity, device, and network policies, you create a powerful, multi-layered Zero Trust enforcement system that adapts in real-time.