ITSkillsCenter
Business Digital

Pod Security Standards et OPA Gatekeeper — admission stricte CKS 2026

9 دقائق للقراءة

📍 Article principal du cluster : CKS Certified Kubernetes Security Specialist — guide pratique 2026

Ce tutoriel fait partie du cluster certification CKS. Pour la vue d’ensemble, lisez d’abord le pilier.

Introduction

Le domaine 4 « Minimize Microservice Vulnerabilities » pèse 20 % de l’examen CKS. Il teste votre capacité à appliquer des politiques d’admission strictes qui bloquent à la création tout Pod ne respectant pas les standards de sécurité — capabilities excessives, runAsRoot, hostNetwork, mounts sensibles. Deux outils sont incontournables : Pod Security Standards (intégré nativement à Kubernetes depuis 1.25) et OPA Gatekeeper (policies déclaratives en Rego, plus flexibles). Ce tutoriel applique les deux sur un cluster kind 1.34, montre les différences, et configure une stratégie défense-en-profondeur.

Prérequis

  • Cluster kind 1.34 fonctionnel
  • Tutoriel kube-bench/CIS terminé
  • 40 minutes

Étape 1 — Activer Pod Security Standards Restricted sur un namespace

Pod Security Standards (PSS) est le successeur de PodSecurityPolicy. Il s’active via labels au niveau namespace, sans installation additionnelle. Trois niveaux : Privileged (aucune restriction), Baseline (anti-escalation), Restricted (durcissement maximal).

kubectl create namespace secure-zone
kubectl label namespace secure-zone \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

# Tester avec un Pod non-conforme
kubectl run nginx --image=nginx:1.27 -n secure-zone
# Doit échouer : Restricted exige runAsNonRoot, capabilities drop, etc.

Le Pod nginx classique est rejeté car l’image tourne en root par défaut. C’est le comportement attendu — vous devez fournir un manifest qui satisfait les contraintes Restricted pour qu’il soit accepté.

Étape 2 — Créer un Pod conforme Restricted

Un Pod Restricted-conforme demande : runAsNonRoot, runAsUser non-zéro, allowPrivilegeEscalation false, capabilities drop ALL, seccompProfile RuntimeDefault.

cat > /tmp/pod-restricted.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: secure-zone
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginxinc/nginx-unprivileged:1.27
    ports:
    - containerPort: 8080
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      runAsNonRoot: true
EOF

kubectl apply -f /tmp/pod-restricted.yaml
kubectl get pod secure-app -n secure-zone

Notez l’utilisation de `nginxinc/nginx-unprivileged` — l’image officielle nginx tourne en root sur le port 80, alors que la version unprivileged tourne en uid 101 sur le port 8080. Pour les workloads CKS, privilégiez les images conçues pour s’exécuter sans privilèges.

Étape 3 — Installer OPA Gatekeeper

OPA (Open Policy Agent) Gatekeeper étend Kubernetes avec un admission webhook qui évalue chaque création/modification de ressource contre des policies Rego. Plus flexible que PSS qui est limité aux contraintes prédéfinies.

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/v3.18.0/deploy/gatekeeper.yaml
sleep 30
kubectl get pods -n gatekeeper-system
kubectl wait --for=condition=ready pod -l control-plane=controller-manager -n gatekeeper-system --timeout=120s

Une fois Gatekeeper démarré, le webhook intercepte toutes les requêtes API. Sans ConstraintTemplate ni Constraint, il laisse tout passer. C’est la prochaine étape qui ajoute les règles.

Étape 4 — Première policy — interdire les images depuis Docker Hub

Cas d’usage classique : forcer toutes les images à venir d’un registry interne (Harbor, ECR, GCR). On commence par un ConstraintTemplate qui définit la logique en Rego, puis on l’instancie via une Constraint.

cat > /tmp/template-allowed-repos.yaml <<'EOF'
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sallowedrepos
spec:
  crd:
    spec:
      names:
        kind: K8sAllowedRepos
      validation:
        openAPIV3Schema:
          type: object
          properties:
            repos:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sallowedrepos
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          satisfied := [good | repo = input.parameters.repos[_]; good = startswith(container.image, repo)]
          not any(satisfied)
          msg := sprintf("container image %v not allowed from repos %v", [container.image, input.parameters.repos])
        }
EOF

kubectl apply -f /tmp/template-allowed-repos.yaml

cat > /tmp/constraint-allowed-repos.yaml <<'EOF'
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: only-corporate-registry
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces: ["kube-system","gatekeeper-system"]
  parameters:
    repos:
      - "registry.example.com/"
      - "ghcr.io/myorg/"
EOF

kubectl apply -f /tmp/constraint-allowed-repos.yaml
sleep 5

# Tester : un Pod nginx public doit être refusé
kubectl run test-block --image=nginx:1.27 -n default
# Doit échouer avec violation Gatekeeper

Le Pod est rejeté avec un message explicite « container image nginx:1.27 not allowed from repos ». C’est exactement le comportement attendu en production : aucune image non-vérifiée ne peut atteindre le cluster.

Étape 5 — Policy interdire hostPath

Les volumes hostPath sont une porte ouverte : un Pod compromis peut lire/écrire sur le filesystem du nœud. Une bonne policy CKS interdit hostPath sauf cas exceptionnels documentés.

cat > /tmp/template-no-hostpath.yaml <<'EOF'
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8snohostpath
spec:
  crd:
    spec:
      names:
        kind: K8sNoHostPath
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8snohostpath
        violation[{"msg": msg}] {
          volume := input.review.object.spec.volumes[_]
          volume.hostPath
          msg := sprintf("hostPath volumes are forbidden, found %v", [volume.name])
        }
EOF

kubectl apply -f /tmp/template-no-hostpath.yaml

cat > /tmp/constraint-no-hostpath.yaml <<'EOF'
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sNoHostPath
metadata:
  name: forbid-hostpath
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces: ["kube-system","gatekeeper-system"]
EOF

kubectl apply -f /tmp/constraint-no-hostpath.yaml

Test : tentez d’appliquer un Pod avec un hostPath volume — il est refusé immédiatement par Gatekeeper. Cette policy seule bloque environ 30 % des escapes container documentés.

Étape 6 — Audit mode pour découverte avant enforcement

Avant de basculer en `enforce`, beaucoup d’équipes commencent en `audit` : Gatekeeper logue les violations sans les bloquer, ce qui permet de quantifier l’impact d’une nouvelle policy.

# Voir les violations détectées (audit mode)
kubectl get k8snohostpath forbid-hostpath -o yaml | grep -A 20 status

Le bloc `status.violations` liste toutes les ressources qui violent la policy. En enforcement mode, ces violations bloquent les nouvelles créations mais ne suppriment pas les Pods existants — vous devez les corriger un par un.

Étape 7 — Combiner PSS et OPA Gatekeeper

PSS et Gatekeeper sont complémentaires. PSS gère les contraintes standardisées de Kubernetes (security context, capabilities, host namespaces). Gatekeeper gère les contraintes business (registry whitelist, labels obligatoires, ResourceQuotas custom). Combinez les deux : PSS au niveau namespace, Gatekeeper pour les règles globales.

# Vérifier la cohérence des deux systèmes sur un Pod test
cat > /tmp/test-combined.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: combined-test
  namespace: secure-zone
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: registry.example.com/nginx:1.27
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
EOF

kubectl apply -f /tmp/test-combined.yaml
# Refusé par Gatekeeper (registry pas dans la liste autorisée)

Si on tente avec une image registry approuvée (ghcr.io/myorg/nginx) ET un security context PSS-conforme, le Pod passe. C’est la posture défense-en-profondeur qu’on cherche.

Étape 8 — Sandbox runtime gVisor (introduction)

gVisor est un runtime conteneur user-space qui isole davantage que runc en interceptant les syscalls. Recommandé pour les workloads non-confiés. La configuration complète demande modification du containerd config et création d’une RuntimeClass.

cat > /tmp/runtimeclass-gvisor.yaml <<'EOF'
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
EOF

# Note : nécessite gVisor installé sur les nœuds avec containerd configuré
# kubectl apply -f /tmp/runtimeclass-gvisor.yaml

# Pod utilisant gVisor :
cat > /tmp/pod-gvisor.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: untrusted-workload
spec:
  runtimeClassName: gvisor
  containers:
  - name: app
    image: nginx:1.27
EOF

Pour kind, gVisor n’est pas pré-installé. En production, c’est une option pour héberger du code utilisateur ou des workloads non-vérifiés. Tombe en domaine 4 du syllabus comme « sandbox runtime ».

Comprendre la différence Validating vs Mutating Admission Webhook

Kubernetes a deux types de webhooks d’admission. Validating dit oui ou non à une création/modification — c’est ce qu’utilise Gatekeeper. Mutating peut modifier la ressource avant qu’elle soit persistée — c’est ce que fait Istio pour injecter des sidecars Envoy. Les deux peuvent coexister : Mutating s’exécute en premier (transforme la ressource), puis Validating (valide la version finale).

OPA Gatekeeper supporte les deux modes depuis la v3.10. Pour CKS v1.34, attendez-vous à des questions principalement sur Validating, occasionnellement sur Mutating pour la transformation de manifests.

Erreurs fréquentes

Erreur Cause Solution
PSS Restricted refuse mes Pods existants Images qui tournent en root Migrer vers `nginx-unprivileged`, `bitnami/postgresql` etc
Gatekeeper laisse passer mes Pods ConstraintTemplate appliqué sans Constraint Les deux objets sont nécessaires : Template puis Constraint qui l’instancie
Rego policy ne match jamais Mauvais chemin dans input.review.object Tester via `gator test` localement avant déploiement
PSS et Gatekeeper en conflit Règles redondantes mais non synchronisées Documenter le partage de responsabilité : PSS pour standards K8s, Gatekeeper pour business
RuntimeClass gvisor non trouvée gVisor pas installé sur les nœuds Suivre la doc gvisor.dev/docs/user_guide/install pour containerd

Adaptation au contexte ouest-africain

Pour les équipes qui montent un cluster k8s en production en Afrique de l’Ouest, OPA Gatekeeper est un investissement très rentable : 1-2 jours de configuration initiale, puis des années de protection automatique. Les premiers Templates à déployer : registry whitelist (force les images depuis votre Harbor interne), labels obligatoires (équipe, environnement, criticité), ResourceQuota par namespace, et anti hostPath. Ces 4 templates couvrent 80 % des incidents de sécurité observés en pratique. Hostinger Cloud Startup a la capacité RAM nécessaire pour faire tourner Gatekeeper (200-400 Mo) et un cluster k3s léger.

Tutoriels frères

Pour aller plus loin

FAQ

Faut-il OPA Gatekeeper ou Kyverno ?
Les deux sont valides. Gatekeeper utilise Rego (puissant mais courbe d’apprentissage), Kyverno utilise YAML déclaratif (plus simple). Pour CKS, Gatekeeper est dans le syllabus officiel.

Peut-on faire tout avec PSS sans Gatekeeper ?
Non. PSS gère uniquement les contraintes prédéfinies de Kubernetes. Pour des règles business (registry, labels, quotas custom), un admission webhook est requis.

Mots-clés secondaires : opa gatekeeper cks, pod security standards, restricted namespace, rego policy kubernetes, validating admission webhook, gvisor runtimeclass

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité