Policy-as-Code for Authorization as a Breach Prevention Control

Centralizing authorization policy stops breaches that scattered code can't prevent.

Summary

Centralizing authorization policy stops breaches that scattered code can't prevent.

Authorization is the most expensive thing security teams keep failing to fix, and the reason isn't effort. OWASP's Top 10 for 2025 puts Broken Access Control at number one, and every application tested in that research carried some form of the weakness. That spread reflects a default implementation pattern that can't hold up under its own weight. Authorization logic, in almost every application built today, lives inline, scattered across service code as role checks, conditional branches, and one-off exceptions added before a release. Each addition makes sense on its own. Taken together, they form something no single engineer can read start to finish and understand. Security teams call the resulting mess "authorization debt," and like any debt, it compounds quietly until the bill arrives as a breach notification. Nobody can answer the basic question, who can access what, without reading every service's source code line by line, and a single missed check becomes the gap an attacker walks through. The problem gets worse as organizations lean harder on automation: analysis from Cerbos found that nearly all non-human identities carry excessive privileges, which widens an attack surface that scattered authorization logic was never built to govern in the first place. Microservice architectures and multi-tenant systems take a bad situation and multiply it, because each service owns its own access logic with no shared location to audit, patch, or test. There is no dashboard for this. There is no single file to grep. The architecture itself guarantees inconsistency, and that inconsistency is what breach reports keep finding.

Authorization logic scattered and unauditable in the breach record

The pattern described above isn't theoretical. It appears in the breach record with names attached. The most damaging incidents of the past year trace directly to authorization that was misconfigured or simply unenforced at the exact point where an API or a third-party integration meets a company's data. In July 2025, TransUnion disclosed a breach affecting 4.4 million customer records. Attackers used social engineering and OAuth token theft to compromise a third-party application, Salesloft's Drift, which was connected to Salesforce, and the exfiltration happened without tripping any standard access control. That detail matters because it shows there was no auditable authorization logic anywhere in that chain for the attack to even violate. A month earlier, in May 2025, Farmers Insurance suffered a breach disclosed that August, where threat actors ran a Salesforce OAuth social engineering campaign, vishing calls and a malicious app authorization, against a third-party vendor's database. The overprivilege involved was never visible as a policy violation, because no policy existed to violate in the first place.

These aren't isolated incidents involving an unlucky vendor. Research from SQ Magazine on API security identifies Broken Object-Level Authorization, BOLA, as the leading API attack vector, accounting for the largest share of API vulnerabilities tracked. BOLA is exactly the category that centralized, declarative policy, evaluated at the moment of each request, is built to catch. And regulators have started pricing the absence of that control into penalties. The ICO fined Capita plc and Capita Pension Solutions Limited a substantial combined penalty for failing to implement appropriate security measures under UK GDPR, after personal data belonging to millions of people was exfiltrated. That fine is what regulatory exposure looks like when a company has no automated policy control to point to. Supply chains have made the exposure systemic rather than occasional: the share of breaches involving a third-party component roughly doubled to approach a third of all breaches, with campaigns harvesting OAuth tokens and CRM data across many organizations by abusing vendor integrations. Every one of those integrations is an authorization boundary, and embedded, per-service logic has no way to govern a boundary it can't even see. None of this is random. These are the predictable output of an architecture that never had a single enforcement point to begin with.

How Policy-as-Code changes the enforcement sequence

Policy-as-Code turns authorization into something that gets checked before it ships, not something investigated after it fails. Mechanically, it starts with policy-based access control, which moves the authorization decision out of application code and into a central policy engine. Policy-as-Code is that same model, run with the engineering discipline normally reserved for application code: version-controlled, tested, and peer-reviewed before anything goes live. Policies get written in human-readable, declarative languages, Rego, YAML, Cedar, stored in version control alongside the application code they govern, and enforced through CI/CD pipelines and runtime checks rather than inspected after the fact.

The sequence itself is what changes operationally. Traditional security models deploy first and audit later, and that order creates exposure windows measured in days between the moment something gets misconfigured and the moment anyone notices. PaC closes that window by blocking the change before it reaches production. A concrete example from Wiz Academy: a Rego policy, evaluated by Open Policy Agent through a tool called Conftest, runs during continuous integration and stops any Terraform plan that would configure an S3 bucket ACL as public from ever reaching deployment. The rule is testable code, independent of whoever reviewed the pull request that day. Git gives every policy change a timestamped, versioned record, which produces an audit trail that scattered, embedded logic structurally cannot generate. Compliance teams get proof that a control operated, instead of a reconstruction exercise after regulators or forensic investigators start asking questions. Centralizing the policy also means one change applies across every service at once, rather than rolling out service by service and leaving a trail of inconsistent enforcement windows behind it. Continuous compliance in cloud environments depends on exactly this combination: policy as code, drift detection, and automated evidence capture. The policy artifact itself becomes the compliance evidence, rather than a report generated downstream of it.

Where PaC enforcement operates across the stack

PaC is a set of layers, each catching what the others structurally cannot. The Spacelift guide to PaC tools lays out five distinct layers, each with its own job. Pre-commit and pull-request scanning checks infrastructure-as-code files before they ever reach the main branch, catching developer-stage mistakes before they enter a pipeline at all. IaC pipeline enforcement gates a proposed infrastructure change against organizational rules at the point of provisioning, the plan-and-apply stage. Kubernetes admission control evaluates resources as they're admitted to a cluster, the last checkpoint before a workload actually runs. Cloud-provider guardrails enforce permission boundaries across accounts at the organizational level. And application authorization, the runtime layer, evaluates who can do what inside an application at the exact moment of each request. That's where BOLA and object-level authorization failures get caught or get missed entirely.

Spacelift frames the practical decision correctly: the question isn't which single tool to pick, it's where the gap sits, because each layer adds coverage the others don't provide. Application-level authorization carries requirements that look nothing like infrastructure governance. A microservice evaluating a live request in real time needs a policy engine that works inside tight latency budgets and handles typed, schema-validated attributes, and that's a different job entirely from the tool used to validate a Terraform plan before a merge. Kyverno offers a clean illustration of admission control doing its job: a policy rejects any pod attempting to run a privileged container before that pod ever enters the cluster, enforcing least privilege at the boundary instead of relying on catching the problem after the fact at runtime. The runtime layer is exactly where the TransUnion and Farmers Insurance failures would have been intercepted. A policy governing what an API integration is allowed to query, enforced on every single request, can't be quietly misconfigured the way a stolen OAuth token or an embedded credential can.

Diagram: Five Layers of Policy-as-Code Enforcement. Visualizes: Show the five distinct PaC enforcement layers as a vertical stack or stepped sequence, ordered from earliest to latest in the development-to-production flow.

The main PaC tools

Each PaC tool is built for a specific layer of that stack, and using the wrong tool for a layer produces a policy that looks complete on paper while missing the exact failure it was meant to stop. Spacelift's PaC tools guide, updated in May 2026, organizes the field by category and stage, and the shape of the landscape is worth laying out directly.

Open Policy Agent (OPA) is the general-purpose engine in this space. It's written in Rego, runs as a sidecar, daemon, or library, and integrates with Kubernetes through Gatekeeper, with Envoy and Istio, with Terraform, and with CI/CD pipelines. It's a CNCF graduated project, and it fits teams that want one vendor-neutral engine spanning microservices and cloud-native infrastructure alike.

Gatekeeper is Kubernetes-native, built on top of OPA, using custom resource definitions and Rego, and it's optimized specifically for cluster-level governance rather than OPA's broader scope.

Kyverno is also Kubernetes-native admission control, but it authors policy in YAML instead of Rego, which lowers the barrier for platform teams already comfortable working in YAML. Kyverno 1.17, released in February 2026, deprecated the legacy YAML and JMESPath ClusterPolicy types in favor of CEL-based policies, with legacy removal planned for a future version in October 2026.

Conftest is OPA's CLI companion. It evaluates Rego policies against structured configuration files, Terraform plan JSON, Helm charts, Kubernetes manifests, Dockerfiles, inside CI without standing up a server, and it runs the same Rego rules OPA uses without modification.

HashiCorp Sentinel sits at the IaC pipeline enforcement stage, with cloud provider integrations built around the plan-and-apply point in a deployment.

AWS Cedar, which underpins Amazon Verified Permissions, operates at the application-authorization layer. It enforces a strict schema upfront and compiles against known, typed entities, which catches attribute-access errors when the policy gets written rather than when it runs, and it's built specifically for externalizing authorization decisions out of application code.

AWS SCPs, Azure Policy, and GCP Org Policy all enforce permission boundaries at the organizational account level, the cloud guardrail layer. Checkov handles pre-commit and pull-request misconfiguration scanning of IaC files.

The choice between OPA and Cedar for runtime application authorization is a real tradeoff. OPA's dynamic JSON traversal is flexible, but that flexibility introduces latency and attribute-access risk that high-throughput systems may not be able to absorb. Cedar enforces its schema strictly upfront, which catches errors at policy creation instead of at query time. Teams planning long-term adoption around OPA should also watch a governance signal from August 2025: Apple hired OPA's maintainers, which raised questions about the project's commercial direction. The OPA project stated that governance and licensing haven't changed, but Apple's interest is itself a signal of how much strategic value this technology now carries, and it's worth tracking actively if a production deployment depends on it. For the runtime layer specifically, where BOLA and object-level failures actually occur, the field also includes purpose-built authorization services, distinct from the infrastructure-governance tools above, that externalize per-request decisions with lower latency and tighter schema enforcement than general-purpose engines offer. Those services are the right comparison when the use case is API-level access control rather than IaC governance.

Real deployments: Goldman Sachs, Netflix, AWS, and Strata Identity put PaC into production

The organizations running PaC at real scale all converge on the same move: pull authorization out of individual services and into one engine that every service boundary has to check. Goldman Sachs, Netflix, and Pinterest have deployed OPA to enforce authorization across microservices and Kubernetes clusters, and what links them is that policy logic lives in one place anyone can audit, instead of scattered across however many service codebases a company happens to run.

AWS Cedar, through Amazon Verified Permissions, externalizes authorization decisions so they can be managed and audited apart from application code, and in March 2026 AWS extended that model somewhere new: Cedar now runs as the policy engine inside Amazon Bedrock AgentCore Policy, intercepting every agent-tool call at the gateway boundary. The same enforcement model that governs a human clicking through an API now governs an autonomous agent deciding what to do next, and that's not a small step. Strata Identity's Maverics AI Identity Gateway runs an embedded OPA engine to evaluate fine-grained policy on MCP tool calls at the moment of request, so every tool invocation has to clear policy evaluation before it reaches any upstream service, which makes the policy engine itself the containment boundary for whatever the agent is trying to do. Both cases matter for the same reason: they show PaC moving out of infrastructure governance and into real-time authorization for AI agents, extending a control model built for APIs onto an attack surface that moves considerably faster.

Objections that slow PaC adoption

Adoption stalls on three honest problems, and none of them are imaginary. The first is low uptake among the people who actually have to write the policies: developers trained to ship features see policy authoring as a tax, not a feature, and a tool that nobody on the team writes for becomes a tool nobody maintains. The practical answer has been to push policy authoring toward formats teams already know, which is a large part of why Kyverno's YAML-based approach and its ongoing shift toward a more familiar expression language found traction among platform teams who never wanted to learn Rego in the first place. The second objection is maintenance burden: policies drift out of sync with the systems they govern just as fast as documentation does, and a stale policy that silently stops matching reality is arguably worse than no policy, since it creates false confidence. Treating policy as code, with the same version control, test suites, and peer review used for application code, is the direct answer to this, because a policy that fails its own test suite gets caught the same way a broken function does. The third objection is the most dangerous because it looks like success: false security from enforcement that only happens in the pipeline. A Terraform plan that passes every Conftest check still says nothing about what happens once a request hits a live API, and the TransUnion and Farmers Insurance breaches both ran straight through authorization boundaries that had pipeline-stage controls but no runtime enforcement watching the actual request. Pipeline gating catches what ships. Runtime enforcement catches what gets exploited, and treating the first as a substitute for the second is how a well-funded security program still ends up in a breach notification.

Sources

  1. Top 12 Policy as Code (PaC) Tools in 2026
  2. Policy-based access control is back for modern authorization
  3. Policy as Code: Benefits, Examples, and How to Get Started
  4. Top 10 Data Breaches of 2025 and What Caused Them
  5. API Security Breach Statistics 2026: Hidden Threats
Filed underControl Patterns

More in Control Patterns