Aller au contenu
Conteneurs & Orchestration high
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Gatekeeper — OPA pour Kubernetes (complément CKS)

17 min de lecture

Logo Kubernetes

Gatekeeper est le projet Kubernetes construit autour d’OPA (Open Policy Agent), moteur de policy-as-code CNCF Graduated. Il utilise le langage Rego pour définir des policies complexes via un modèle ConstraintTemplate + Constraint. C’est un outil mature et largement adopté par les équipes déjà familières avec l’écosystème OPA.

  • Quand choisir Gatekeeper vs VAP vs Kyverno
  • Comprendre le modèle ConstraintTemplate + Constraint
  • Écrire des policies Rego orientées sécurité (privileged, hostPath, runAsNonRoot)
  • Utiliser gator pour tester localement
  • Diagnostiquer un rejet d’admission (Gatekeeper vs PSA vs RBAC)

Gatekeeper n’est pas toujours le bon choix. Avant d’investir du temps dans l’apprentissage de Rego, posez-vous les bonnes questions. Ce tableau compare les trois approches principales selon des critères concrets.

CritèreVAPKyvernoGatekeeper
LangageCEL (natif K8s)YAMLRego
Composant externeNonOui (webhook)Oui (webhook)
Courbe d’apprentissageFaibleFaibleÉlevée
Logique complexeLimitéeMoyenneTrès riche
Audit ressources existantesNonPolicyReportsIntégré
MutationBeta (1.34)
Génération de ressourcesNonNon
Écosystème OPA existantNonNonOui
Maturité CNCFNatif K8sIncubatingGraduated (OPA)

Résumé en une phrase : Choisissez VAP si vous voulez rester natif, Kyverno pour sa simplicité YAML, ou Gatekeeper si vous avez déjà un écosystème OPA/Rego.

Voici les scénarios où Gatekeeper a un avantage clair :

  • Vous utilisez déjà OPA ailleurs (Terraform, CI/CD, APIs)
  • Votre équipe maîtrise Rego
  • Vous avez besoin de logique complexe (références croisées, calculs, ensembles)
  • Vous voulez un audit intégré des ressources existantes
  • Vous avez une librairie de policies Rego à réutiliser

À l’inverse, ces situations suggèrent un autre outil :

  • Vous débutez en policy-as-code → VAP ou Kyverno
  • Vous voulez éviter un composant externe → VAP
  • Vous avez besoin de générer des ressources → Kyverno
  • L’équipe préfère rester en YAML pur → Kyverno

Architecture Gatekeeper : ConstraintTemplate instancie Constraint

Analogie : ConstraintTemplate = classe, Constraint = instance de cette classe.

Fenêtre de terminal
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/v3.22.0/deploy/gatekeeper.yaml

Vérifier l’installation :

Fenêtre de terminal
kubectl get pods -n gatekeeper-system
NAME READY STATUS RESTARTS AGE
gatekeeper-audit-5c4b5d897d-x7bmt 1/1 Running 0 42s
gatekeeper-controller-manager-6958bc4b76-6bhq2 1/1 Running 0 42s
gatekeeper-controller-manager-6958bc4b76-cjtk2 1/1 Running 0 42s
gatekeeper-controller-manager-6958bc4b76-sjhdf 1/1 Running 0 42s

Après l’installation, vous verrez deux types de pods. Comprendre leur rôle est essentiel pour le dépannage.

ComposantRôleRéplicas
controller-managerWebhook d’admission — intercepte et valide les requêtes3 (HA)
auditScan périodique des ressources existantes1

Pourquoi 3 réplicas pour le controller-manager ? C’est un composant critique sur le chemin de l’API Server. Si un seul pod est down, les requières d’admission pourraient échouer. Avec 3 réplicas, vous avez de la haute disponibilité.

Le pod audit scanne les ressources existantes pour détecter les violations. Même si une ressource a été créée avant l’installation de Gatekeeper, l’audit la trouvera.

Cet exemple est le plus rentable pour la CKS : refuser les conteneurs en mode privileged est un contrôle fondamental.

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdenyprivileged
spec:
crd:
spec:
names:
kind: K8sDenyPrivileged
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdenyprivileged
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("Conteneur '%v' en mode privileged interdit", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged == true
msg := sprintf("InitContainer '%v' en mode privileged interdit", [container.name])
}

Exemple 2 : securityContext complet (runAsNonRoot + readOnlyRootFilesystem)

Section intitulée « Exemple 2 : securityContext complet (runAsNonRoot + readOnlyRootFilesystem) »

Pour la CKS, imposer un securityContext sécurisé est encore plus pertinent :

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8ssecuritycontextcomplete
spec:
crd:
spec:
names:
kind: K8sSecurityContextComplete
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8ssecuritycontextcomplete
# Vérifie runAsNonRoot
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.securityContext.runAsNonRoot == true
msg := sprintf("Conteneur '%v' doit avoir runAsNonRoot: true", [container.name])
}
# Vérifie allowPrivilegeEscalation
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.securityContext.allowPrivilegeEscalation == false
msg := sprintf("Conteneur '%v' doit avoir allowPrivilegeEscalation: false", [container.name])
}
# Vérifie readOnlyRootFilesystem
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.securityContext.readOnlyRootFilesystem == true
msg := sprintf("Conteneur '%v' doit avoir readOnlyRootFilesystem: true", [container.name])
}

Exemple 3 : refuser hostPath (isolation filesystem)

Section intitulée « Exemple 3 : refuser hostPath (isolation filesystem) »
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdenyhostpath
spec:
crd:
spec:
names:
kind: K8sDenyHostPath
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdenyhostpath
violation[{"msg": msg}] {
volume := input.review.object.spec.volumes[_]
volume.hostPath
msg := sprintf("Volume hostPath '%v' interdit", [volume.name])
}
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedregistries
spec:
crd:
spec:
names:
kind: K8sAllowedRegistries
validation:
openAPIV3Schema:
type: object
properties:
registries:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedregistries
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not registry_allowed(container.image)
msg := sprintf("Image '%v' provient d'un registry non autorisé", [container.image])
}
registry_allowed(image) {
registry := input.parameters.registries[_]
startswith(image, registry)
}

Constraint associé :

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRegistries
metadata:
name: only-trusted-registries
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
registries:
- "gcr.io/my-project/"
- "registry.internal.company.com/"

La librairie officielle Gatekeeper a une section dédiée aux Pod Security Standards. Pour la CKS, c’est l’angle le plus fort de Gatekeeper.

Fenêtre de terminal
# Installer les templates Pod Security Standards
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/privileged-containers/template.yaml
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/host-network-ports/template.yaml
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/allowed-users/template.yaml
Template PSSDescriptionÉquivalent PSA
K8sPSPPrivilegedContainerInterdit privilegedBaseline/Restricted
K8sPSPHostNetworkingPortsContrôle hostNetwork/hostPortBaseline/Restricted
K8sPSPAllowedUsersRestreint UID/GIDRestricted
K8sPSPCapabilitiesContrôle les capabilitiesRestricted
K8sPSPHostFilesystemRestreint hostPathBaseline

Ces templates permettent d’implémenter les mêmes contrôles que PSA, mais avec plus de flexibilité. Par exemple, vous pouvez autoriser hostPath pour certains namespaces seulement, ce que PSA ne permet pas.

Gatekeeper peut ainsi compléter PSA pour des règles spécifiques non couvertes, ou l’implémenter complètement si vous avez besoin de plus de flexibilité.

Déployer une policy directement en mode bloquant est risqué. Gatekeeper offre trois modes d’enforcement pour une adoption progressive et sécurisée.

ValeurComportementPhase
dryrunAccepte, enregistre dans statusDécouverte
warnAccepte, affiche warningSensibilisation
denyBloque la requêteProduction

Comment utiliser ces modes ?

  1. Démarrez avec dryrun : Les violations sont enregistrées dans le champ status de la Constraint, mais aucune requête n’est bloquée. Lancez l’audit pour voir les ressources existantes non conformes.
  2. Passez à warn : Les développeurs voient des warnings lors de leurs déploiements, mais peuvent continuer. Cela les sensibilise avant le blocage.
  3. Activez deny : Une fois tous les workloads corrects, passez au blocage effectif.
spec:
enforcementAction: dryrun # Étape 1 : découverte
# enforcementAction: warn # Étape 2 : alerter
# enforcementAction: deny # Étape 3 : enforcement

Gatekeeper scanne périodiquement les ressources déjà déployées :

Fenêtre de terminal
# Voir les violations détectées par l'audit
kubectl get k8sdenyprivileged deny-privileged-containers -o yaml
status:
auditTimestamp: "2026-03-24T10:30:00Z"
totalViolations: 2
violations:
- enforcementAction: deny
kind: Pod
message: "Conteneur 'debug' en mode privileged interdit"
name: debug-pod
namespace: production
Fenêtre de terminal
# Installer gator
brew install gator
# Tester un template + constraint contre une ressource
gator test \
--filename template.yaml \
--filename constraint.yaml \
--filename pod-to-test.yaml
# Vérifier la syntaxe Rego d'un template
gator verify --filename template.yaml

Depuis v3.22+, gator policy ajoute même une gestion “brew-like” de la policy library :

Fenêtre de terminal
# Installer des policies depuis la librairie
gator policy install privileged-containers

Un Pod refusé peut l’être par plusieurs mécanismes. Avant de supposer que Gatekeeper est la cause, vérifiez systématiquement ces sources possibles. Le message d’erreur vous indique généralement la source.

Message / IndiceSource probableCommande de diagnostic
admission webhook "validation.gatekeeper.sh" deniedGatekeeperkubectl get constraints
violates PodSecurityPSAkubectl get ns -o yaml (labels)
exceeded quotaResourceQuotakubectl describe quota
forbidden: User cannotRBACkubectl auth can-i
admission webhook "..." denied (autre)Autre webhookkubectl get validatingwebhookconfigurations
Fenêtre de terminal
# Lister tous les webhooks
kubectl get validatingwebhookconfigurations
# Lister les ConstraintTemplates
kubectl get constrainttemplates
# Lister tous les Constraints actifs
kubectl get constraints
# Détails d'un Constraint (violations, status)
kubectl describe k8sdenyprivileged deny-privileged-containers
# Logs du controller (rejets récents)
kubectl logs -l control-plane=controller-manager -n gatekeeper-system --tail=50
# Logs d'audit (violations ressources existantes)
kubectl logs -l control-plane=audit-controller -n gatekeeper-system --tail=50

Si Gatekeeper bloque des déploiements critiques :

Fenêtre de terminal
# Option 1 : passer le Constraint en dryrun
kubectl patch k8sdenyprivileged deny-privileged-containers \
--type='merge' -p '{"spec":{"enforcementAction":"dryrun"}}'
# Option 2 : désactiver le webhook temporairement
kubectl delete validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
# ⚠️ Penser à le réactiver après résolution

Gatekeeper supporte la mutation (stable depuis v3.10+). Ce guide se concentre sur la validation, mais voici un exemple minimal :

apiVersion: mutations.gatekeeper.sh/v1
kind: Assign
metadata:
name: add-default-security-context
spec:
applyTo:
- groups: [""]
kinds: ["Pod"]
versions: ["v1"]
match:
scope: Namespaced
location: "spec.containers[name:*].securityContext.runAsNonRoot"
parameters:
assign:
value: true

Pour un guide complet sur la mutation Gatekeeper, voir la documentation officielle.

  1. Excluez les namespaces système (kube-system, gatekeeper-system) pour éviter de bloquer le cluster
  2. Commencez en dryrun avant deny — découvrez les violations sans impact
  3. Limitez le scope avec match.namespaces pour les performances
  1. Réutilisez la librairie avant de créer des templates custom
  2. Testez avec gator localement avant de déployer
  3. Surveillez l’audit pour la conformité continue
  4. Documentez vos Constraints — le Rego n’est pas lisible par tous
  1. Gatekeeper = OPA pour Kubernetes, basé sur le moteur CNCF Graduated OPA
  2. Modèle à 2 niveaux : ConstraintTemplate (logique Rego) + Constraint (application)
  3. Rego : puissant pour la logique complexe, mais courbe d’apprentissage
  4. Audit intégré pour scanner les ressources existantes — avantage unique
  5. gator pour tester localement (pas opa eval)
  6. Librairie PSS pour implémenter les Pod Security Standards
  7. Admission webhook : composant critique, tester hors production
  8. v3.22+ intègre VAP : Gatekeeper peut cohabiter avec les policies natives

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn