The Migration Problem
Imagine you've just joined a company and want to enforce "all Pods must have CPU and memory resource limits." The cluster has 800 existing Pods, and you have no idea how many violate this rule. If you deploy the policy with enforcementAction: deny, you won't delete running Pods (Gatekeeper only intercepts API requests, not running workloads), but you will block any kubectl apply that touches a non-compliant Pod — including routine deployments and rollouts. You could accidentally freeze your entire deployment pipeline.
The Three Enforcement Actions
Gatekeeper's enforcementAction field gives you a graduated rollout path:
| Action | Behavior | Use Case |
|---|---|---|
dryrun |
Requests are allowed through; violations are logged to the Constraint's .status.violations field |
Discovery: find out what's already broken |
warn |
Requests are allowed through; a warning is returned to the kubectl caller |
Soft enforcement: educate developers without blocking them |
deny |
Requests are rejected with a 4xx error | Hard enforcement: policy is fully active |
The Recommended Rollout Workflow
- Deploy in
dryrunmode. Let it run for a week. - Inspect violations:
kubectl get constraint <name> -o yaml— the.status.violationsfield lists every existing resource that would have been blocked. - Remediate: Work with teams to fix non-compliant resources.
- Switch to
warnmode. Developers see warnings but aren't blocked. Monitor for new violations. - Switch to
denymode. Policy is now fully enforced.
This workflow lets you introduce governance without causing production incidents.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-cost-center
spec:
enforcementAction: dryrun # Change to 'warn', then 'deny' over time
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["cost-center"]
A common interview question is: "How would you safely roll out a new Gatekeeper policy to a production cluster that already has hundreds of resources?" The answer is the dryrun → warn → deny progression. Mention that you'd use kubectl get constraint <name> -o jsonpath='{.status.violations}' to audit existing violations before switching to deny, and that you'd coordinate with teams to remediate before hard enforcement. This demonstrates operational maturity, not just technical knowledge.