Open Policy Agent: The Policy Engine That Rewrote Its Own Language

Styra — founded 2015 by two ex-Nicira/VMware engineers who had built OpenStack's Congress policy engine — pushed the root commit on 2015-12-28. The Rego language, the Gatekeeper CRD rebuild, the 1.0 syntax purge, and a 2025 Apple acquihire followed.

Sources

Every platform team eventually rediscovers the same problem: authorization logic is smeared across API gateways, service meshes, Kubernetes admission, CI pipelines, and a hundred if-statements nobody dares to delete. Open Policy Agent was built in 2015 to collapse all of it into one declarative engine with one query language. It succeeded so thoroughly that the language itself became the product — and then, eight years in, the project did something almost nothing in the CNCF portfolio has dared: it broke its own syntax on purpose, shipped OPA 1.0, and deprecated every policy ever written for v0. This is the archaeology of how a two-founder startup became the cloud's default authorization engine — the sidecar model it abandoned, the CRD rebuild that made Gatekeeper, the audit that embarrassed it into hardening, and the acquihire that left its founding company gone while the engine keeps shipping.

The Origin: Congress Veterans and a Christmas Root Commit

The two people who wrote the first lines of OPA were not Kubernetes people. Tim Hinrichs and Teemu Koponen came out of Nicira — the software-defined networking company VMware acquired in 2012 — and Hinrichs spent his VMware years working on OpenStack Congress, a policy engine for OpenStack whose entire premise was that infrastructure policy should be a declarative query over a database of resources. That premise did not survive contact with OpenStack's politics, but it survived in its author. When Hinrichs and Koponen heard customers complain that authorization had to be re-implemented in every layer of every system, they left to build the general version. They founded Styra in 2015 and started the Open Policy Agent project, as Cisco's investment team later told it, "to unify policy enforcement across different technologies and systems."

The repository's birth is unusually well-documented, because the root commit is the project's founding act:

open-policy-agent/opa  (GitHub repo ID 48714685, created 2015-12-28T22:08:25Z)
├── root  7eb56674  "Initial commit"                                  (timothyhinrichs, 2015-12-28)
├──       f260b790  "Merge pull request #2 from timothyhinrichs"     (timothyhinrichs, 2015-12-28)
├──       cecbc342  "Add parser test"                                 (timothyhinrichs, 2016-01-04)
├──       9cfea2c2  "Add jsonlog parser"                             (timothyhinrichs, 2016-01-06)
├──       1c4494e1  "Changed representation of dictionary
│                     to handle variables"                           (timothyhinrichs, 2016-01-06)
└──       fdda9817  "Merge pull request #73 from tsandall/dev"       (tsandall,         2016-07-22)
         — by mid-July 2016: string built-ins, regexp built-ins, cross-compile refactors

Read the commit messages and the design priority is obvious: OPA began as a language implementation, not a Kubernetes tool. Before there was a Docker image, before there was an admission webhook, there was a parser — a query language over JSON that became Rego, inspired by Datalog, with implicit joins over nested document data. Torin Sandall shows up in the history in 2016 building the standard library — string manipulation, regexp match built-ins — and becomes the project's co-creator and most public face for the next decade. The "agent" in the name is doing honest work: the 2016-era vision was a daemon, or a Go library, that any system could call for a policy decision over HTTP or in-process.

That generality is the first thing platform engineers should internalize about OPA, because it explains everything that came later — including the crisis points. OPA was never a Kubernetes admission controller. Kubernetes was one integration among many: in the early years the docs carried recipes for Docker engine authorization plugins, HTTP API authorization, SSH daemon integration, and even PAM policies for sudo — the CNCF's 2018 Cure53 audit literally reproduces a scenario where OPA decides who may run sudo on a Linux host. The Kubernetes story, the one that made OPA famous, arrived later and was rebuilt twice.

The Timeline: From Sidecar ConfigMaps to the CNCF's Authorization Standard

Crisis Points & Architectural Pivots

Crisis one: the ConfigMap sidecar model. OPA's first Kubernetes story was operationally honest but primitive. You ran an OPA pod, attached the kube-mgmt sidecar, and the sidecar discovered policies by scanning ConfigMaps labeled openpolicyagent.org/policy=rego and syncing their contents into the engine:

apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-policy
  labels:
    openpolicyagent.org/policy: rego      # kube-mgmt syncs this ConfigMap into OPA
data:
  policy.rego: |
    package kubernetes.admission
    deny[msg] {
      input.request.kind.kind == "Ingress"
      not input.request.object.spec.tls
      msg := "ingress must be TLS-only"
    }

This is the shape the Kubernetes blog post later described as Gatekeeper v1 — "OPA as the admission controller with the kube-mgmt sidecar enforcing configmap-based policies… donated by Styra" — with v2 a Microsoft donation of the same idea with audit bolted on. The toil was structural, not incidental: policies were opaque ConfigMap blobs with no parameters, no reusable abstractions, no cluster-visible state of what was enforced, and drift between clusters was invisible. Every team that adopted it ended up maintaining a private library of copy-pasted Rego. The v3 rebuild — announced August 6, 2019 as "a collaboration between Google, Microsoft, Red Hat, and Styra" — moved the entire policy lifecycle into Kubernetes resources:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
        listKind: K8sRequiredLabelsList
        plural: k8srequiredlabels
        singular: k8srequiredlabels
      validation:
        openAPIV3Schema:            # parameters the constraint instances will pass
          properties:
            labels:
              type: array
              items: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        deny[{"msg": msg, "details": {"missing_labels": missing}}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("you must provide labels: %v", [missing])
        }

One CRD now carries the Rego and the parameter schema; administrators instantiate it as ordinary constraint CRDs (kind: K8sRequiredLabels) with a match block and parameters; audit results are written back to the constraint's own status. The shareable-template problem — Gatekeeper's explicit design goal, "to enable users to customize admission control via configuration, not code" — was solved by the same primitive every other Kubernetes operator uses. The pivot is a close structural cousin of Helm deleting Tiller: the K8s integration was rebuilt to be Kubernetes-native, and the old path (kube-mgmt still lives, unarchived, in the OPA org) became a relic you should not build on today.

v1/v2 ERA (2017-2019): policies ride ConfigMaps into a sidecar-synced engine

  kube-apiserver ──webhook──▶ gatekeeper pod
                                ├─ OPA           (policies + data, in memory)
                                └─ kube-mgmt     (sync loop)
                                       ▲
                                ConfigMaps labeled openpolicyagent.org/policy=rego
                                (hand-authored, per-cluster, opaque)

  toil: no parameters, no reusable templates, no enforcement state on objects,
        no audit record, silent drift between clusters

v3 ERA (2019-present): policies are cluster resources

  kube-apiserver ──webhook──▶ gatekeeper v3 controller (kubebuilder)
       ▲                            ├─ OPA as embedded library (in-process)
       │                            └─ constraint framework
       │ CRD watch / reconcile
  ConstraintTemplate CRD ──▶ generates Constraint CRD kind ──▶ constraint instances
  (Rego + parameter schema)                              (match + parameters)
                                                        ──▶ deny/warn at admission
  violations written back to constraint status (audit) — enforcement state is queryable

Crisis two: the language. By the early 2020s the number-one community complaint about OPA was not performance or the engine — it was that Rego's v0 rule bodies were hard to read. A rule was just a name, followed by a bare brace block, and every line inside was an implicit conjunct; there was no visible keyword separating the rule head from its body, and comprehension-heavy idioms made authoring errors common. The project's answer was a two-year, opt-in deprecation: the new syntax shipped first as "future keywords" (if, in, every) behind explicit imports, then v0.59.0 (November 2023) added a --rego-v1 flag to opa fmt and opa check so teams could migrate their modules a year ahead, and finally OPA 1.0 (December 20, 2024) flipped the default:

v0 (every OPA release before 1.0):

  package example

  allow {
    input.method == "GET"
    input.path == ["salary", employee_id]
    data.salaries[employee_id] == input.user
  }

v1 (OPA 1.0+, December 2024 — default, no imports needed):

  package example

  allow if {
    input.method == "GET"
    input.path == ["salary", employee_id]
    data.salaries[employee_id] == input.user
  }

  multi-value rules gain 'contains':
    allowed_users contains user if user in data.admins

  'in' and 'every' need no future-keywords imports;
  strict-mode checks (duplicate/shadowing imports) become defaults.
  Legacy policies keep compiling behind the v0 compatibility flag.

Credit where due: this was a deprecation done the way the CNCF wishes every project did it — two years of opt-in, a mechanical migration flag, a compatibility mode, and a hard cutover only at a major version that also bought users a 10–20% evaluation speedup from a batch of memory-allocation rewrites (PRs #7172–#7222, Anders Eknert). The cost was real anyway: every Rego tutorial, blog post, and library written before December 2024 now renders in a syntax the current engine treats as legacy, and every large policy estate had to budget a migration sprint. Ask any team that ran it what their CI said the week they upgraded without reading the release notes.

Crisis three: the founding company disappears. In August 2025, Apple acquihired Styra — the three founders and several engineers moved over, and the company wound down with no public acquisition filing, as the CNCF Atlas history records it. For most CNCF projects that would be a governance scare; for OPA it landed on a graduated project with foundation-owned governance, an audited security process, and a maintainer bench that keeps shipping: the 1.21 indexer rewrite (September 2026) and v1.22.0's rego.v2 import (October 2026) both landed post-acquihire, and conftest gained a new independent maintainer in September 2026. The uncomfortable fact is still on the screen in MAINTAINERS.md: every maintainer of the core opa repository area is now Apple-affiliated. The single-employer maintainer concentration that killed countless open source projects is now OPA's structural risk, mitigated — so far — only by CNCF governance and Apple's continued investment. Watch that table.

Community Engine & Corporate Influence: Who Actually Built It

The CNCF arc was fast by foundation standards: sandbox March 29, 2018; incubating April 2, 2019; graduated January 29, 2021 — announced February 4 with production users from Goldman Sachs, Netflix, Pinterest, and T-Mobile, 90+ individuals from ~30 organizations, and maintainers from four companies (Google, Microsoft, VMware, Styra). The graduation press release also carries the two incubation-era security audits (OPA's Cure53 report and Gatekeeper's own audit) and the user-survey stat platform teams still quote: 91% of ~150 surveyed organizations ran OPA somewhere between QA and production, with configuration authorization — Kubernetes admission — and API authorization the two dominant use cases. Cisco Investments counted OPA as the 15th CNCF graduated project and the first focused on authorization.

The commercial engine behind the first five years was Styra: founded 2015 by Tim Hinrichs and Teemu Koponen (ex-Nicira, where Hinrichs went on to build OpenStack's Congress policy engine at VMware), with Bill Mann installed as CEO in 2018, a $14M Series A led by Accel in November 2019, and a $40M Series B led by Battery in May 2021 — by then claiming over a million OPA downloads a week. Torin Sandall, the third OPA co-creator, was the project's public face for most of that decade. The company monetized a management plane (Styra DAS) over the engine it had given away; the engine's growth curve — 75M+ downloads by the Series B announcement — is the open source working as intended.

Today's maintainer table, straight from the repository's MAINTAINERS.md, tells the post-Styra story with unusual candor. Core opa: Anders Eknert, Ash Narkar, Charlie Egan, Stephan Renatus, Tim Hinrichs, Torin Sandall — all Apple. The Gatekeeper cluster (gatekeeper, gatekeeper-library, frameworks/constraints, cert-controller, external-data-provider): Max Smythe at Google, Sertaç Özercan and Jaydip Gabani at Microsoft. Conftest: James Alseth, independent, added September 30, 2026. The emeritus list — Rita Zhang (Microsoft, co-author of the Gatekeeper v3 announcement), Patrick East, Will Beason, Ernest Wong, Craig Tabita, Oren Shomron, Andrew Peabody, Nilekh Chaudhari — reads like a roster of every era: the Styra founding years, the Microsoft-Google Gatekeeper collaboration, and the CNCF-era contributors who carried the project to graduation.

The ecosystem footprint is where OPA's real gravity shows. The open-policy-agent GitHub organization spans the engine (12.4k stars), Gatekeeper (4.3k stars), the constraint frameworks, the template library, conftest for config testing, the Envoy authorization plugin, and the certificate controller that bootstraps Gatekeeper's webhook TLS. Rego long ago escaped the admission niche: it now tests Terraform plans in CI, authorizes API calls in service meshes, gates CI pipelines, and powers commercial authorization products — the "policy as code" category that Cisco's investors credited Styra with creating. The engine's adoption story is the same one the Helm tale tells: the artifact everyone standardized on (there, the chart format; here, a query language) outgrew the tool that shipped it.

Current Trajectory: The Verdict

The trajectory question for OPA in late 2026 is not whether the engine works — v1.22.2 shipped six days before this tale, and the 1.x line's biggest recent change is a new rego.v2 import in v1.22.0, which tells you the project's center of gravity is still the language. The question is who needs a general-purpose policy engine now that the platforms have learned from it. Kubernetes 1.30 graduated ValidatingAdmissionPolicy (April 2024): CEL expressions evaluated in-process by the API server, no webhook, no sidecar, no extra failure domain — and its own KEP is explicit that it targets "the vast majority of validating admission use cases." For simple label checks, resource limits, and security-context validation, the honest engineering answer is the in-tree feature; running Gatekeeper for those is paying the webhook tax to keep a language you may not need (we run the numbers in our Gatekeeper vs. Kyverno guide).

What CEL cannot do — by design — is everything that made OPA bigger than admission in the first place. A ValidatingAdmissionPolicy sees the request in front of it; it does not join the object against your CMDB, your ownership data, or your spend graph without more machinery, and the same CEL policy does not follow your service out of the cluster into your API gateway, your CI pipeline, and your data layer. OPA's defensible territory is exactly the original 2015 thesis: one declarative language, one engine, policy decisions wherever the data lives — admission being merely the highest-volume integration. The performance envelope is actively managed: the 1.21 release rewrote rule indexing for large policy sets (see our 1.21 release coverage for the numbers and two silent breaking changes worth knowing about), and 1.22 extended partial evaluation to unroll every over known domains — the compile-time work that makes data-filtering use cases viable.

Verdict: OPA is the rare infrastructure project that survived two acts of institutional courage — donating its core asset to a foundation before its Series A, and deleting its own v0 syntax at the height of its adoption — and its current form is more library and language than product. Who should skip it? Clusters on Kubernetes ≥1.30 whose entire policy estate is simple admission checks should use ValidatingAdmissionPolicy and skip the webhook infrastructure; teams that would have to hire or train for Rego specifically for one use case should not bother — the language rewards exactly the platform teams that get leverage from writing policy once and enforcing it everywhere; and organizations allergic to the current bus-factor risk of an all-Apple maintainer bench should pin their OPA versions and watch MAINTAINERS.md more closely than the release notes. Everyone else — platform teams building golden paths, anyone unifying authorization across K8s admission, API gateways, and CI, and anyone who wants their infrastructure rules to be a queryable, testable artifact rather than scattered if-statements — gets the most honest answer in the policy space: a language that a decade of production use has failed to dislodge, maintained by the people who wrote it, shipped twice in the two weeks this tale was written. (For the delivery tools that consume OPA policies at deploy time rather than admission time, see our Argo CD and Flux tales; for the packaging half of the platform equation, the Helm tale covers the other engine that standardized a format and then had to delete part of itself to grow up.)