OPA Gatekeeper Issue #3928 Playground
This playground provides a complete environment to reproduce Gatekeeper issue #3928 with OPA Gatekeeper in a Kubernetes cluster using Kind.

- eth0
- /
- docker
What You Can Do
- Recreate Gatekeeper issue #3928
- Launch separate playgrounds with either a 1.29.12 or 1.32.3 Kind cluster
- Deploy Gatekeeper 3.15.1 (no defect)
- Or deploy Gatekeeper 3.18.3 (defect)
- Apply policy enforcement resources
- Test policy enforcement with the sample resources
Deploying Kind 1.29.12 and Gatekeeper 3.15.1
Deployment Files
Deployment files for reference:
- deploy.sh
- mutating-gatekeeper-3-15-1.yaml
- validating-gatekeeper-3-15-1.yaml
- cert-manager-resources.yaml
Observations
No defect observations for Gatkeeper 3.15:
- Support running seprate operations for each webhook, one for validating and one for mutation.
- Does not have an
operation=generatefor the audit webhook. - All mutation and valdation policies work as expected.
Running the Playground
- Open the playground in a separate browser tab
- Start playground with
kind.versionset to1.29.12under the Playground Parameters section above. - Once the playground fully starts, you control the deployment of the Gatekeeper environement by using
maketargets under the home directory of the playground.
Running Make Targets
Ensure you are in the home directory of the playground and run the following make targets in this order:
- Deploy Gatekeeper version 3.15.1.
make deploy-gk-3-15-1 - Apply all Gatekeeper policies (mutation and validation).
make apply-policy - Apply all example resources.
make apply-example-resources - Review the running gatekeeper instances and their configured operations.
- The gatekeeper mutation webhook is configured with only
mutation-webhookoperation. - The gatekeeper validating webhook is configured with only
webhookoperation. - The gatekeeper audit webhook is configured with
audit, status, mutation-statusoperations.
- The gatekeeper mutation webhook is configured with only
Deploying Kind 1.32.3 and Gatekeeper 3.18.3
Deployment Files
Deployment files for reference:
- deploy.sh
- mutating-gatekeeper-3-18-3.yaml
- validating-gatekeeper-3-18-3.yaml
- cert-manager-resources.yaml
Observations
Defect observations for Gatekeeper 3.18
- Cannot run seprate operations for each webhook, one for validating and one for mutation.
- As a potential workaround: Add the
webhookoperation to the mutation gatekeeper webhook in addition to themutation-webhookoperation.
- As a potential workaround: Add the
- The audit gatekeeper webhook MUST add the
generateoperation. - All mutation and valdation policies seem to work as expected.
Running the Playground
- Open the playground in a separate browser tab
- Start the playground with
kind.versionset to1.32.3under the Playground Parameters section above. - Once the playground fully starts, you control the deployment of the Gatekeeper environement by using
maketargets under the home directory of the playground.
Running Make Targets
Ensure you are in the home directory of the playground and run the following make targets in this order:
- Deploy Gatekeeper version 3.18.3:
make deploy-gk-3-18-3- The gatekeeper-mutating-controller-manager will fail to start due to Gatekeeper issue #3928.
- A potential workaround is to add the
operation=webhookto the gatekeeper-mutating-controller-manager deployment manifest. - Update the deployment manifest by running the following command:
sed -i '/- --operation=mutation-webhook/ a\ - --operation=webhook' deployment/mutating-gatekeeper-3-18-3.yaml- Re-run the
make deploy-gk-3-18-3target command
- Apply all Gatekeeper policies (mutation and validation):
make apply-policy - Apply all example resources:
make apply-example-resources - Review the running gatekeeper instances and their configured operations.
- The gatekeeper mutation webhook is configured with the potential workaround of
mutation-webhookandwebhookoperations. - The gatekeeper validating webhook is configured with only
webhookoperation. - The gatekeeper audit webhook is configured with
audit, status, mutation-status, generateoperations.
- The gatekeeper mutation webhook is configured with the potential workaround of
Validating the Fix — PR #4423
PR #4423 fixes issue #3928 by conditionally initializing the constraint/OPA client only when validation operations are enabled (operations.HasValidationOperations()). Since the constraint client is exclusively used for validation (constraints and constraint templates), it is no longer required for mutation-only deployments. The cache manager now handles a nil cfClient gracefully to prevent panics when mutation operations interact with the cache without a constraint client present.
With this fix, Gatekeeper can start successfully with --operation=mutation-webhook only — no workaround of adding --operation=webhook is needed.
Deployment Files
Deployment files for reference:
- deploy.sh
- mutating-gatekeeper-3-22-0.yaml
- validating-gatekeeper-3-22-0.yaml
- cert-manager-resources.yaml
Note: The deployment manifests use the development image
openpolicyagent/gatekeeper:70d79e4which contains the fix from PR #4423. This fix is expected to ship in the next official release (v3.23.0+).
Runtime Flags
Since this setup splits Gatekeeper into separate controllers (validating, mutating, audit), each deployment requires specific runtime flags. The constraint templates in this setup use Rego only (no CEL/K8sNativeValidation engine), so the Kubernetes ValidatingAdmissionPolicy (VAP) integration must be explicitly disabled. In Gatekeeper v3.22.x, several VAP-related flags default to true, which causes errors when the VAP API is not in use.
Validating Webhook (--operation=webhook)
| Flag | Default | Value | Purpose |
|---|---|---|---|
--operation | all | webhook | Run only the validating webhook |
--port | 443 | 8443 | Webhook listening port |
--exempt-namespace | — | gatekeeper-system | Exclude Gatekeeper's own namespace from admission |
--disable-opa-builtin | — | {http.send} | Disable http.send Rego builtin for security |
--enable-k8s-native-validation | true | false | Disable VAP/CEL driver initialization (Rego-only) |
--default-create-vap-for-templates | true | false | Prevent auto-generating ValidatingAdmissionPolicy resources |
--default-create-vap-binding-for-constraints | true | false | Prevent auto-generating ValidatingAdmissionPolicyBinding resources |
Mutating Webhook (--operation=mutation-webhook)
| Flag | Default | Value | Purpose |
|---|---|---|---|
--operation | all | mutation-webhook | Run only the mutating webhook |
--port | 443 | 8443 | Webhook listening port |
--exempt-namespace | — | gatekeeper-system | Exclude Gatekeeper's own namespace from admission |
--disable-opa-builtin | — | {http.send} | Disable http.send Rego builtin for security |
--disable-cert-rotation | false | true | Disable built-in cert rotation (cert-manager handles TLS) |
The mutating webhook does not need VAP flags because it has no validation operations — the constraint controller's
Add()method returns early whenHasValidationOperations()is false.
Audit Controller (--operation=audit,status,mutation-status,generate)
| Flag | Default | Value | Purpose |
|---|---|---|---|
--operation | all | audit, status, mutation-status, generate | Run audit and status reporting |
--disable-opa-builtin | — | {http.send} | Disable http.send Rego builtin for security |
--disable-cert-rotation | false | true | Disable built-in cert rotation (cert-manager handles TLS) |
--enable-k8s-native-validation | true | false | Disable VAP/CEL driver initialization (Rego-only) |
--default-create-vap-for-templates | true | false | Prevent auto-generating ValidatingAdmissionPolicy resources |
--default-create-vap-binding-for-constraints | true | false | Prevent auto-generating ValidatingAdmissionPolicyBinding resources |
Note: During startup, the constraint controller unconditionally calls
IsVapAPIEnabled()as part of controller registration (source). This produces a one-timeerror checking VAP API availabilitylog entry aterrorlevel in both the validating webhook and audit pods. This is benign — it only determines whether to register VAP binding watchers and does not affect constraint enforcement. No runtime flag can suppress this startup check.
For the full list of Gatekeeper runtime flags, see the Runtime Flags documentation.
Observations
Fix validation observations for Gatekeeper with PR #4423:
- The mutating controller starts successfully with only
--operation=mutation-webhook— the previousunable to create client: must specify at least one enforcement pointerror no longer occurs. - The
--operation=webhookworkaround documented in the 3.18.3 section is no longer required. - Separate operations for each webhook are restored: one for validating (
webhook) and one for mutation (mutation-webhook). - All mutation and validation policies work as expected.
Running the Playground
- Open the playground in a separate browser tab
- Start the playground with
kind.versionset to1.32.3under the Playground Parameters section above. - Once the playground fully starts, you control the deployment of the Gatekeeper environment by using
maketargets under the home directory of the playground.
Running Make Targets
Ensure you are in the home directory of the playground and run the following make targets in this order:
- Deploy Gatekeeper with the fix from PR #4423:
make deploy-gk-3-22-0- The gatekeeper-mutating-controller-manager should now start without errors using only
--operation=mutation-webhook.
- The gatekeeper-mutating-controller-manager should now start without errors using only
- Apply all Gatekeeper policies (mutation and validation):
make apply-policy - Apply all example resources:
make apply-example-resources - Review the running gatekeeper instances and their configured operations.
- The gatekeeper mutation webhook is configured with only
mutation-webhookoperation (fix validated). - The gatekeeper validating webhook is configured with only
webhookoperation. - The gatekeeper audit webhook is configured with
audit, status, mutation-status, generateoperations.
- The gatekeeper mutation webhook is configured with only
A real VM, not a container
Get root on a VM with its own kernel, so Docker, Kubernetes, and systemd just work.
Read the docs →
SSH from browser or CLI
Use the built-in web terminal, or connect with labctl ssh, plain ssh, scp, or rsync.
Read the docs →
Drive it with AI
Let Claude, Codex, or any MCP client start this playground and run commands in it.
Read the docs →
Expose HTTP(S) ports
Give any web app running inside the VM a public URL - for yourself or to share with others.
Read the docs →
Share terminals
Invite others into your terminal session, or open it yourself from another device.
Read the docs →
Customize with init scripts
Add shell scripts that run at boot to install packages, clone repos, or seed test data.
Read the docs →
Private networking
VMs reach the internet via NAT with no public IP; several VMs share bridge networks.
Read the docs →
Ephemeral or persistent
By default, VMs are destroyed when the session ends; enable persistence to keep the disks for next time.
Read the docs →
Built-in container registry
A private registry.iximiuz.com for every playground to share images across services and VMs.
Read the docs →