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.
Rego language essentials
5 commandspackage authzEvery 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 := falseDefault 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].privilegedIterate 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 commandsstartswith(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 commandsopa 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 ./policiesRun 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.regoRun 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 commandskubectl apply -f constraint-template.yamlInstall 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.yamlInstall 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 constraintsList 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 violationsSee 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 commandsopa build -b ./policies -o bundle.tar.gzBuild 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.comOPA 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.yamlRun 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 commandstest_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 ./policiesEnforce 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" --partialPartial evaluation — useful for ahead-of-time policy compilation.
Production note: Helps identify rules that are constant given known inputs; can dramatically speed runtime evaluation.
Common misconfigurations
The unsafe pattern, the replacement, and the reason the two are not equivalent in production.
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.
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.
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.
Related learning paths
Cloud Native Security Engineering — Policy as Code module
Module: design and ship OPA policy across admission, ingress, and microservice authz.
ContinueKubernetes Security Simulator
Practice spotting RBAC/admission misconfigurations including policy-as-code coverage.
ContinueOPA glossary entry
Definition and how OPA fits into a cloud-native security architecture.
Continue