Stage 4 · Provision
GitOps Workflows
Policy Enforcement in GitOps
Kyverno, Gatekeeper, and admission control — validating resources before they reach the cluster.
Why Enforce Policies?
GitOps ensures all changes flow through Git. But not all Git changes are safe. Policies validate resources before they reach the cluster — blocking images from untrusted registries, requiring resource limits, enforcing labels, and preventing privileged containers.
Admission controllers run inside the Kubernetes API server. They intercept every resource creation and modification request. If a policy denies the request, the API server rejects it. This is the last line of defense.
Kyverno
Kyverno is a Kubernetes-native policy engine. Policies are written in YAML (not Rego). Kyverno validates, mutates, and generates resources. It integrates with Kubernetes admission webhooks and does not require a separate policy language.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-team-label
spec:
validationFailureAction: Enforce
rules:
- name: check-team-label
match:
any:
- resources:
kinds: ["Deployment", "Service", "ConfigMap"]
validate:
message: "The label 'team' is required."
pattern:
metadata:
labels:
team: "?*"The ClusterPolicy applies to all namespaces. validationFailureAction: Enforce blocks non-compliant resources. The pattern validates that the team label exists with any value.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-image-registries
spec:
validationFailureAction: Enforce
rules:
- name: validate-registries
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "Images must come from approved registries."
pattern:
spec:
containers:
- image: "ghcr.io/* | gcr.io/my-project/*"This policy restricts container images to ghcr.io or a specific GCR project. Any pod using images from other registries is denied. The pipe (|) operator represents OR in the pattern.
Gatekeeper (OPA)
Gatekeeper is the Kubernetes-native implementation of OPA (Open Policy Agent). Policies are written in Rego. Gatekeeper is more flexible than Kyverno but requires learning Rego. It is a CNCF graduated project.
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("Missing required labels: %v", [missing])
}The ConstraintTemplate defines a reusable policy in Rego. The violation rule produces messages for resources missing required labels. The template is parameterized — each Constraint specifies which labels are required.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment"]
parameters:
labels:
- "team"
- "environment"
- "cost-center"The Constraint applies the K8sRequiredLabels template to all Deployments. The parameters specify which labels are required. Any Deployment missing team, environment, or cost-center is denied.
Policy Examples
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-limits
spec:
validationFailureAction: Enforce
rules:
- name: check-container-resources
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "All containers must have CPU and memory limits."
pattern:
spec:
containers:
- resources:
limits:
cpu: "?*"
memory: "?*"
requests:
cpu: "?*"
memory: "?*"
memory: "?*"This policy requires every container to have resource limits and requests. Without limits, a single container can consume all node resources. This prevents noisy neighbor problems.
GitOps Integration
In a GitOps workflow, policies should run at two points: in CI (pre-deployment) and in the cluster (admission control). CI checks catch issues early. Admission control catches issues that bypass CI.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
spec:
syncPolicy:
automated:
prune: true
syncOptions:
- Validate=true # Enable server-side validation
ignoreDifferences: []
# Kyverno policies validate resources during sync
# Gatekeeper policies validate during admissionArgoCD's Validate=true option enables server-side validation. When ArgoCD applies resources, the API server runs admission controllers. Kyverno or Gatekeeper policies validate the resources before they are created.
Best Practices
- Start with audit mode (Audit instead of Enforce) to identify violations without blocking.
- Test policies in a staging cluster before enforcing in production.
- Use exception policies for system namespaces (kube-system, argocd).
- Document all policies and provide guidance for developers to comply.
- Use policy-as-code repositories with CI testing for policy changes.
- Combine CI policy checks with admission control for defense in depth.
Kyverno policies are YAML-based and easier to learn than Rego. Start with Kyverno if your team is new to policy engines. Move to Gatekeeper if you need the full power of Rego or have existing OPA policies.
A too-strict policy can block all deployments. Always test with audit mode first. Use exclude rules for system workloads. Monitor policy violations before switching to enforce mode.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.