Production Reference

OPA & Rego Cheatsheet

Operational reference for Open Policy Agent (OPA) and the Rego policy language. Rego syntax, Kubernetes admission patterns with Gatekeeper, OPA bundle workflow, and the testing flow that catches policy regressions before they reach production.

Command-firstProduction notesSecurity warningsHardened patterns

Rego language essentials

5 commands
package authz

Every Rego file is in a package. Queries reference this path: data.authz.allow.

Production note: Use a hierarchy that mirrors your services: data.kubernetes.admission.podsecurity, data.authz.payments.read.

default allow := false

Default rule: when no allow rule fires, return false. Always set defaults — undefined is not the same as false.

Warning: Without a default, undefined results may be coerced to false by some integrations and to "no decision" by others. Be explicit.

allow if { input.user.role == "admin" }

Rule body — Rego is "if all expressions hold, the rule succeeds". The body is implicit AND.

Production note: Multiple allow rules are OR-ed. Define multiple `allow` rules instead of nested OR conditions for readability.

deny[msg] if { input.request.kind.kind == "Pod" input.request.object.spec.hostNetwork msg := "hostNetwork is not allowed" }

Partial set rule — produces violations as set entries. Common pattern in Gatekeeper and admission control.

Production note: Each entry includes a human-readable message; surface these in admission webhook responses for fast debugging.

some i; input.containers[i].privileged

Iterate over a collection looking for any element matching the body. `some` introduces variables.

Production note: Quantifier patterns: `every i in input.containers { not c.privileged }` for "all must satisfy".

Built-in functions (most useful)

4 commands
startswith(input.image, "registry.example.com/")

String prefix match. Use for image registry allowlists.

Production note: Combine with regex.match() for richer patterns; never trust user-supplied strings without normalization.

time.now_ns()

Current time in nanoseconds. Use for time-window rules (e.g. business hours, ticket expiry).

Warning: Time-based rules are evaluator-dependent. In Gatekeeper, time.now_ns() may not reflect the cluster controller's clock identically.

json.unmarshal(input.annotations.policy, parsed)

Parse a JSON string into a Rego object. Useful when annotations carry policy metadata.

Production note: Wrap in error handling (`with default {}`) — malformed JSON will fail the rule otherwise.

crypto.sha256(input.payload)

SHA-256 hash. Useful for content-addressable policy keys.

Production note: OPA also has crypto.x509.parse_certificates() for cert chain analysis.

OPA CLI (eval, test, run)

5 commands
opa eval -d policy.rego -i input.json "data.authz.allow"

Evaluate a query against a policy file with input data. Primary smoke-test command.

Production note: Add -f pretty for readable output. Use --explain=full to debug rule evaluation.

opa test -v ./policies

Run all unit tests in the directory. Tests live in *_test.rego files alongside policy files.

Production note: Run in CI on every policy change. Failing policy tests should block merges to main.

opa fmt -w .

Format Rego files in place (like gofmt). Run before commit.

Production note: Pair with a pre-commit hook so policies stay formatted across contributors.

opa run --server policy.rego

Run OPA as a long-lived server. Loads policy at startup; serve queries over REST.

Production note: In production, prefer bundles over file mounts so policy can rotate without restarts.

opa bench -d policy.rego -i input.json "data.authz.allow"

Microbenchmark a query. Use to find policies that are too slow for the request path.

Production note: Target sub-millisecond evaluation for inline authz. Slow policies often have an O(N²) iteration that indexing or partial evaluation can fix.

Gatekeeper (Kubernetes admission)

4 commands
kubectl apply -f constraint-template.yaml

Install a ConstraintTemplate — defines a constraint kind (e.g. K8sRequiredLabels) backed by Rego.

Production note: ConstraintTemplate goes in cluster-scoped CRD; the Rego is in the spec.targets[].rego field.

kubectl apply -f constraint.yaml

Install a Constraint instance — applies the template to specific resources (kinds, namespaces).

Production note: Use enforcementAction: dryrun first to capture violations without blocking. Promote to deny once clean.

kubectl get constraints

List all active constraints across the cluster.

Production note: Each constraint reports violations in status.violations — perfect for dashboards and alerting.

kubectl describe constraint <name> | grep -A 10 violations

See current violations for a specific constraint.

Warning: Violations are an audit signal of past bad state. Existing resources don't get retro-blocked when you create a constraint.

OPA bundles (production policy distribution)

3 commands
opa build -b ./policies -o bundle.tar.gz

Build a bundle from a policy directory. Bundle is a tarball of .rego files plus metadata.

Production note: Sign bundles with cosign so OPA verifies provenance before loading.

services: policy-bundle: url: https://bundles.example.com

OPA config snippet that points at a bundle service. OPA polls for updates and hot-swaps policy.

Production note: Bundle service can be S3, GCS, OCI registry, or a custom HTTP server. OCI registries integrate cleanly with cosign signing.

opa run --server -c config.yaml

Run OPA as a server with bundle config. No file-mount, no restart-to-update.

Production note: Serves /v1/data/<package>/<rule> for policy queries. Configure proper readiness/liveness probes.

Testing & CI patterns

3 commands
test_admin_can_read if { allow with input as {"user":{"role":"admin"}} }

Rego unit test. Use `with input as ...` to inject test inputs.

Production note: Name tests test_<expectation_in_words> — they read like specifications when failing.

opa test --coverage --threshold 80 ./policies

Enforce policy test coverage threshold. Fails CI if below 80%.

Production note: Combine with --explain=fails to surface why specific tests broke.

opa eval -d policies -i sample-input.json "data.authz.allow" --partial

Partial evaluation — useful for ahead-of-time policy compilation.

Production note: Helps identify rules that are constant given known inputs; can dramatically speed runtime evaluation.

Hardened patterns

Common misconfigurations

The unsafe pattern, the replacement, and the reason the two are not equivalent in production.

FIXReview

Risky

package authz

allow {
  input.user.role == "admin"
}
# (no default)

Hardened

package authz

default allow := false

allow if {
  input.user.role == "admin"
}

Why it matters: Without a default, the rule produces undefined when no path succeeds. Some integrations treat undefined as deny, others as "no decision" passed up the chain. Always set an explicit default so policy behaviour is predictable across contexts.

FIXReview

Risky

# Image allowlist
deny[msg] if {
  not contains(input.image, "registry.example.com")
  msg := "untrusted image"
}

Hardened

# Image allowlist (anchored prefix)
deny[msg] if {
  not startswith(input.image, "registry.example.com/")
  msg := sprintf("image %s is not from a trusted registry", [input.image])
}

Why it matters: contains() matches the substring anywhere — an attacker registers "registry.example.com.attacker.com/img" and bypasses the check. startswith() with a trailing "/" anchors the match to the registry host; the message also identifies the offending image for fast triage.

FIXReview

Risky

# Constraint applied with deny enforcement on day one:
spec:
  enforcementAction: deny
  match:
    kinds:
    - apiGroups: [""]
      kinds: ["Pod"]

Hardened

# Roll out in dryrun first:
spec:
  enforcementAction: dryrun
  match:
    kinds:
    - apiGroups: [""]
      kinds: ["Pod"]
# Promote to deny only after status.violations is empty.

Why it matters: Going straight to deny on existing clusters blocks legitimate workloads that pre-date the policy. dryrun captures violations in status.violations without rejecting requests — once you can see (and fix) the gap, promote to deny in a controlled change.

Go deeper