CoursesPolicy-as-code at scaleDocuments, data, and packages

Documents, data, and packages

input, data, and how Rego loads the world.

In short. Rego never "runs a script against a cluster." It evaluates rules against documents: JSON (or YAML-as-JSON) trees. The document under inspection is usually `input`.

Advanced30 min · lesson 2 of 13

Rego never "runs a script against a cluster." It evaluates rules against documents: JSON (or YAML-as-JSON) trees. The document under inspection is usually input. Facts you load ahead of time — org charts, approved registries, exception lists — live under data. Packages namespace rules so data.kubernetes.admission.deny does not collide with data.terraform.deny.

If you treat Rego like Python with odd syntax, you will fight the language. If you treat it like a query over nested maps and sets, the same patterns scale from one ConstraintTemplate to a multi-repo library.

input vs data

Admission controllers typically put the admission review payload in input. CI tools like Conftest put the file you are scanning in input. data comes from files OPA loads (opa run -b bundle) or from Kubernetes resources Gatekeeper syncs. Confusing the two produces policies that work in unit tests (where you stuffed everything into input) and fail in production.

terminal
printf '%s\n' 'package example' 'deny contains msg if {' ' input.kind == "Pod"' ' not startswith(input.spec.containers[_].image, data.allowed.registry)' ' msg := "image registry not allowed"' '}' > /tmp/ex.rego
printf '{"allowed":{"registry":"ghcr.io/acme/"}}' > /tmp/data.json
echo '{"kind":"Pod","spec":{"containers":[{"image":"evil/x:1"}]}}' \
| opa eval -f pretty -I -d /tmp/ex.rego -d /tmp/data.json 'data.example.deny'
output
{
"evil/x:1 image registry not allowed"
}
Documents in an OPA decision
1Load data
bundles / synced resources
2Receive input
AdmissionReview or file JSON
3Evaluate package
rules query both trees
4Return decision
allow/deny set
Stable document shapes matter more than clever rules — version your input contracts.

Packages and rule names

package kubernetes.admission defines where rules live in the data document. Entry points like deny or violation are conventions your engine expects — Gatekeeper looks for violation, Conftest often uses deny. Name helpers clearly (is_privileged, has_valid_label) and keep them pure.

Hidden defaults
Undefined values in Rego are undefined, not false — until you use constructs that treat them carefully. Test both positive and negative fixtures.

Going deeper

Bundles package Rego + data as versioned artifacts. Sign and pin them. A cluster on bundle 2026.07.01 and CI on main will disagree — that disagreement is how "it passed CI" incidents happen. Treat bundle promotion like container image promotion.

Document schemas for input in each PEP: AdmissionReview versions differ; Conftest file wrappers differ. Provide JSON Schema or example fixtures next to policies so authors stop guessing field paths.

Avoid gigantic data trees synced from the whole cluster. Sync only kinds you query. Oversync hurts latency and memory and encourages accidental coupling to irrelevant objects.

When debugging, dump the exact input document your PEP sees — not the YAML you think you applied. Helm wrappers, defaulting webhooks, and Kyverno mutators change shapes before OPA/Gatekeeper evaluate.

Try this

Write a tiny policy that denies Pods missing metadata.labels.app, load it with opa eval, and feed both good and bad input.

terminal
printf '%s\n' 'package k8s' 'deny contains msg if {' ' input.kind == "Pod"' ' not input.metadata.labels.app' ' msg := "missing app label"' '}' > /tmp/label.rego
echo '{"kind":"Pod","metadata":{"labels":{}}}' | opa eval -f raw -I -d /tmp/label.rego 'count(data.k8s.deny)'
output
1

Takeaway

Rego evaluates packages over input and data documents. Get the document model right and every later pattern — tests, Gatekeeper, bundles — gets easier.

Next: make those rules testable with opa test and CI fixtures.

Quick check
01In admission-style policies, the object under review is usually…
Incorrect — data is preloaded facts.
Correct —
Incorrect — Unrelated to OPA.
Incorrect — No.
02Packages in Rego primarily…
Incorrect — No.
Correct —
Incorrect — JSON is still the document format.
Incorrect — Opposite of what you want.

Related