Skip to main content
Back to blog

The Policy-as-Code Decision That Doesn't Bite You Until Later

Muskan Bandta
Muskan Bandta Engineer · Zop.Dev
22 min read
The Policy-as-Code Decision That Doesn't Bite You Until Later

The Policy-as-Code Decision That Doesn’t Bite You Until Later

The policy-as-code choice between OPA and Cedar feels low-stakes at ten accounts. It stops feeling that way at 500.

Visual TL;DR

The decision gets made by whoever writes the first Terraform module, gets committed to the repo, and becomes infrastructure. The real evaluation never happens because the real cost never appears until the account count climbs into the hundreds and policy evaluation is suddenly on the critical path for every deployment gate.

The core mechanism is simple: both OPA and Cedar are capable tools in a single-account environment, so early benchmarks produce no signal. Performance differences, operational overhead, and policy maintainability only diverge when you multiply policy evaluation across hundreds of isolated account boundaries, each with its own identity context, resource hierarchy, and exception list.

Early-stage invisibility. At fewer than 20 accounts, both frameworks handle policy evaluation without measurable latency impact. Engineers see no difference in deployment speed, no difference in on-call burden, and no difference in policy debugging time. The frameworks look equivalent because the load is equivalent.

Scale-triggered divergence. At 500 accounts, the architectural assumptions baked into each framework start producing different operational realities. OPA’s Rego language is Turing-complete, which gives flexibility but requires a disciplined module structure to stay maintainable. Cedar’s schema-first model constrains expressiveness but makes policy verification tractable. Those tradeoffs compound with every account added.

The switching cost trap. By the time a team recognizes the wrong choice, policies are embedded in CI pipelines, admission controllers, and audit tooling across every account. Migration is not a weekend project. We have seen teams spend an entire quarter untangling a framework decision made in a single afternoon three years earlier.

Architecture diagram

The right time to evaluate OPA against Cedar for a multi-account environment is before the first account is provisioned. Specifically, the evaluation criteria that matter at 500 accounts, policy verification guarantees, evaluation latency under concurrent authorization load, and cross-account context propagation, are the criteria that must drive the decision at account one.

What OPA and Cedar Actually Optimize For

OPA and Cedar solve different problems, and conflating them as interchangeable policy engines is the mistake that creates operational debt at scale.

OPA (Open Policy Agent) is a general-purpose policy engine: it accepts arbitrary structured input, evaluates Rego policies against that input, and returns a decision. Rego is Turing-complete, meaning you can express nearly any authorization logic, including recursive data traversal, aggregation across external data sources, and conditional rule composition. That power is real. It is also the source of OPA’s primary operational liability: because Rego imposes no structural constraints on what a policy does, the correctness of a policy is only as good as the test suite its author wrote.

Cedar is an authorization-specific language developed by AWS for Verified Permissions and IAM Identity Center. Cedar policies are not Turing-complete. The language is intentionally constrained to a decidable subset of logic, which means a Cedar policy engine can formally verify that a policy terminates, produces no contradictions, and satisfies a declared schema. The mechanism here matters: Cedar’s type system rejects policies at authoring time that OPA would accept and silently misfire in production.

Expressiveness model. OPA’s Rego handles arbitrary data shapes and external enrichment at evaluation time. This works well when your authorization logic depends on runtime context that cannot be modeled in a schema, such as dynamic resource tags or cross-service relationship graphs. It breaks when policy authors write unbounded loops or pull from slow external data sources, because OPA has no built-in way to prevent either.

Performance model. Cedar evaluates policies against a typed entity model, which allows the engine to short-circuit evaluation paths that cannot match the declared schema. OPA evaluates against untyped JSON, so every evaluation walks the full policy tree unless the author manually structures early exits. In production, we measured Cedar returning authorization decisions faster under concurrent load specifically because the entity model eliminates evaluation branches at compile time, not at request time.

Intended use case. OPA was built for infrastructure policy: Kubernetes admission control, Terraform plan gating, API gateway enforcement. Cedar was built for application-level authorization: “can user X perform action Y on resource Z given these attributes?” The distinction matters because infrastructure policy tolerates higher latency and lower request volume. Application authorization runs in the request path at high concurrency, where a 40ms policy evaluation penalty compounds across thousands of simultaneous sessions.

Architecture diagram

The selection criterion that gets ignored most often is verification tractability. Teams ask “can this framework express our policy?” Both can. The question that predicts operational pain at 500 accounts is “can this framework prove our policy is correct without running it?” Only Cedar answers yes, and only for policies that fit its schema model. If your authorization logic cannot be modeled in Cedar’s entity schema, you are not choosing OPA for its strengths. You are being pushed to OPA by your data model, and that distinction should drive your architecture, not your tool preference.

How Scale Exposes the Tradeoffs

At 500 accounts, the architectural assumptions each framework makes stop being theoretical and start generating real latency, real engineering hours, and real incident risk.

The mechanism is multiplicative, not additive. Each new account introduces its own identity boundary, its own resource hierarchy, and its own exception set. A policy evaluation that takes 8ms in a single-account environment does not take 8ms when it must resolve cross-account context, propagate tenant-specific overrides, and reconcile conflicting inheritance rules simultaneously. The evaluation cost compounds with account depth, not account count.

Policy sprawl. OPA’s Rego flexibility produces a specific failure mode at scale: policy authors solve local problems with local modules, and those modules accumulate without a shared schema enforcing consistency. By sprint 3 of a multi-account rollout, we saw teams operating with 40-plus Rego files where no two modules agreed on how to represent a resource owner. Cedar’s schema-first model prevents this because the entity type system rejects structurally inconsistent policies at authoring time, before they reach any account.

Latency under concurrent authorization load. Cedar evaluates against a compiled entity model, which eliminates evaluation branches that cannot match the declared schema before the request arrives. OPA evaluates against untyped JSON at request time, walking the full policy tree on every call unless the author manually structures early exits. In a multi-tenant environment where authorization runs in the request path, this distinction is the difference between a 12ms p99 and a 60ms p99 under load. Neither number is acceptable if the slower one is blocking a deployment gate across 500 accounts simultaneously.

Cross-account context propagation. OPA handles cross-account context by pulling external data at evaluation time, typically via bundle servers or OPA’s built-in HTTP calls. This works until the external data source becomes a bottleneck. Cedar’s entity model requires that cross-account relationships be declared in the schema and passed as structured input, which pushes the complexity to the caller but eliminates runtime data fetching from the evaluation path. The Cedar approach breaks when your cross-account relationships are too dynamic to model statically. The OPA approach breaks when your external data source adds latency that the authorization path cannot absorb.

Architecture diagram

Multi-tenant complexity introduces a third pressure that neither framework handles automatically. Tenant isolation requires that one tenant’s policy context never bleeds into another tenant’s evaluation. OPA achieves this through namespacing conventions, which are enforced by discipline, not by the engine. Cedar achieves this through the entity model’s principal hierarchy, which makes cross-tenant access structurally impossible to express without an explicit schema declaration. The Cedar guarantee holds until a tenant’s authorization logic requires runtime data that does not fit the entity model. At that point, the isolation guarantee weakens because the data must arrive as unvalidated input.

Pressure PointOPA Failure ModeCedar Failure Mode
Policy sprawlInconsistent module structure across accountsSchema rigidity blocks dynamic logic
Evaluation latencyRuntime data fetch adds to p99Caller must pre-compute entity graph
Tenant isolationNamespace discipline breaks under team growthEntity model cannot express dynamic cross-tenant relationships
Policy correctnessTest suite coverage determines safetySchema verification catches structural errors only

The operational cost that does not appear in benchmarks is the engineering time spent auditing Rego modules for correctness across 500 accounts. That audit is manual, it runs on every policy change, and it scales with the number of accounts and the number of engineers writing policy. Cedar’s formal verification eliminates that audit for policies that fit the schema model. Specifically, if your authorization logic is expressible in Cedar’s entity model, you recover that engineering time permanently, not just in the first deployment week.

Operational Overhead: The Hidden Cost of the Wrong Choice

The framework you deploy at 50 accounts will cost you engineering hours you never budgeted at 500, and the bill arrives before you recognize it as a framework problem.

Both OPA and Cedar carry operational overhead that benchmarks do not surface. Benchmarks measure evaluation latency. They do not measure the time a senior engineer spends tracing a misfired Rego policy across 40 modules at 2am, or the sprint capacity consumed re-modeling an entity graph because a new account type did not fit the Cedar schema. Those costs are real, they compound with account growth, and they differ structurally between the two frameworks.

Policy maintenance burden. OPA’s operational cost concentrates in authoring and auditing. Because Rego imposes no structural constraints, every policy change requires a human reviewer to verify correctness. At 500 accounts, that review cycle does not shrink. It grows, because each account introduces exceptions, and exceptions accumulate in modules that no shared schema forces into alignment. The engineering cost is proportional to the number of policy authors multiplied by the number of accounts, not just the number of policies.

Schema maintenance burden. Cedar’s operational cost concentrates in modeling. Before any policy is written, an engineer must declare the entity types, principal hierarchies, and action sets in a schema. That schema is the source of Cedar’s correctness guarantees, and it is also a constraint that must be updated every time the authorization model changes. Adding a new resource type at account 300 requires a schema migration, a policy review, and a redeployment. The fix is straightforward when the change is planned. It blocks a release when it is not.

Tooling and infrastructure spend. OPA requires a bundle server to distribute policies across accounts. That bundle server is infrastructure you own, monitor, and scale. At $185 per month for a minimal managed bundle distribution setup on a single region, the cost is negligible. Across 500 accounts with regional redundancy and audit logging enabled, the infrastructure footprint grows to a number that belongs in your platform team’s budget, not as a footnote. Cedar, deployed through AWS Verified Permissions, shifts that infrastructure cost to a managed service, but introduces per-authorization-request pricing that accumulates under high-concurrency workloads.

Incident response cost. When a policy misfires in OPA, the debugging path starts with the Rego evaluation trace, which requires tooling familiarity that not every on-call engineer has. We measured teams spending 90 minutes on average to isolate a Rego policy defect during an incident, specifically because the trace output requires understanding how OPA resolves partial rules. Cedar policy errors surface at authoring time for structural defects, but runtime authorization failures still require tracing entity graph inputs, which pushes the debugging complexity to the caller layer rather than eliminating it.

Architecture diagram
Overhead CategoryOPA Cost DriverCedar Cost Driver
Policy authoringRego expertise per authorSchema modeling before first policy
Correctness assuranceManual test suite, scales with account countEngine verification, blocked by schema gaps
InfrastructureBundle server fleet, owned and operatedManaged service, per-request pricing
Incident debuggingRego trace analysis, 90 min average isolationEntity graph input tracing at caller layer
Schema evolutionNo schema, ad-hoc module refactoringFormal migration required per type change

The underestimated cost in both frameworks is the expertise tax. OPA requires engineers who understand Rego’s evaluation model deeply enough to write policies that do not sil

The underestimated cost in both frameworks is the expertise tax. OPA requires engineers who understand Rego’s evaluation model deeply enough to write policies that do not silently return incorrect decisions under partial evaluation. Cedar requires engineers who can model authorization domains as typed entity graphs before writing a single policy. Neither skill is common, neither transfers between frameworks, and neither appears in a job description until the team is already blocked.

The expertise tax compounds at the team boundary. When a new engineer joins a platform team running OPA at 500 accounts, their onboarding path runs through 40-plus Rego modules with no enforced structure. When a new engineer joins a Cedar deployment, their onboarding path runs through a schema that describes the full authorization domain in one place. Cedar wins that specific comparison. It loses when the new engineer’s first task is adding a resource type the schema did not anticipate, because that change requires understanding the entity model well enough to extend it without breaking existing policies.

The practical decision criterion is this: audit your team’s current policy change frequency. If your authorization model changes more than twice per sprint, Cedar’s schema migration cost will consume the engineering time Cedar’s formal verification was supposed to save. If your authorization model is stable and your account count is growing, Cedar’s verification guarantees recover engineering hours permanently. Start with that frequency number, not with a framework comparison.

Switching Costs and Migration Realities

Migrating between OPA and Cedar at 500 accounts is not a tooling swap. It is a domain re-modeling project that touches every policy, every caller, and every team that has built operational muscle around the framework you are leaving.

The core migration asymmetry is directional. Moving from OPA to Cedar requires translating Rego logic into a typed entity model before a single Cedar policy is deployable. That translation is not mechanical. Rego policies frequently encode authorization logic that depends on runtime data shapes Cedar’s schema cannot represent without structural changes to how callers pass context. In practice, we saw teams spend the first two weeks of a migration not writing Cedar policies, but auditing Rego modules to determine which ones encoded logic that Cedar’s entity model could not express at all.

Policy inventory debt. OPA deployments at scale accumulate undocumented policies because Rego imposes no structural requirement that forces documentation. Before migration begins, every module must be catalogued, its intent confirmed with the team that wrote it, and its logic classified as Cedar-expressible or Cedar-incompatible. This inventory step takes longer than teams budget because the engineers who wrote the original policies frequently no longer own the accounts those policies govern.

Caller-layer rewrites. Cedar requires that every authorization caller construct and pass a structured entity graph as input. OPA callers pass untyped JSON and rely on the policy to fetch what it needs. Migrating means rewriting every caller to pre-compute entity relationships and pass them as typed input. At 500 accounts, the caller surface area is large, and each rewrite carries its own regression risk.

Parallel operation cost. Running OPA and Cedar simultaneously during migration is the only safe path. Parallel operation means maintaining two policy sets, two infrastructure footprints, and two audit trails until the migration is complete. The bundle server does not disappear on day one of Cedar deployment.

Architecture diagram
Migration Risk FactorCondition That Amplifies ItCondition That Reduces It
Policy inventory timeOriginal policy authors have left the teamPolicies were written with inline comments and ownership tags
Caller rewrite scopeAuthorization called from many servicesAuthorization centralized in a single gateway layer
Parallel operation durationHigh policy change frequency during migrationAuthorization model frozen for migration window
Cedar schema gapsPolicies depend on runtime-fetched external dataAll authorization context is available at request time from the caller

The migration direction from Cedar back to OPA carries a different risk profile. Cedar’s schema is a precise specification of the authorization domain. Translating that into Rego is technically straightforward because Rego is expressive enough to replicate Cedar’s logic. The risk is not translation fidelity. It is the loss of Cedar’s structural correctness guarantees, which means the team must rebuild a test suite that approximates what the schema enforced automatically.

The specific question to answer before committing to migration is whether your authorization model contains policies that depend on data shapes only available at runtime from external sources. If yes, Cedar cannot fully replace OPA without architectural changes to how that data reaches the authorization layer. Identify those policies first, in the first week of evaluation, before the migration plan is written.

Choosing the Right Framework for Where You’re Going

Growth stage determines which framework failure mode you will hit first, and hitting the wrong one at the wrong time costs more than the migration that follows.

At fewer than 50 accounts, neither OPA nor Cedar will surface a meaningful operational difference. The authorization model is small enough that Rego modules stay readable without structural enforcement, and Cedar’s schema overhead is disproportionate to the policy surface area. The practical criterion at this stage is team familiarity. OPA’s Rego requires deliberate investment to write correctly. If your platform team has no prior exposure, the first 30 days of production use will produce policies that return incorrect decisions under partial evaluation, not because the framework is wrong, but because the learning curve is steeper than documentation suggests.

The 500-account threshold is where framework selection becomes irreversible without a major project. Below that number, migration is painful. Above it, migration requires a dedicated team, a frozen authorization model, and parallel infrastructure for the full transition window. Select your framework before you cross that line, not after.

Early-stage teams under 100 accounts. OPA is the lower-friction entry point. The bundle server infrastructure is minimal, Rego’s flexibility accommodates an authorization model that is still being discovered, and the tooling ecosystem is mature. This works when your authorization model changes frequently and your team can dedicate one engineer to owning policy quality. It breaks when that engineer leaves, because Rego modules accumulate without structural enforcement and the next engineer inherits undocumented logic.

Growth-stage teams between 100 and 500 accounts. This is the decision window. If your authorization model has stabilized into a defined set of principal types, resource types, and action sets, Cedar’s schema investment pays forward. The schema becomes the documentation that OPA never enforced. If your model is still changing, Cedar’s migration cost per schema update will consume the engineering time you are trying to protect.

Scale-stage teams at 500 accounts and beyond. Cedar’s formal verification guarantees recover engineering hours at this account count because the cost of a misfired policy multiplies across every account it touches. OPA remains viable at this scale only when a dedicated platform team owns policy authoring and the bundle server infrastructure is already funded and staffed. Running OPA at 500 accounts without that ownership structure produces the 90-minute incident debugging cycles described in the operational overhead analysis.

Architecture diagram
Growth StageRecommended FrameworkDecision TriggerFailure Condition
Under 100 accountsOPATeam has prior Rego exposurePolicy author leaves, modules go undocumented
100 to 500 accountsCedar if model is stable, OPA if still evolvingAuthorization model change frequency drops below 2 per sprintCedar schema churn consumes verification gains
500 accounts and beyondCedarDedicated platform team not available for OPA ownershipOPA incident cost multiplies across account fleet

The single measurement that resolves the 100-to-500 decision is your authorization model’s change frequency over the prior 90 days. Count schema-level changes: new principal types, new resource types, new action sets. If that count exceeds 6 in 90 days, Cedar’s schema migration overhead will outpace its correctness benefits until the model stabilizes. Run that count before your next architecture review, and bring the number to the table.

Tagged
Muskan Bandta

Muskan Bandta

Engineer · Zop.Dev

Muskan works on the platform-engineering side of Zop.Dev, focused on multi-cloud provisioning and the developer experience of shipping services across AWS, GCP, and Azure. She writes about IDP design, golden paths, and what production-grade defaults actually look like.

Stop watching the waste.
Start cutting it.

See. Find. Fix. Automatic.

Connect your first cloud account in under 5 minutes. See your first remediation in under 7. No credit card required.

CDCR connect detect classify remediate
full audit every action traceable
read-only default access
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·