The split between the component that enforces an access decision and the one that makes it is settled architecture. NIST named the parts, and the AuthZEN Authorization API reached Final Specification in January 2026, standardizing the wire between them so any compliant enforcement point can call any compliant decision point. None of it settles what to do when the application cannot host an enforcement point at all.
Every authorization program reaches that set of applications and stops. They authenticate against Active Directory or an LDAP directory, and their access rules are encoded in group membership. The people who wrote them have moved on, the build is fragile, and the case for touching them is weak because they still work.
These are not bad systems. They are systems whose change budget has run out. Asking one to call a policy engine means finding every place it checks a permission, which is rarely one place, then carrying the regression risk of changing all of them. That work does not get funded, so new services get externalized authorization and the older ones keep whatever they had.
Entitlement provisioning, policy provisioning and claim enrichment
The field has already named the options for reaching an application that cannot host an enforcement point. Entitlement provisioning has the decision layer compute which permission sets or group memberships a user should hold in the target, then write them through its admin API. Policy provisioning translates the policy into whatever access control language the target already speaks. Claim enrichment has the identity provider consult the decision point while it mints the token, so the application reads claims it already understands.
All three work, and for some targets they are the only thing that works. They also share a property. Each decides at a moment that is not the moment of the request, so it cannot see what is being asked. A permission set granted this morning is still granted this afternoon, whatever has changed since. Entitlement provisioning also flattens context into identity centric grants, dropping the conditions the policy was written to express.
A fourth option keeps the decision at request time. Put the enforcement point in front of the application rather than inside it.
The proxy in front of the application is already a decision point
These applications almost always sit behind something already, a reverse proxy, an API gateway, an ingress controller. That component sees every request and can be told to ask a question before it forwards one.
Envoy is the general case, because its external authorization filter is part of the HTTP filter chain and every proxy built on Envoy inherits it. The filter pauses a matching request, sends the method, path and headers to a configured service, and forwards or refuses based on the answer. Per route bypass and the fail open decision are covered in the Envoy piece in this series.
What turns that filter from a route allow list into an authorization layer is whatever answers the call. A service that resolves the caller against the directory, evaluates policy against the result and explains the outcome is doing the job the application never would. Cerbos Synapse implements the external authorization protocol natively, so the proxy side is configuration rather than an adapter you build and maintain.

Three moving parts turn a request into a decision
The first is a data source. It takes an identifier, queries the directory, and returns the user's profile and group memberships. It is the only component holding the bind credentials, the base DN and the search filter. Everything downstream sees a plain structure of profile fields and group names.
The second is a proxy extension. It runs on every authorization request before evaluation, calls the data source by name, and writes the result onto the principal. Directory groups become roles, directory attributes become principal attributes that policy can test. Together the two are the context handler NIST SP 800-162 places alongside the decision and enforcement points, the part that assembles the attributes a decision needs so the engine can stay stateless. Data sources are also where the caching lives.
The third is the mapping that turns an Envoy check into a Cerbos check, written as CEL expressions rather than code, which leaves the enforcing component with no logic of its own. The principal identifier comes out of a header, the resource identifier is the request path, and the method is carried as an attribute. The action is a single verb, because at the boundary the only question is whether the request may proceed.
The application takes part in none of this. It receives a request or it does not.
Directories are not built for per request query volume
An LDAP directory or an Active Directory forest is built for authentication and periodic reads, not for a search on every HTTP request from every application in the estate, so the lookup is cached. The data source checks the cache before it searches, writes the result back with a TTL, and holds a pool of bound connections so binding is amortized rather than paid per request. The cache can be in process, or shared through Redis so a fleet of instances does not each warm its own copy.
Treating that cache as a resilience property rather than an optimization is now visible in public sector architecture. Germany's federal API authorization infrastructure, approved by the country's IT Planning Council on 17 June 2026, fronts a federation of public services nobody was going to rewrite together. The published account of the design describes twenty three architecture decision records released in the open, and says the whole thing is designed so that a decision point keeps working even when the central plane is down. Caching policies and attributes locally is how a decision point holds that property, which is why the expiry on those caches is a design decision rather than a tuning one.
Two consequences follow. Attributes are stale by up to the TTL, so a group removal takes effect at the next expiry, which makes that number a correctness decision rather than a tuning parameter. And on a cache miss the directory sits in the request path, so a lookup failure either fails the check or admits an incomplete principal, the second of which turns a policy depending on directory attributes into one that allows almost anything while the directory is down.
The same shape applies when the attributes live in a database, covered in a companion piece on SQL data sources and caching.
The policy changes, the application does not
Once attributes arrive at the decision point from outside the application, the access model can move without the application knowing. Watch one policy evolve while the code stays fixed. A first version allows everything, which is where a lot of these estates sit once past the login screen.
A second version becomes role based, using the directory groups the proxy extension put onto the principal. An expense users group can view and edit, an approvers group can approve. This restates what the directory already encoded, somewhere it can be read.
A third version stops treating membership as sufficient. Approval requires the amount to be at or below the approval limit held as an attribute on the user's directory record. Membership answers who may approve, the attribute answers how much.
A fourth version adds separation of duties, comparing the expense owner to the principal so an approver cannot approve their own expense. A fifth brings in a risk score computed by a second data source from the amount and a device compliance flag, refusing approval above a threshold. Each carries its reason back in the output, so a refusal explains itself.
Five changes to the access model, none to the application. That is what the provisioning routes cannot reach, because the last three versions all depend on the request. It is decoupled authorization in the form that matters for an estate you cannot modify, expressed as ordinary resource policies.
Migrating from Active Directory to Entra ID without touching applications
Directories get replaced. An organization moves from Active Directory to Entra ID, consolidates three directories after an acquisition, or puts an identity provider in front and starts issuing tokens. When every application resolves identity for itself, that migration is a project per application, and the long tail nobody wants to touch is where it stalls.
When resolution happens at the proxy, it is a change to one component. The data source is swapped for one that speaks the new protocol, the incoming field names are mapped onto the principal shape the policies already reference, and the applications carry on unchanged. Keeping that shape stable is what makes this work. Resolving identity attributes at decision time rather than trusting what a token carried when it was issued is covered in a separate piece in this series.
At the scale of Utility Warehouse, a FTSE 250 company running 4,500 services, the gap between changing one component and changing every application is not a matter of degree.
What this changes about the architecture
Group membership stops being the access model and becomes an input to it. The directory keeps ownership of who belongs to what, and the rule about what that permits becomes a file that can be read, reviewed and versioned.
The enforcement layer also becomes where the estate converges. Applications that can call a policy engine call it directly. Applications that cannot are fronted by the proxy and get the same policy set at the boundary. Both produce decision logs in one stream, often the first time anyone sees the older systems in the same view as the newer ones. That makes a gradual migration tractable, because an application can move from boundary enforcement to in application checks one at a time without the rules being rewritten.
It is also where agent traffic to these systems lands. An agent reaching a frozen application arrives through the same proxy as a browser and gets the same check, which is the only answer available for systems that predate the question.
Coarse grained limits, bypass paths and trusting the proxy's identity
This gives coarse grained control at the boundary and nothing finer. The proxy sees a method, a path, headers and a body. If the record identifier and the attributes that matter are carried in the URL or the payload, a policy can decide on them. Anything depending on state the request does not contain, such as whether a document is archived, needs the application to participate or a data source that resolves it from an identifier the request does carry. For an application you genuinely cannot change, you get the boundary and no more, and pretending otherwise signs off a control that does not do what it says.
A gateway is a nearly all configuration enforcement point, which is its strength, and the standing caveat is that every call has to route through it or the bypass paths go unauthorized. In a legacy estate that is not academic. An internal client, a scheduled job, a batch feed or an operator with a port forward all reach the service without passing the check, so network controls have to make the proxy the only route.
Pulling every attribute through one enrichment layer also moves the constraint rather than removing it, from authorization to the data layer, so where the information comes from has to be designed alongside where the decision is made.
Identity is the last constraint. The mapping trusts what the proxy hands it, so whatever establishes the caller's identity has to be verified before the check runs. Reading a principal from a header is reasonable behind a gateway that authenticates and strips inbound copies of it, and unsafe anywhere else.
The application is frozen, the access model is not
"Cannot call a policy engine" describes the application, not the architecture. It rules out one location for the enforcement point and says nothing about whether the rules can be externalized, versioned, tested and audited, because those properties come from where the policy lives. The applications are frozen. The access model does not have to be.
Try Cerbos to see how this works in practice, or book a call to talk through your architecture with the team.
Go deeper: How to adopt externalized authorization (eBook) for a structured approach to moving access rules out of application code, including the estates you cannot modify.
FAQ
Tagged in




