LearnDevOps
DevOps10. DevSecOps·EXPERT·6 min read

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.
🔒 Locked
Sign in and unlock the full syllabus to keep reading.
Sign in to continue
Knowledge check
5 scenario questions on this topic
Take the quiz →
Related in 10. DevSecOps
32. Secrets Management
EXPERT
33. Supply Chain Security
EXPERT
34. Vulnerability Management
EXPERT
36. Runtime Security
EXPERT