devops platformengineering/policyascode sitereliabilityengineering

OPA Intro and Deep Dive
Open Policy Agent (OPA) | Open Policy Agent
Rego Playground

Core Idea

OPA is a general-purpose policy engine that separates policy decisions from policy enforcement, so one Rego policy can gate anything in the stack.

  • Core architecture and philosophy, including the OPA evaluation cycle.
  • Rego (v1.0 standard) is the policy language: rule anatomy plus a hands-on REST API example with deny-by-default, role-based allows, and an audit list.
  • Key benefits of pulling policy out of application code.

OPA

Open Policy Agent (OPA) is an open-source, general-purpose policy engine that graduates out of the Cloud Native Computing Foundation (CNCF). It provides a unified framework to decouple policy decision-making from policy enforcement across your entire technology stack.

1. Core Architecture & Philosophy

The foundational philosophy of OPA is decoupling policy from application logic. Instead of hardcoding authorization rules (e.g., if (user.role == 'admin')) directly into your application code, database queries, or CI/CD pipelines, you delegate those decisions to OPA.

       [ Client Request ]
               β”‚
               β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚    Service / API      β”‚ <── (Policy Enforcement Point)
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚           β–²
  1. Ask β”‚           β”‚ 4. Return Decision
  for    β”‚           β”‚    (JSON)
  Query  β–Ό           β”‚
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚   OPA Policy Engine   β”‚ <── (Policy Decision Point)
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β–²           β–²
         β”‚           β”‚
     2. Policy   3. Data / Context
     (Rego)      (JSON)

The OPA Evaluation Cycle

  1. The Query (Input): A service receives a request (e.g., an API call, a Kubernetes admission review, or an SSH login). It packages this context as a structured JSON object and queries OPA.
  2. Evaluation: OPA evaluates this JSON input against loaded Rego policies and external system data.
  3. The Decision: OPA returns a structured JSON response representing the policy decision. This decision is not limited to a simple true/false; it can return strings, arrays, or complex nested JSON objects (e.g., a list of allowed endpoints or mutated configurations).

2. Key Benefits of OPA

  • Single Policy Language: Write policy rules for Kubernetes, HTTP APIs, Terraform/OpenTofu, SSH access, and Envoy proxies using a single language: **Rego**.
  • High Performance: OPA is written in Go and stores policies and data in-memory. It can make authorization decisions in sub-milliseconds, making it highly suitable for high-throughput APIs and microservice sidecars.
  • Declarative Logic: Rego focuses on defining what the system state should look like, not how to calculate it.
  • Inspectability and Testing: OPA provides built-in tooling to dry-run policies, trace evaluations step-by-step, and write native unit tests.

3. Writing Policies in Rego (v1.0 Standard)

Rego (pronounced β€œray-go”) is a declarative query language.

⚠️ Important Note: In OPA 1.0 (and modern configurations), the if and contains keywords are mandatory. Pre-1.0 formats that omit if or use older bracket notations for sets are deprecated. Always prepend your policy files with import rego.v1 to ensure compatibility.

Structural Anatomy of a Rule

  • Single-Value Rule: Evaluates to a single value (defaults to true if the value is omitted in the rule head).
  • Multi-Value (Partial) Rule: Builds a set of values. It requires the contains keyword.

4. Hands-on Example: Securing a REST API

To understand OPA in practice, let us look at a simple scenario where a web application needs to decide if an incoming HTTP request should be permitted.

Step 1: Define the Input (input.json)

This is the context the application passes to OPA:

{
  "user": "alice",
  "role": "developer",
  "action": "DELETE",
  "resource": "/billing/v1/accounts"
}

Step 2: Write the Rego Policy (policy.rego)

This policy uses Rego v1.0 syntax. It restricts deletion of billing resources to managers, while letting developers read them.

package authz

# Force OPA 1.0 syntax rules (mandatory 'if' and 'contains')
import rego.v1

# 1. Deny by default
default allow := false

# 2. Allow admins full access
allow if input.role == "admin"

# 3. Allow developers to read (GET) billing resources
allow if {
    input.role == "developer"
    input.action == "GET"
}

# 4. Create an audit list of policy violations
violations contains msg if {
    input.action == "DELETE"
    input.resource == "/billing/v1/accounts"
    input.role != "manager"
    msg := sprintf("Security Alert: User '%v' (role: %v) attempted unauthorized delete on billing endpoints.", [input.user, input.role])
}

Step 3: Run and Test Locally

You can evaluate policies directly using the OPA Command Line Interface (CLI):

# 1. Download OPA
curl -L -o opa https://openpolicyagent.org/downloads/v1.16.1/opa_linux_amd64
chmod +x opa

# 2. Evaluate the allow rule
./opa eval --data policy.rego --input input.json "data.authz.allow"

# 3. Evaluate the violations set
./opa eval --data policy.rego --input input.json "data.authz.violations"

Given our input (user: "alice", role: "developer", attempting a DELETE on a /billing resource), OPA will output:

  • data.authz.allow false
  • data.authz.violations ["Security Alert: User 'alice' (role: developer) attempted unauthorized delete on billing endpoints."]

5. Major Integration Ecosystems

Integration PointTooling / ImplementationAction Type
KubernetesOPA GatekeeperValidating & Mutating Admission Webhook
Infrastructure as CodeConftest (uses OPA)Command Line linter for Terraform/Helm prior to apply
Service Mesh / GatewayEnvoy Proxy, Kong, IstioAuthorization filter (External Authz API)
Linux Host SecurityLinux PAM moduleSSH login authorization checks

6. OPA Best Practices

  1. Keep Policies Stateless: Do not try to make OPA manage runtime database changes. Pass the database attributes as read-only context data inside the request payload (input) or load them as cached static bundles (data).
  2. Write Unit Tests: Rego supports native unit testing. Create policy_test.rego files alongside your rules and validate them using opa test . during CI/CD steps.
  3. Log Decisions: In production environments, configure OPA to ship its raw decision logs to a centralized collector (like Elasticsearch or Splunk). This creates a highly auditable ledger of exactly why requests were allowed or denied.
  4. Automate Syntax Migrations: If you are migrating older legacy Rego code to v1.0, you can run opa fmt --write --v0-v1 <filepath> to automatically insert the modern if and contains keywords.

OPA Gatekeeper

OPA for Kubernetes Admission Control | Open Policy Agent

OPA is the general-purpose engine, and OPA Gatekeeper is a specific product built to make OPA work seamlessly inside Kubernetes.

An easy analogy is to think of OPA as an engine and Gatekeeper as a specialized off-road vehicle built specifically to house that engine. You can put an OPA engine into an API gateway, a Linux server, or a CI/CD pipelineβ€”but Gatekeeper is the custom car body built strictly to drive it through Kubernetes.

  • Kubernetes Custom Resources (CRDs): Instead of manually managing raw Rego files, Gatekeeper allows you to declare policies using Kubernetes manifests called ConstraintTemplates and Constraints.
  • Audit Capabilities: Gatekeeper doesn’t just block bad deployments at the door; it continuously runs a background audit loop to scan existing resources in your cluster that might already be violating updated policies.
  • Data Replication: To make advanced policy decisions (like β€œEnsure every Ingress hostname is unique across the whole cluster”), Gatekeeper automatically syncs and caches cluster state into OPA’s memory so your rules have context.

OPA and Kyverno

Kyverno

The fundamental difference comes down to philosophy: OPA is a universal policy engine that can run anywhere, while Kyverno is a Kubernetes-native engine built specifically for Kubernetes resources using standard YAML.

FeatureOPA GatekeeperKyverno
ScopeUniversal (K8s, APIs, Envoy, Linux, CI/CD)Kubernetes-Only
Policy LanguageRego (a specialized query language)Standard Kubernetes YAML
Learning CurveSteep (requires mastering Rego syntax)Shallow (uses familiar K8s paradigms)
Primary CapabilitiesValidate, MutateValidate, Mutate, Generate
Resource GenerationNot natively supportedExcellent (e.g., auto-create NetworkPolicies for new namespaces)
PerformanceExtremely fast (compiled Rego evaluates in memory)Highly performant, but can scale linearly with massive YAML schemas
Ecosystem EcosystemCNCF Graduated (Massive, multi-industry adoption)CNCF Incubating (Rapidly growing, K8s-centric)

Which should you choose?

Choose Kyverno if: You are a pure Kubernetes shop, your team is already stretched thin, and you want to implement guardrails quickly using standard YAML. It is also the clear winner if you need to automatically generate resources (like default network profiles) on the fly.

Choose OPA Gatekeeper if: You need a single, unified policy framework that spans across your entire enterprise architectureβ€”not just Kubernetes. If you plan to enforce policies on APIs, CI/CD pipelines, public cloud IAM, and service meshes, OPA’s steep learning curve pays off at scale.