You can't review every K8s manifest manually. Policy-as-code automatically enforces rules: no latest tags, resource limits required, no root containers. This lesson teaches OPA Gatekeeper — the Kubernetes policy engine.
What Policy-as-Code Does
Essential Production Policies
Install Gatekeeper
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper gatekeeper/gatekeeper \
-n gatekeeper-system --create-namespace
Policy 1: No latest Tag
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdisallowedtags
spec:
crd:
spec:
names:
kind: K8sDisallowedTags
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdisallowedtags
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("Container '%v' uses :latest tag", [container.name])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDisallowedTags
metadata:
name: no-latest
spec:
match:
kinds: [{ apiGroups: [""], kinds: ["Pod"] }]
namespaces: ["production"]
Policy 2: Resource Limits Required
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredresources
spec:
crd:
spec:
names:
kind: K8sRequiredResources
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredresources
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits
msg := sprintf("Container '%v' must have resource limits", [container.name])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResources
metadata:
name: require-limits
spec:
match:
kinds: [{ apiGroups: [""], kinds: ["Pod"] }]
namespaces: ["staging", "production"]
Policy 3: No Root Containers
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8snoroot
spec:
crd:
spec:
names:
kind: K8sNoRoot
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8snoroot
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not input.review.object.spec.securityContext.runAsNonRoot
msg := "Pods must set securityContext.runAsNonRoot: true"
}
What Happens When a Policy Blocks
Policies are GitOps-managed too. Store your ConstraintTemplates and Constraints in the GitOps repo. ArgoCD syncs them. The policies themselves are version-controlled, reviewed, and deployed via the same process as everything else.
🧠 Recall Check
- At what point does Gatekeeper enforce policies — build time or deploy time?
- What's a ConstraintTemplate vs a Constraint?
- If ArgoCD tries to sync a Deployment that violates a policy, what happens?
- Name three policies every production cluster should have.
Reveal answers
- Deploy time (admission). Gatekeeper is a Kubernetes admission webhook — it intercepts API requests BEFORE resources are created/updated.
- ConstraintTemplate = the rule logic (Rego code). Constraint = where/when to apply it (which namespaces, which resource kinds).
- The sync fails. ArgoCD shows the app as "Degraded" with the admission error. The violating resource is NOT created.
- No
:latesttags, resource limits required, no root containers. Also valuable: no LoadBalancer services (use Ingress), require labels, max replica limits.
Next lesson: Pipeline Optimization & Cost — making everything fast and cheap.