Skip to main content

OPA Policy as Code: Rego Rules, Gatekeeper & CI Enforcement Guide

Open Policy Agent (OPA) is a CNCF graduated general-purpose policy engine that decouples policy decisions from application code. Write authorization rules, Kubernetes admission policies, and infrastructure guardrails in Rego — a declarative language designed for expressing complex policy logic as testable, versionable code.

✓ CNCF graduated project ✓ Kubernetes + API + Terraform ✓ Built-in test framework ✓ Policy bundles via OCI/S3 ✓ REST API for policy queries

What is OPA and Policy as Code?

Policy as Code means expressing your authorization rules, compliance requirements, and infrastructure guardrails as code files that can be version-controlled, reviewed, and tested — just like application code. Without policy as code, authorization logic is scattered across application code, Kubernetes RBAC YAML, Terraform configurations, and tribal knowledge in ops runbooks. OPA provides a single engine that evaluates policies consistently across all these systems.

OPA answers one question: is this request allowed? Your application (or webhook, or CI pipeline) sends a JSON object describing what is happening, and OPA returns a policy decision based on your Rego rules and any external data you've loaded.

Rego Language Basics

# policy.rego — basic allow/deny
package myapp.authz

import rego.v1

# Default deny — undefined rules evaluate as false
default allow := false

# Allow if user is admin
allow if {
  input.user.role == "admin"
}

# Allow GET requests to public paths
allow if {
  input.method == "GET"
  input.path[0] == "public"
}

# Allow users to access their own resources
allow if {
  input.method == "GET"
  input.path[0] == "users"
  input.path[1] == input.user.id
}
# Query OPA (input is passed as JSON)
echo '{
  "input": {
    "user": {"id": "alice", "role": "admin"},
    "method": "DELETE",
    "path": ["users", "bob"]
  }
}' | opa eval -d policy.rego -I 'data.myapp.authz.allow'
# Output: {"result": [{"expressions": [{"value": true}]}]}

OPA Playground and opa eval

# Install OPA
curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64_static
chmod +x opa && sudo mv opa /usr/local/bin/

# Evaluate a policy from CLI
opa eval \
  --data policy.rego \
  --data data.json \
  --input input.json \
  'data.myapp.authz.allow'

# Start OPA as REST server
opa run --server --addr :8181 policy.rego data.json

# Query via REST API
curl -X POST http://localhost:8181/v1/data/myapp/authz/allow \
  -H "Content-Type: application/json" \
  -d '{"input": {"user": {"role": "admin"}, "method": "GET"}}'

Kubernetes Gatekeeper: ConstraintTemplate Example

# Install Gatekeeper
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.15/deploy/gatekeeper.yaml

# ConstraintTemplate — defines the policy logic
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: requiredlabels
spec:
  crd:
    spec:
      names:
        kind: RequiredLabels
      validation:
        openAPIV3Schema:
          properties:
            labels:
              type: array
              items: {type: string}
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package requiredlabels
        violation[{"msg": msg}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("Missing required labels: %v", [missing])
        }
# Constraint — applies the policy to Pods in production namespace
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: RequiredLabels
metadata:
  name: pod-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces: ["production"]
  parameters:
    labels: ["owner", "team", "environment"]

OPA for API Authorization

// Express.js middleware — query OPA before processing requests
const axios = require('axios');

async function opaAuthz(req, res, next) {
  const input = {
    user: req.user,         // from JWT middleware
    method: req.method,
    path: req.path.split('/').filter(Boolean),
    resource: req.params.id,
  };

  const response = await axios.post('http://opa:8181/v1/data/myapp/authz/allow', {
    input,
  });

  if (response.data.result !== true) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  next();
}

app.use('/api', opaAuthz);

Testing Rego Policies

# policy_test.rego
package myapp.authz_test

import data.myapp.authz

test_admin_can_delete if {
  authz.allow with input as {
    "user": {"role": "admin"},
    "method": "DELETE",
    "path": ["users", "alice"],
  }
}

test_viewer_cannot_delete if {
  not authz.allow with input as {
    "user": {"role": "viewer"},
    "method": "DELETE",
    "path": ["users", "alice"],
  }
}

# Run tests
# opa test ./policies/ --verbose --coverage

CI Integration

# .github/workflows/opa.yml
- name: Run OPA tests
  uses: open-policy-agent/setup-opa@v2
  with:
    version: latest

- name: Test policies
  run: opa test ./policies/ --coverage --format=json > coverage.json

- name: Check Terraform plan (Conftest)
  run: |
    terraform plan -out=plan.tfplan
    terraform show -json plan.tfplan > plan.json
    conftest test plan.json --policy policies/terraform/

OPA vs Kyverno vs Casbin

Tool Language Kubernetes API authz Best for
OPARego (declarative)Via GatekeeperYesMulti-system policy
KyvernoYAMLNative CRDNoK8s-only, no Rego
CasbinPERM model + CSVNoYes (library)In-app RBAC/ABAC
Share this tool: X / Twitter LinkedIn
✓ 60,000+ developers use DevPlaybook ★★★★★ 4.8 / 5 on Gumroad ✓ MIT licensed · Instant download ✓ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚡ AI Code Review, Doc Generator & SQL Builder
  • ⚡ All premium templates & early access
  • ⚡ Member discounts on Gumroad products
Start Free Trial →

$9/mo after trial · Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro — $79 →

MIT licensed · Instant download · No subscription

See what's included → Browse all deals →