35. Policy as Code
Policy as Code
TL;DR
- Policy-as-code (OPA/Gatekeeper, Kyverno) converts written standards into automated admission control checks that cannot be silently skipped or bypassed under deadline pressure.
- Enforcement makes the difference: a manual code-review policy is only as consistent as human reviewers; an automated policy gates admission automatically.
- OPA (Open Policy Agent) is a general-purpose policy engine usable across Kubernetes, API gateways, and CI/CD pipelines; Rego is its policy language.
- Gatekeeper implements OPA for Kubernetes (policies in Rego); Kyverno uses native Kubernetes YAML, making it gentler for teams familiar with manifest authoring.
- Audit/dry-run mode is essential before switching a policy to enforce — it catches unintended scope or logic errors against real cluster state without causing outages.
- Policy definitions deserve the same version control and PR review as Terraform or Kubernetes manifests, given their organization-wide blast radius.
Core Concepts
Manual review vs. automated enforcement
A written standard enforced through code review depends on every reviewer’s consistency, every time, under every deadline pressure — which means it’s not reliably enforced in practice. Policy-as-code converts that written rule into an automated admission control check: a Kubernetes resource missing required resource limits is rejected at deployment time automatically, regardless of whether a human happened to catch it. This removes reliance on human consistency for rules that should never have an exception.
Open Policy Agent (OPA) and Rego
OPA is a general-purpose policy engine not scoped to Kubernetes. Rego is OPA’s purpose-built policy language. The value of this generality is concrete: the same engine and often the same policy logic can enforce rules across multiple systems — Kubernetes admission control, API gateway authorization, CI/CD pipeline gates — rather than needing a separate, differently-configured policy tool for each system.
Gatekeeper: OPA for Kubernetes
Gatekeeper is OPA’s Kubernetes-native admission controller implementation. Policies are written in Rego. It provides generality (policies could theoretically be reused outside Kubernetes if needed) but requires teams to learn Rego, a new policy-specific language and mental model.
Kyverno: YAML-native policies for Kubernetes
Kyverno takes a different approach: policies are written as native Kubernetes YAML resources in the same syntax and mental model as Kubernetes manifests. This is the concrete reason for its reputation for a gentler learning curve — teams don’t need to learn Rego; they extend their existing Kubernetes YAML fluency. The trade-off: Kyverno is Kubernetes-specific, so policy logic cannot be reused outside Kubernetes.
Audit and dry-run mode before enforcement
A policy deployed directly in enforce mode without an audit phase risks immediately blocking legitimate, previously-working deployments — an overly broad or subtly incorrect policy doesn’t announce itself until something breaks. Running a new policy in audit/dry-run mode first — logging what would have been blocked against real, current cluster state without actually blocking — catches unintended scope or logic errors before causing an outage. Audit results inform safe graduation to enforce mode.
Version control and policy governance
Policy definitions directly control what can and can’t be deployed cluster-wide. An unreviewed, undocumented change to a policy has organization-wide blast radius. Policies deserve the same version control and PR-review discipline as Terraform or Kubernetes manifests — arguably more, given their enforcement authority.
Gatekeeper (OPA + Rego) vs. Kyverno
| Aspect | Gatekeeper | Kyverno |
|---|---|---|
| Scope | General-purpose across systems (K8s, API gateways, CI/CD) | Kubernetes-specific |
| Policy language | Rego (purpose-built, new syntax to learn) | Native Kubernetes YAML (extends existing fluency) |
| Learning curve | Steeper (Rego is a new language) | Gentler (YAML-based) |
| Generality/reusability | High — policies may apply outside Kubernetes | Low — Kubernetes-only |
| Enforcement entry point | Webhook (external to API server) | Direct admission control (built into API server) |
| Best fit | Multi-system policy consistency, complex rule logic | Kubernetes-focused teams, simpler policies |
Configuration / Command Reference
# Gatekeeper example: enforce resource limits on all pods
# 1. Install Gatekeeper (via Helm or manifests)
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml
# 2. Create a ConstraintTemplate (Rego policy definition)
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
not input.review.object.metadata.labels.app
msg := "Label 'app' is required"
}
# 3. Create a Constraint (instantiate the template in audit mode first)
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-labels
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
# Run in audit mode first
parameters: {}
# Kyverno example: same requirement, native YAML
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-app-label
spec:
validationFailureAction: audit # Start in audit mode
rules:
- name: check-app-label
match:
resources:
kinds:
- Pod
validate:
message: "Label 'app' is required"
pattern:
metadata:
labels:
app: "?*" # must exist and not be empty
# Check audit results (Gatekeeper)
kubectl get constrainttemplates
kubectl get constraints
kubectl logs -n gatekeeper-system deployment/gatekeeper-audit -f
# Check audit results (Kyverno)
kubectl get clusterpolicies
kubectl get policyreports -A
# Switch to enforce mode once audit looks good
kubectl patch K8sRequiredLabels require-labels --type merge -p '{"spec":{"match":{"excludedNamespaces":[]}}}'
Common Pitfalls
- Pitfall: A written standard (resource limits required) routinely missed in manual code review under deadline pressure. Why: Manual review is inconsistent; reviewers skip or deprioritize non-blocking feedback. Fix: Convert genuinely non-negotiable standards into automated admission control policies that cannot be bypassed.
- Pitfall: A new policy deployed directly in enforce mode, immediately blocking legitimate deployments because an unanticipated edge case wasn’t caught in audit mode first. Why: Skipping the audit phase means unintended scope is only discovered when real deployments fail. Fix: Always run new policies in audit/dry-run mode first; review audit results against real cluster state before switching to enforce.
- Pitfall: Policy definitions edited ad-hoc with no version control or review. Why: Nobody knows who changed an enforcement rule, why, or when — troubleshooting becomes a forensics exercise. Fix: Version-control and PR-review policy definitions with the same discipline as Terraform or Kubernetes manifests.
- Pitfall: A team learning Rego (Gatekeeper) when their need is Kubernetes-only and would benefit more from Kyverno’s native-YAML approach. Why: Unnecessary learning burden; tool fit was evaluated poorly. Fix: Evaluate Kyverno’s YAML-based approach for Kubernetes-only needs; Gatekeeper’s Rego complexity is justified only when multi-system policy reuse is needed.
- Pitfall: Policies becoming outdated — enforcing rules that no longer reflect current cluster usage patterns. Why: Policies are written but not reviewed or adjusted over time. Fix: Periodically review existing enforced policies for continued relevance and accuracy.
Interview Questions
- A written policy requiring resource limits on every container is routinely missed in code review. Design the fix. — Tests whether automated admission control is recognized as the durable answer versus reinforcing manual review processes.
- Why would you run a new admission control policy in audit mode before enabling enforce mode? — Tests understanding of the outage-prevention value of the audit/dry-run phase.
- When would you choose Kyverno over Gatekeeper (or vice versa) for a Kubernetes-only policy need? — Tests understanding of the Rego-versus-native-YAML authoring trade-off and tool fit.
- How would you ensure policy definitions remain maintainable and aligned with actual cluster usage over time? — Tests whether ongoing policy review and version control are treated as essential governance practices.