Policy-as-code gates

Kyverno & OPA enforce what must be true.

Advanced12 min · lesson 14 of 18

Signature verification is one policy; policy-as-code is the general capability behind it. A policy engine — Kyverno (Kubernetes-native, YAML) or OPA/Gatekeeper (general, Rego) — lets you express security requirements as code that is version-controlled, reviewed, and automatically enforced at admission or in CI. Instead of a wiki page saying "images should come from our registry and run non-root," the rule is a policy the cluster mechanically enforces on every deploy, with no room for it to be forgotten.

require-registry (Kyverno)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: { name: allowed-registries }
spec:
validationFailureAction: Enforce
rules:
- name: only-internal-registry
match: { any: [{ resources: { kinds: [Pod] } }] }
validate:
message: "images must come from registry.acme.internal"
pattern:
spec:
containers:
- image: "registry.acme.internal/*"

Policy in CI and at admission

Policy-as-code runs at two points, and both matter. In CI, tools like Conftest (OPA) or Kyverno CLI check manifests and configs before merge, so a bad setting is caught in review — fast feedback, shift-left. At admission, the same class of policy is the enforcement backstop that catches anything that bypassed CI or was applied directly. CI policy is the guardrail developers see; admission policy is the wall that actually holds. Run both, ideally from the same rule set, so what CI warns about is what the cluster enforces.

terminal
# shift-left: fail the build if a manifest violates policy, before it ever deploys
$ conftest test k8s/ --policy policies/ # OPA/Rego rules
$ kyverno apply policies/ --resource k8s/deploy.yaml # or Kyverno rules in CI
# the same policies then run as admission webhooks in the cluster as the backstop

What to enforce

A mature policy set encodes the whole chain’s requirements: images must be signed by your CI identity and carry provenance; images must come only from your registry; no :latest tags; workloads must be non-root with dropped capabilities and a read-only root filesystem (the Pod Security baseline); required labels and resource limits must be present. Each rule is one hole closed, expressed once, enforced everywhere, and reviewed like any other code — which is exactly what makes it reliable.

Policy is only as current as its review and exemptions
Policy-as-code drifts into theater two ways: broad exemptions that quietly swallow the workloads that matter ("exclude kube-system" becomes "exclude everything"), and stale rules nobody updates as threats change. Keep exemptions narrow, explicit, and reviewed; treat the policy repo as security-critical code with owners and change control; and periodically audit what is actually being exempted. An enforced policy full of holes is worse than an honest gap, because it looks covered.