Security musings

Catégories

Tags

🔍 Licence d'Utilisation 🔍

Sauf mention contraire, le contenu de ce blog est sous licence CC BY-NC-ND 4.0.

© 2025 à 2042 Sébastien Gioria. Tous droits réservés.

⏱️
Temps de lecture estimé
~10 minutes

En mai 2026, le paysage du Policy as Code Kubernetes a beaucoup changé. Gatekeeper v3.22 industrialise la génération native de ValidatingAdmissionPolicy, Kyverno gagne sérieusement du terrain, et CEL devient la norme des contrôleurs d’admission. La question en 2026 est où placer OPA et Gatekeeper dans une chaîne déjà chargée par les scanners, l’admission native et le runtime.


Policy as Code n’est plus une option

Ces dernières semaines on a parlé de Trivy (scan statique) et Falco (détection runtime). Entre les deux, il manque une couche : ce qui s’applique au moment où une ressource entre dans le cluster. C’est le terrain de l’admission control, et c’est là ou il faut être clair : OPA et Gatekeeper ne sont plus seuls sur ce créneau.

En 2026, trois choses ont changé la donne :

  1. ValidatingAdmissionPolicy (VAP) est globalement disponible côté Kubernetes depuis la 1.30, et stable en 1.32. Le langage CEL embarqué dans l’API server permet d’exprimer des politiques simples sans webhook externe. La latence et la disponibilité ne sont plus des arguments contre l’admission policy.
  2. Gatekeeper v3.22 génère et synchronise nativement les ressources VAP à partir des ConstraintTemplate. Concrètement : on écrit ses policies une fois en Rego ou en CEL, et Gatekeeper les déploie aussi en VAP côté API server. C’est le point d’inflexion qui réconcilie les deux mondes.
  3. Kyverno continue son ascension chez les équipes plates-formes. Pour beaucoup de cas d’usage, il est plus rapide à prendre en main qu’OPA et ne demande pas d’apprendre Rego.

En 2026, la question centrale est : quelle politique va où, et qui la maintient ?

🤔 Kesako ?

ValidatingAdmissionPolicy (VAP)

Une ressource Kubernetes native (groupe admissionregistration.k8s.io) qui décrit une politique d'admission évaluée directement par l'API server, sans webhook externe. Elle est composée de deux objets :

  • ValidatingAdmissionPolicy, le « code » de la politique : les ressources ciblées (matchConstraints) et une ou plusieurs expressions CEL qui retournent true si la requête est valide. CEL (Common Expression Language) est un mini-langage d'expression de Google, plus simple que Rego, déjà utilisé dans Kubernetes pour les CRD et les autorisations.
  • ValidatingAdmissionPolicyBinding , l'instance qui « branche » la politique sur un périmètre concret : namespaces, mode (Deny / Warn / Audit), paramètres éventuels.

Ce qui se passe lors d'un kubectl apply :

  1. L'API server reçoit la requête.
  2. Avant d'écrire dans etcd, il évalue les VAP qui matchent - en CEL, dans le même process.
  3. Si l'expression retourne false, la requête est refusée (ou loggée / avertissement) selon le binding.
Conséquences clés : pas de webhook réseau (latence nulle), disponibilité calquée sur l'API server, mais limitée à ce que CEL sait exprimer - pas d'appel externe, pas de mutation complexe.

Quand on parle de « ressource VAP » dans la suite, c'est de ce couple ValidatingAdmissionPolicy + ValidatingAdmissionPolicyBinding qu'il s'agit.


Pourquoi le Policy as Code reste indispensable

Avant de comparer les outils, il faut rappeler que les contrôles natifs Kubernetes ne couvrent pas :

  • Le RBAC régit qui peut faire quoi sur l’API, mais pas la sémantique des ressources créées. Un développeur autorisé à créer un Deployment peut très bien le créer sans resources.limits, sans securityContext, ou avec une image venue d’un registre douteux.
  • Les Pod Security Standards offrent trois profils (privileged, baseline, restricted) qui couvrent les bases côté pod, mais ne savent rien des règles métier : « tout Deployment de production doit porter le label cost-center », « interdiction d’utiliser le namespace default », « les images doivent être signées par notre clé interne ».
  • Les NetworkPolicies s’arrêtent au réseau.

Le Policy as Code apporte ce qui manque :

  • Des règles versionnées dans Git, testables, revues comme du code.
  • Un langage déclaratif (Rego, CEL, ou DSL Kyverno) pour exprimer des logiques que les contrôles natifs ne couvrent pas.
  • Une validation et une mutation à l’admission, avant que la ressource n’existe dans le cluster.
  • Un audit continu des ressources existantes contre les nouvelles politiques, sans blocage.
  • Un mode dry-run pour mesurer l’impact réel avant d’enforcer.

Avant de déployer ces éléments en production il faut compter deux à trois semaines de mode dryrun ou warn avant de basculer en deny. Sauter cette phase, c’est s’exposer à un blocage surprise de déploiements dès la mise en prod.


OPA, le moteur générique

OPA (Open Policy Agent) est le moteur de policies maintenu par la CNCF. C’est un binaire Go qui évalue du Rego, son langage déclaratif. OPA vit en dehors de Kubernetes : on l’utilise aussi pour Envoy, Terraform, les API REST, les CI/CD. Côté versions, OPA 1.16.1 est la release courante de mai 2026 (la 1.16.0 a été marquée par une régression sur le plugin manager, à éviter).

Ce qu’il faut retenir des OPA récentes : nouvelles built-ins uri.parse / uri.is_valid, support de métadonnées request/response sur la Data API, métriques Prometheus exportées via OTLP, et un effort soutenu sur les performances de l’évaluateur.

Gatekeeper, l’intégration Kubernetes

Gatekeeper est l’intégration officielle d’OPA pour Kubernetes : un opérateur, un webhook d’admission, et deux Custom Resources clés — ConstraintTemplate (le code Rego ou CEL) et Constraint (l’instance paramétrée).

Les versions à connaître au 12 mai 2026 :

  • Gatekeeper v3.22.2 (avril 2026) — version stable courante. La v3.22.1 a connu un souci de publication d’artefacts, sauter directement à la v3.22.2.
  • Gatekeeper v3.22.0 (10 mars 2026) — la release qui marque la convergence avec VAP. Le flag sync-vap-enforcement-scope est désormais à true par défaut.
  • Gatekeeper v3.21.0 (novembre 2025) — introduction du flag sync-vap-enforcement-scope et meilleur support de l’External Data API.
  • Gatekeeper v3.23.0-beta.0 (mars 2026) — version de preview pour les early adopters.

Les nouveautés qui comptent vraiment

Trois choses méritent l’attention des équipes qui exploitent déjà Gatekeeper :

  • Génération native de ValidatingAdmissionPolicy. Avec sync-vap-enforcement-scope à true, Gatekeeper produit des ressources VAP côté API server à partir de chaque Constraint. Pour les politiques simples, l’évaluation se fait directement dans l’API server via CEL, sans appel au webhook. Latence proche de zéro, disponibilité égale à celle de l’API server. Le webhook Gatekeeper reste utilisé pour les cas que CEL ne couvre pas (logique complexe, données externes, mutation).
  • Support du namespace pour les moteurs Rego et CEL. Les expressions CEL accèdent à namespaceObject et les politiques Rego à input.namespace, ce qui permet enfin des décisions vraiment scopées au namespace, en admission comme en audit.
  • gator policy et gator bench côté CLI. gator policy apporte une expérience à la brew pour découvrir, installer, mettre à jour des bundles de la gatekeeper-library (par exemple pod-security-baseline). gator bench benchmarke les performances Rego et CEL avec percentiles de latence, throughput, profil mémoire — utile pour détecter les régressions en CI/CD.

À cela s’ajoutent un enforcement strict des timeouts sur les External Data Providers (5 s par défaut), un mode out-of-cluster / remote cluster, et la possibilité de désactiver le sidecar audit quand on a déjà un collecteur OTel.


Architecture,

Voila ce qui se passe vraiment quand un kubectl apply traverse un cluster équipé d’OPA / Gatekeeper.

flowchart LR
    U[kubectl apply] --> A[API Server]
    A -->|CEL natif| V[ValidatingAdmissionPolicy]
    A -->|webhook| GK[Gatekeeper webhook]
    GK --> OPA[OPA engine - Rego]
    GK --> CEL[Engine CEL]
    OPA --> D{Verdict}
    CEL --> D
    V --> D
    D -->|allow| K[(etcd)]
    D -->|deny| R[Réponse 403]
    D -->|mutate| M[Mutation puis allow]
    GK -. sync .- V

Trois rôles complémentaires :

  1. L’API server évalue les ValidatingAdmissionPolicy directement en CEL, dans le même process; pas d’appel réseau, pas de timeout possible.
  2. Le webhook Gatekeeper prend le relais pour ce que CEL ne couvre pas : logique Rego complexe, appels à des données externes (registre interne, OPA Provider), mutations.
  3. Le contrôleur Gatekeeper tourne en permanence : il génère les VAP depuis les ConstraintTemplate, audite les ressources existantes, et remonte les violations.

L’audit continu est trop souvent oublié. C’est lui qui vous dit, après avoir poussé une nouvelle politique, combien de ressources existantes la violent — sans bloquer les nouvelles. C’est l’outil de planification de migration le plus utile que je connaisse.


OPA / Gatekeeper face à Kyverno et VAP : le comparatif honnête

Critère Gatekeeper + OPA Kyverno VAP natif (CEL)
Langage Rego (et CEL via Gatekeeper) YAML déclaratif CEL
Courbe d’apprentissage Élevée (Rego) Faible à moyenne Moyenne (CEL est plus simple que Rego)
Écosystème hors Kubernetes ✅ OPA réutilisable partout ❌ Spécifique K8s ❌ Spécifique K8s
Mutation ✅ via Gatekeeper Mutation ✅ Native ⚠️ Limitée
Données externes ✅ External Data Providers ✅ Variables externes
Latence d’admission Webhook (réseau) Webhook (réseau) ✅ Évaluation in-process
Génération automatique de VAP ✅ depuis v3.22 ⚠️ Partielle N/A
Maturité 2026 CNCF graduated, très mature CNCF incubating, très adopté Stable depuis K8s 1.32
Politiques prêtes à l’emploi gatekeeper-library, gator policy Kyverno policies catalog Très limité
  • Si vous démarrez un cluster aujourd’hui et que vos politiques sont simples (PodSecurity-like, labels, registries, resource limits), commencez par VAP natif. Pas de webhook à maintenir, latence imbattable.
  • Si vous voulez du déclaratif sans apprendre Rego, Kyverno est un excellent choix. La mutation y est plus naturelle qu’avec Gatekeeper.
  • Si vous avez déjà OPA en place (Envoy, CI/CD, Terraform), Gatekeeper reste pertinent pour mutualiser un seul moteur de policies cross-stack. Et avec la génération automatique de VAP depuis v3.22, vous combinez admission native rapide et logique Rego pour les cas complexes.
  • Si vous avez besoin d’External Data, par exemple pour vérifier la signature d’une image ou interroger un registre interne d’autorisations, Gatekeeper conserve une longueur d’avance.

Choisir Gatekeeper en 2026, c’est faire un pari sur la portabilité des policies (Kubernetes + ailleurs), pas sur Kubernetes seul. Si tout votre besoin est intra-cluster, le ratio coût / valeur d’OPA s’effrite.


Bonnes pratiques d’usage en 2026

  • Démarrer en dryrun puis warn avant deny. Deux à trois semaines minimum, le temps de mesurer l’impact réel sur vos workloads. Aucune politique ne devrait passer en deny sans rapport d’audit préalable.
  • Versionner les ConstraintTemplate et Constraint dans le même dépôt Git que les manifestes applicatifs ou dans un dépôt « plate-forme » dédié, et les déployer via Argo CD ou Flux. Pas de kubectl apply manuel.
  • Tester les policies en CI avec gator verify (équivalent unit test pour Rego/CEL Gatekeeper) et benchmarker avec gator bench pour détecter les régressions de performance avant qu’elles ne saturent le webhook.
  • Couvrir les exceptions par configuration, pas par contournement. Une exception non documentée devient une dette invisible , comme un .trivyignore non maintenu.
  • Privilégier VAP / CEL pour les politiques simples, garder le webhook pour les cas qui le justifient. Moins de webhooks = moins de points de défaillance lors d’un incident API server.
  • Surveiller le webhook Gatekeeper : disponibilité, latence p95, taux d’erreurs. Un webhook configuré en failurePolicy: Fail qui tombe peut bloquer tous les déploiements du cluster.
  • Pinner les images Gatekeeper et OPA par digest SHA256, vérifier les signatures Cosign , même hygiène supply chain que pour Trivy et Falco.
  • Faire la part des choses avec Pod Security Admission. Pour les profils standards (baseline, restricted), le contrôle natif suffit. Gardez OPA pour vos règles métier propres.

Articulation avec le reste de la chaîne DevSecOps

Une stack mature en 2026 ressemble à ceci, et chaque couche a son rôle :

  • Pre-commit / CI : Trivy en mode filesystem détecte secrets et CVE des dépendances avant même le push.
  • Build / registre : Trivy scanne l’image construite, Cosign la signe, le SBOM est publié.
  • Admission Kubernetes : VAP couvre le standard (CEL natif), Gatekeeper ou Kyverno couvre les règles métier et la mutation. Refus des images non scannées récemment ou non signées.
  • Runtime : Falco surveille les syscalls et l’audit Kubernetes. Toute évasion ou comportement anormal détecté en quelques secondes.
  • Audit continu : Gatekeeper audite les ressources existantes, Falco audite les comportements, le SOC corrèle dans son SIEM.

OPA / Gatekeeper occupe la troisième case. Sans lui ou un équivalent, il y a un trou entre « j’ai validé l’image » et « je surveille son comportement ». C’est ce trou qui laisse passer les ressources mal configurées, les hostPath oubliés, les images non signées qui finissent en production.


Limites et angles morts à connaître

Le Policy As Code c’est bien mais il faut être clair sur ses limites :

  • OPA / Gatekeeper a un coût d’apprentissage réel. Rego n’est pas trivial. Beaucoup d’équipes finissent par recopier des policies de la gatekeeper-library sans les comprendre, et créent une fausse impression de sécurité.
  • Le webhook est un SPOF s’il est mal configuré. Un failurePolicy: Fail sur un webhook indisponible bloque les déploiements à l’échelle du cluster. Un failurePolicy: Ignore peut laisser passer du contenu non conforme. Le bon réglage dépend du contexte (cluster prod vs lab).
  • Les politiques ne valent que ce que valent leurs exceptions. Un Constraint bourré d’exemptions revient à ne rien faire.
  • OPA ne sait pas tout. Pour la sécurité des secrets en transit, l’analyse comportementale, la détection d’exploits —;il faut Falco, Trivy, Cosign, etc. OPA est un moteur de règles, pas un EDR.
  • Comme tout outil tiers, Gatekeeper et OPA font partie de votre supply chain. Mêmes précautions : pinning par digest, vérification des signatures, miroir interne si possible.

À retenir

À retenir 📌
  • Le Policy as Code n'est plus optionnel en 2026 : il est la couche manquante entre les scanners statiques (Trivy) et la détection runtime (Falco).
  • Gatekeeper v3.22 réconcilie OPA et VAP : génération automatique des ValidatingAdmissionPolicy depuis les ConstraintTemplate, latence quasi nulle pour les politiques simples.
  • VAP natif (CEL) suffit pour la plupart des règles standards ; gardez Gatekeeper / Kyverno pour la complexité, la mutation et les données externes.
  • Kyverno est un sérieux concurrent pour les équipes qui veulent rester en YAML déclaratif sans apprendre Rego.
  • Toujours commencer en `dryrun` puis `warn` deux à trois semaines avant de passer en `deny` : c'est ce qui distingue une adoption réussie d'un blocage massif des déploiements.
  • Tester en CI avec `gator verify` et benchmarker avec `gator bench` pour éviter les régressions qui saturent le webhook en production.
  • Mêmes principes supply chain que Trivy et Falco : pinning par digest, vérification des signatures, surveillance de la disponibilité du webhook.