Skip to content
7 min read·Lesson 7 of 8

Policy Engines and Enforcement

The decision and enforcement plane of Zero Trust — Conditional Access, OPA, Cedar, and ZTNA brokers.

NIST 800-207 calls them the Policy Engine and Policy Enforcement Point. In practice you will encounter half a dozen different engines and a dozen kinds of enforcement points. This lesson maps the landscape.

The Decision Plane

A policy engine answers one question billions of times a day: given this principal, this resource, this action, and this context — allow or deny (and what additional steps)?

The decision can be:

  • Allow
  • Allow with step-up (MFA challenge, approval workflow)
  • Allow with constraints (read-only, no download, time-limited)
  • Deny

The signal set: principal identity, group/role membership, device posture, network location, time, behavioural risk, threat intelligence, application sensitivity, requested action.

IdP-Native Engines

For user-to-application access (north-south), the identity provider's own policy engine is the dominant pattern.

IdPEngine
Microsoft Entra IDConditional Access + Continuous Access Evaluation
OktaSign-on policies, Authentication policies, Device Trust
Google WorkspaceContext-Aware Access
Ping IdentityPingOne policies + DaVinci flows

These engines plug into the federation flow: every SAML / OIDC sign-in is evaluated. Continuous evaluation (CAE in Entra) revokes access mid-session when signals change (password reset, leaked credential, device non-compliant).

Configuration is declarative. A typical Conditional Access policy:

Name: Require compliant device for Finance apps
Assignments:
  Users: group "Finance"
  Cloud apps: "SAP Finance", "Workday", "Stripe Dashboard"
  Conditions:
    User risk: low or medium
    Locations: not "blocked countries"
Access controls:
  Grant: Require compliant device AND Require phishing-resistant MFA
Session controls:
  Sign-in frequency: 4 hours
  Use app-enforced restrictions

Application-Level Authorisation

IdP policies decide whether to let you into the app. Inside the app, you still need fine-grained authorisation — "User X may read order Y because they are the account owner."

The historical mess: ad-hoc if user.role == 'admin' checks scattered through the codebase. The Zero Trust pattern is to externalise authorisation into a policy engine.

Open Policy Agent (OPA) and Rego

OPA is a CNCF graduated project, the most widely adopted general-purpose policy engine. Policies are written in Rego:

# package authz
allow {
    input.user.id == input.resource.owner
}
allow {
    input.user.role == "admin"
    input.action != "delete"
}

Applications send a small JSON input ("can user U do action A on resource R") and get back an allow/deny. OPA is embedded as a sidecar, library, or central service. The same engine evaluates Kubernetes admission (via OPA Gatekeeper), Terraform plans (via conftest), API gateway decisions, and microservice authorisation.

AWS Cedar

Cedar is the policy language behind Amazon Verified Permissions and Verified Access. Designed for SaaS-style RBAC + ABAC:

permit (
  principal in Group::"sales",
  action == Action::"viewReport",
  resource
) when {
  resource.region == principal.region
};

Cedar is more constrained than Rego, which makes it more analysable — you can ask "does this policy ever allow X" with formal guarantees. Good fit for SaaS authorisation; not yet as broadly tooled as OPA.

Other engines worth knowing

  • Oso / Permit.io / Aserto — managed authorisation for application developers
  • Warrant, OpenFGA — Zanzibar-style relationship-based access control (the model Google Drive uses)
  • Kyverno — Kubernetes-native policy as YAML (alternative to OPA Gatekeeper for the cluster admission case)

Enforcement Points

Wherever traffic is intercepted, a PEP applies the decision. The same engine often feeds many PEPs.

LayerEnforcement points
Identity / SSOIdP federation flow
API edgeAPI gateway (Kong, Apigee, AWS API Gateway), Envoy with ext_authz
Service meshSidecar / proxy with AuthorizationPolicy
Cluster admissionKubernetes admission webhooks (Gatekeeper, Kyverno)
DatabaseRow/column-level security (Postgres RLS, Snowflake), permissions.cloud, immutable proxies
Network / ZTNAZTNA broker, secure web gateway
EndpointEDR / MDM

ZTNA — Zero Trust Network Access

ZTNA is the specific category of product that replaces VPNs for user-to-application access. The pattern:

  1. The user authenticates to a ZTNA broker (a SaaS service).
  2. The broker evaluates identity, device posture, and context.
  3. If allowed, the broker establishes an authenticated, encrypted tunnel directly to the application (not the network).
  4. The application is invisible to anyone who is not authorised — no DNS, no IP reachability.

This is BeyondCorp commoditised. Compared to a VPN:

  • No "I'm in" — every connection is per-app, not per-network
  • Applications are not exposed to the internet
  • Authorisation is identity- and context-based, not IP-based
  • Often clientless (browser-based) for partner / contractor access

Major ZTNA products:

  • Cloudflare Access (part of Cloudflare One)
  • Zscaler Private Access (ZPA)
  • Netskope Private Access
  • Palo Alto Prisma Access
  • Twingate, Tailscale (mesh-VPN approaches that meet many ZTNA principles)
  • Microsoft Entra Private Access / Microsoft Entra Internet Access

For pure HTTPS apps you may not need a dedicated ZTNA at all — exposing the app behind a reverse proxy (e.g., Cloudflare Tunnel, AWS Verified Access, Azure App Proxy) plus Conditional Access can be enough.

Policy as Code

At scale, point-and-click policy is unmaintainable. The mature pattern is policy as code:

  • Policy stored in git, versioned, peer-reviewed via PR
  • Unit tests (Rego unit tests, Cedar policy tests, Conditional Access policy mock evaluation)
  • CI pipelines push to the engine — never manual changes in production
  • Drift detection — anything changed outside git is flagged
  • Pre-deployment dry-run (Conditional Access "report-only" mode, OPA decision logs in non-blocking mode)

Treat policy as you treat application code: write tests, deploy through CI, monitor in production.

Observability of Decisions

Every allow and deny is a security event. Ship:

  • Sign-in logs from the IdP
  • OPA decision logs to the SIEM
  • ZTNA access logs
  • Admission controller decisions

Correlate with the SIEM. Tune policies based on observed deny rates and user friction. A successful Zero Trust deployment ends up with a measurable "denial reasons" dashboard that the security team reviews weekly.

The Picture

Behind every successful request in a mature Zero Trust deployment: an identity provider verified the user, the device posture engine confirmed the laptop was compliant, the ZTNA broker brokered the connection, the API gateway evaluated an OPA policy, the database enforced row-level security, and every decision was logged. That is six policy decisions for one HTTP request — none of which the user noticed.

The final lesson puts it all together into a practical adoption roadmap.

Key Takeaways

  • Policy engines centralise the access decision; enforcement points apply it across applications, networks, and APIs.
  • IdP-native engines (Entra Conditional Access, Okta Workflows) cover human-to-app decisions.
  • OPA / Rego, AWS Cedar, and Kyverno cover authorisation inside applications and Kubernetes clusters.
  • ZTNA brokers (Cloudflare Access, Zscaler ZPA, Twingate, Tailscale) replace VPNs for user-to-app access.
  • Policy as code — versioned, reviewed, tested — is the only way to keep policy correct at scale.

Test your knowledge

Try exam-style practice questions to reinforce what you've learned.

Practice Questions →