Rego basics: rules & queries
How Rego actually evaluates.
Rego is OPA’s declarative language, and it thinks differently from imperative code. A rule defines the conditions under which something is true; OPA finds all the ways to satisfy it. Expressions in a rule body are implicitly ANDed, and a rule with the same name defined multiple times is implicitly ORed. Variables are not assignments so much as things Rego solves for, and iteration happens by unification rather than explicit loops.
package example# allow is true if ALL body lines hold (implicit AND)allow if {input.method == "GET"input.path == "/health"}# a second allow rule = OR: allow is also true if this holdsallow if {input.user.role == "admin"}
Iteration and the underscore
Rego iterates by referencing a collection with a variable (or _ for “any”): input.servers[_].port checks the port of every server, and the rule succeeds if any iteration satisfies the body. Comprehensions build new collections ([p | p := input.ports[_]; p > 1024]). This takes adjusting to — you are describing what must be true, and OPA searches for satisfying values — but it makes policies compact once it clicks.
package example# deny if ANY container runs as privileged (iterate with [_])deny contains msg if {c := input.spec.containers[_]c.securityContext.privileged == truemsg := sprintf("container %v is privileged", [c.name])}