Safeguard
Security

Rego Policy Examples: Practical Rules for Policy-as-Code

Real Rego policy examples you can adapt today — from denying privileged containers to gating deployments on vulnerability severity — with the language patterns that make them readable.

Marcus Chen
DevSecOps Engineer
5 min read

The fastest way to learn Rego is to read working policies, so here are Rego policy examples that solve real problems — blocking privileged containers, requiring image registries, and failing a pipeline when a scan finds critical vulnerabilities — written the way you would actually deploy them with Open Policy Agent. Rego is a declarative query language, not a scripting language, and that trips people up until they see enough examples to internalize its rule-and-assignment model. This post is those examples, with just enough explanation to make each one adaptable.

Every snippet below assumes OPA. The modern idiom uses import rego.v1, which makes keywords like if, in, and contains explicit and is the style OPA has been steering toward.

Example 1: deny privileged containers

The canonical admission-control policy. Given a Kubernetes admission review as input, refuse any pod that runs a privileged container:

package kubernetes.admission
import rego.v1

deny contains msg if {
    some container in input.request.object.spec.containers
    container.securityContext.privileged == true
    msg := sprintf("container %q must not run privileged", [container.name])
}

deny is a set of strings. Each violating container adds a message. If the set is empty, nothing is denied. This set-of-messages pattern is the most common shape in policy-as-code because it reports every violation at once instead of stopping at the first.

Example 2: require images from an approved registry

A rule with a positive requirement expressed as a negation — deny anything that does not start with your registry prefix:

package kubernetes.admission
import rego.v1

allowed_registry := "registry.internal.example.com/"

deny contains msg if {
    some container in input.request.object.spec.containers
    not startswith(container.image, allowed_registry)
    msg := sprintf("image %q is not from the approved registry", [container.image])
}

The not startswith(...) line is where beginners stumble: Rego's not negates the whole expression, so this reads as "there exists a container whose image does not begin with the allowed prefix." That is a violation, so it joins deny.

Example 3: enforce required labels

Compare a set of required keys against the labels actually present:

package kubernetes.admission
import rego.v1

required := {"app", "owner", "env"}

deny contains msg if {
    provided := {k | some k, _ in input.request.object.metadata.labels}
    missing := required - provided
    count(missing) > 0
    msg := sprintf("missing required labels: %v", [missing])
}

This shows two of Rego's most useful features together: a set comprehension to collect the provided keys, and set subtraction to find what is missing. Once set operations click, a surprising amount of policy becomes one or two lines.

Example 4: gate a deployment on vulnerability severity

Policy-as-code is not only for Kubernetes. A common CI gate takes a scanner's JSON output and fails the build when critical findings exist:

package ci.securitygate
import rego.v1

max_critical := 0

deny contains msg if {
    criticals := [v | some v in input.vulnerabilities; v.severity == "CRITICAL"]
    count(criticals) > max_critical
    msg := sprintf("%d critical vulnerabilities exceed the allowed %d", [count(criticals), max_critical])
}

Feed this the findings from your composition-analysis run and OPA returns a clean pass or a list of reasons. This is exactly the kind of gate teams wire between a scan and a merge; if you use Safeguard, its findings export in a shape you can evaluate against a policy like this one. Our SCA overview covers what that finding data contains, and the Academy has a fuller policy-as-code walkthrough.

Example 5: a reusable helper

Rego lets you factor common logic into helper rules, which keeps large policy sets readable:

package lib.util
import rego.v1

is_production(obj) if obj.metadata.labels.env == "prod"

Import it and your production-only rules read like plain sentences. Small helpers like this are the difference between a policy set a team maintains and one everyone is afraid to touch.

Testing your policies

Rego has a first-class test framework, and untested policy is as dangerous as untested code — a broken gate either blocks every deploy or silently allows everything. Write tests as rules prefixed test_ and run opa test:

package kubernetes.admission
import rego.v1

test_denies_privileged if {
    deny["container \"web\" must not run privileged"] with input as {
        "request": {"object": {"spec": {"containers": [
            {"name": "web", "securityContext": {"privileged": true}}
        ]}}}
    }
}

The with input as construct swaps in mock input for one evaluation. Cover both the deny and the allow case for every rule; a policy that only ever tests the failure path can quietly stop enforcing anything.

FAQ

What is Rego used for?

Rego is the policy language for Open Policy Agent. It expresses rules as declarative queries and is used for Kubernetes admission control, CI/CD deployment gates, authorization decisions, and general policy-as-code where you want rules separated from application logic.

Why is deny a set instead of a boolean?

Making deny a set of messages lets one evaluation report every violation at once and attach a human-readable reason to each. An empty set means no violations. It is the idiomatic OPA pattern for admission and gating policies.

What does import rego.v1 do?

It opts into the modern Rego syntax where keywords like if, in, and contains are required and explicit. It makes rules less ambiguous and is the direction OPA has standardized on, so new policies should use it.

How do I test Rego policies?

Write rules prefixed with test_ in a _test.rego file, use with input as to supply mock data, and run opa test. Cover both the violating and the passing case for each rule so the gate cannot silently stop enforcing.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.