Cedar vs OPA for AI Agent Access Control: Why Deny-Wins Matters
Published 2026-04-15
The problem with RBAC for agents
Traditional RBAC assigns roles to humans. AI agents don’t have a fixed identity — they execute on behalf of users, but their tool access scope is often broader than any individual user’s permissions.
When an agent can call ec2:DescribeInstances, cloudwatch:GetMetricData, rds:DescribeDBInstances, and ssm:GetParameter, the question isn’t “what role does this agent have?” — it’s “which of these actions is allowed for this request, from this tenant, for this purpose, at this time?”
That’s what policy-as-code was built for.
Why Cedar over OPA
Both Cedar and OPA can express fine-grained policies. We chose Cedar for three reasons:
1. Deny-wins semantics. In Cedar, an explicit forbid always beats a permit. In OPA, policy evaluation order matters and can be subtle. For agentic systems where the blast radius of a mistake is high, deny-wins is the right default.
2. WASM compilation. Cedar compiles to WASM, which runs directly in Cloudflare Workers via @cedar-policy/cedar-wasm. No separate policy server, no network hop. Policy evaluation is synchronous and ~1ms.
3. Structured entities. Cedar policies operate on typed entity graphs — User::"alice" is a principal, Action::"ec2:Describe" is an action, Resource::"prod" is a resource. The schema prevents a whole class of policy authoring mistakes that OPA’s Rego allows.
The guard-gate implementation
EAIP’s guard-gate Cloudflare Worker loads Cedar policies from Workers KV on cold start. Every /invoke request evaluates:
permit(
principal in Team::"${teamId}",
action in [Action::"agent:invoke"],
resource is Agent
) when {
resource.tenant == principal.tenant &&
context.injection_scan_passed == true
};
The forbid rules cover cross-tenant access, actions outside business hours (optional), and any resource where resource.sensitivity == "classified" for teams without clearance.
The entire evaluation runs before any model call. If Cedar returns deny, the request never reaches the agent runtime.