What policy as code means
Policy as code is the practice of writing authorization, compliance and operational rules in a machine-readable language and managing them like software. Rules live in a repository, change through pull requests, pass automated tests and deploy through a pipeline. The alternative is a rule written in a document or clicked into a console, which is hard to review, hard to test and easy to forget.
The benefit is not novelty. It is that every change has an author, a reviewer, a timestamp and a diff, and that an automated check can tell you whether a proposed change breaks an existing expectation before it reaches production.
Languages and engines you will meet
Open Policy Agent uses a declarative language called Rego and is widely used for admission control, API authorization and infrastructure checks. Cedar, an open source policy language, is built around principals, actions and resources with a design that supports analysis of what a policy set permits. Kyverno expresses Kubernetes policy in YAML, which lowers the barrier for teams already living in manifests.
Each has trade-offs. A general-purpose engine is flexible but asks authors to learn a new language. A domain-specific tool is easier to read but covers fewer use cases. Choose by the decisions you must make, the skills your team has and the integrations you need, not by popularity.
What a healthy policy repository contains
- Policies: small, named rules with a single clear purpose and a comment explaining the intent.
- Tests: example requests with expected decisions, including cases that must be denied.
- Data: reference information the rules consult, such as team membership or data classifications, with a defined refresh path.
- Metadata: an owner, a version and a link to the requirement the rule implements.
- Pipeline definitions: linting, test execution and staged rollout.
Testing is the point
A policy that has never been tested against a denial is a policy of unknown value. Write tests for the allow cases the business needs and for the deny cases the risk team fears. Run them on every change. Where the language supports it, run analysis that shows what a change newly permits, because an accidental widening of access is the most expensive kind of bug.
Staged rollout matters as much as tests. Run a new policy in audit or dry-run mode first, compare its decisions with the current policy on real traffic and promote it only when the differences are understood.
Common failure modes
Teams often write policy as code but keep the exceptions in email. Every exception should be a code change with an expiry date. Another failure is policy sprawl: hundreds of rules with overlapping scope and no owner. Review the catalog on a schedule and retire rules that no longer map to a requirement.
A third failure is treating the language as the whole solution. Distribution, versioning, decision logging and enforcement still need design. Policy as code is the authoring discipline inside a larger control plane, not a substitute for one.
A practical adoption path
Pick one domain, such as Kubernetes admission or API authorization. Convert the five most important written rules into code with tests. Run them in audit mode for two weeks, fix the surprises and then enforce. Measure time to change a rule, number of denied requests and number of exceptions. Expand only when those numbers are stable.
A short example of the workflow
Consider a rule that says production workloads must run only images from an approved registry. An author writes the rule, adds a test that submits an approved image and expects an allow, and adds a second test with an unknown registry that expects a deny. A reviewer reads the diff, the pipeline runs both tests and the rule is published in audit mode. After a week of logs shows no surprises, the team switches it to enforce. Every step leaves a record, and the same path is used for the next rule.
That repeatable path is the real asset. The language matters less than the habit of treating each rule as a reviewed, tested, versioned change.


