From Kubernetes Gatekeeper to Full-Stack Governance with OPA

Pulumi’s OPA (Open Policy Agent) support is now stable. The v1.1.0 release of pulumi-policy-opa makes OPA/Rego a first-class policy language for Pulumi with full feature parity alongside the native TypeScript and Python policy SDKs. Write Rego policies that validate any resource Pulumi manages, across AWS, Azure, GCP, Kubernetes, and the rest of the provider ecosystem. If you already have Kubernetes Gatekeeper constraint templates, a new compatibility mode lets you drop those .rego files directly into a Pulumi policy pack and enforce them against your Kubernetes resources without modification.
What’s in the stable release
OPA/Rego is now fully supported as a policy language for Pulumi Insights, with the same capabilities as the TypeScript and Python SDKs:
- Resource and stack-level policies: Validate individual resources with
denyandwarnrules, or evaluate your entire stack at once withstack_denyandstack_warnfor cross-resource checks like relationship validation and resource count limits. - Enforcement levels: Control how violations are handled.
mandatoryblocks deployments,advisorysurfaces warnings, anddisabledturns rules off without removing them. Enforcement levels can be overridden per policy without modifying Rego source. - Policy configuration: Pass custom parameters to policies via configuration files, with optional JSON schema validation. Configuration values are accessible in Rego as
data.config.<policy_name>.<key>. - OPA metadata annotations: Use standard OPA
# METADATAcomments to provide titles, descriptions, and messages for your policies. These populate the policy metadata displayed in Pulumi Cloud. - Preventative and audit evaluation: OPA policies work with both preventative enforcement during
pulumi upand audit policy scans for continuous compliance monitoring.
You can choose whichever language best fits your team. Organizations already using OPA across their toolchain can standardize on Rego for Pulumi policies, while teams preferring TypeScript or Python can continue to use those. All three languages work side by side in the same policy groups.
Kubernetes Gatekeeper compatibility
The headline feature of this release is native support for Kubernetes Gatekeeper constraint template rules. If you’re running Gatekeeper as an admission controller in your clusters, you likely have a library of .rego policies that enforce security and operational standards at admission time. With v1.1.0, those same rules can now run as Pulumi policies, catching violations during pulumi preview before resources ever reach the cluster.
To enable Gatekeeper compatibility, set inputFormat: kubernetes-admission in your PulumiPolicy.yaml:
description: Kubernetes Gatekeeper Policy Pack
runtime: opa
inputFormat: kubernetes-admission
With this setting, Pulumi automatically wraps Kubernetes resources in the Gatekeeper AdmissionReview structure (input.review.object, input.review.kind, etc.), so your existing rules work without modification. Non-Kubernetes resources are silently skipped.
Here’s an example that reuses standard Gatekeeper-style rules, requiring an app label and prohibiting the latest image tag:
package gatekeeper
import rego.v1
# METADATA
# title: Require App Label
# description: All Kubernetes resources must have an "app" label.
violation contains {"msg": msg} if {
not input.review.object.metadata.labels["app"]
msg := sprintf("%s '%s' is missing required label: app",
[input.review.kind.kind, input.review.name])
}
# METADATA
# title: Disallow Latest Tag
# description: Container images must not use the "latest" tag.
deny contains msg if {
container := input.review.object.spec.template.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("container '%s' uses the 'latest' tag -- pin to a specific version",
[container.name])
}
These rules are identical to what you’d write for Gatekeeper. Both rule head formats are supported and can coexist: the violation[{"msg": msg}] map format and the deny[msg] string format. Per-policy configuration via input.parameters also works as expected. You can take a .rego file from your Gatekeeper constraint templates, drop it into a Pulumi policy pack, and publish it to Pulumi Cloud to enforce automatically across your stacks.
This shifts policy enforcement left. Instead of waiting for the Kubernetes API server to reject a resource at admission time, you catch the violation during pulumi preview, before anything is deployed.
Walkthrough: Reusing policies from the gatekeeper-library
The OPA Gatekeeper Library is a community-maintained collection of constraint templates covering common Kubernetes guardrails like pod security, image provenance, and resource limits. You can use these policies directly with Pulumi. Here’s an end-to-end example using the allowedrepos policy to restrict which container image registries your deployments can use.
Create a new Kubernetes OPA policy pack:
pulumi policy new kubernetes-opaCopy the Rego source from gatekeeper-library into your policy pack as
allowedrepos.rego. No modifications are needed:package k8sallowedrepos violation[{"msg": msg}] { container := input.review.object.spec.containers[_] not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.initContainers[_] not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("initContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.ephemeralContainers[_] not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("ephemeralContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) }Verify that your
PulumiPolicy.yamlhas Gatekeeper compatibility enabled:description: Kubernetes Gatekeeper Policy Pack runtime: opa inputFormat: kubernetes-admissionConfigure the allowed registries. Create a
policy-config.jsonfile to pass thereposparameter:{ "k8sallowedrepos": { "repos": ["gcr.io/my-company/", "docker.io/library/"] } }Test the policy locally against a stack:
pulumi preview --policy-pack . --policy-pack-config policy-config.jsonAny Kubernetes deployment using an image outside the allowed registries will produce a violation at preview time, before it reaches the cluster.
Publish the pack and add it to a policy group to enforce it across your organization:
pulumi policy publish
The same approach works for any policy in the gatekeeper-library: containerlimits, requiredlabels, disallowedtags, and others. Copy the Rego, configure parameters, and publish.
Part of the Pulumi Insights governance story
OPA policy support is part of the broader Pulumi Insights governance platform. Insights gives you visibility and compliance across your entire cloud footprint, and OPA policies plug directly into that:
- Audit policy scans continuously evaluate OPA policies against your Pulumi stacks and discovered cloud resources, providing a compliance baseline without redeploying anything.
- Self-hosted execution lets you run policy evaluations on your own infrastructure using customer-managed workflow runners, keeping credentials and data within your network.
- Pre-built compliance packs for CIS, NIST, PCI DSS, and other frameworks are available alongside your custom OPA policies in the same policy groups.
Whether you’re enforcing policy at deployment time, scanning existing infrastructure for drift, or running continuous compliance checks, OPA policies are a native participant.

Frequently asked questions
Do I need to modify my existing Gatekeeper .rego files?
No. Set inputFormat: kubernetes-admission in your PulumiPolicy.yaml and your existing Gatekeeper constraint template rules work as-is. Pulumi handles the AdmissionReview wrapping automatically.
What happens with non-Kubernetes resources?
When using inputFormat: kubernetes-admission, non-Kubernetes resources are silently skipped during evaluation. Your Gatekeeper rules only run against Kubernetes resources.
Do I need OPA installed locally?
No. The pulumi-policy-opa analyzer plugin embeds the OPA evaluation engine and is installed automatically by the Pulumi CLI (v3.227.0+). The standalone OPA CLI is only needed if you want to run opa test against your policies independently.
When should I use OPA vs. TypeScript or Python for policies?
If your team already writes Rego for other tools like Gatekeeper, writing Pulumi policies in Rego keeps your policy language consistent. If your team is more comfortable with general-purpose languages or needs auto-remediation, use the TypeScript or Python SDKs.
Gatekeeper constraint templates can be reused directly via the kubernetes-admission input format, but other OPA integrations use different input structures, so those policies would need to be adapted to Pulumi’s resource model. All three languages work together in the same policy groups.
Get started
Templates are available for kubernetes-opa, aws-opa, azure-opa, and gcp-opa via pulumi policy new. For more details, see the policy authoring guide and the Policy as Code overview.