Contexte
Le 22 avril 2026, Kubernetes 1.36 sortait avec MutatingAdmissionPolicy en GA. C’est un tournant. Jusqu’ici, beaucoup d’équipes restaient sur Kyverno ou OPA Gatekeeper pour la simple raison qu’il manquait la mutation native dans l’API server.
Maintenant, validation et mutation tournent sans webhook, sans dépendance externe.
En parallèle, en février 2026, Kyverno 1.17 bascule sur CEL comme moteur principal et déprécie ses anciennes CRDs JMESPath. Le même langage que les Admission Policies natives, mais avec la génération, le contexte externe et les PolicyReports en plus.
Le rapport de force entre les solutions n’est plus le même qu’en 2022-2024.
Mais avant d’aller plus loin, rappelons ce qu’est l’admission control dans Kubernetes.
Chaque requête vers l’API server Kubernetes passe par une chaîne d’admission avant d’être persistée dans etcd, cette chaîne se compose de 2 phases : d’abord la mutation pour modifier la requête (spec). Par exemple : injecter un label, forcer une limite de ressource… Ensuite la validation pour accepter ou rejeter la requête selon des policies prédéfinies. C’est le dernier rempart avant que la ressource ne se crée dans le cluster.
Ce mécanisme repose historiquement sur des webhooks, un pod externe que l’API server appelle à chaque requête. Depuis Kubernetes 1.30, une approche native existe avec les ValidatingAdmissionPolicies (VAP), qui évaluent des expressions CEL directement dans l’API server. Et avec la 1.36, la mutation rejoint la validation du côté natif via les MutatingAdmissionPolicies (MAP).
Cet article n’est pas une introduction à l’admission control mais plutôt un cadre de décision pour choisir la meilleure approche d’admission pour ses workloads. Le choix de l’outil d’admission n’est pas un détail d’implémentation, c’est une décision d’architecture qui impacte la sécurité, la fiabilité et la maintenabilité de votre cluster sur la durée. C’est dans ce cadre que s’inscrit cet article où on a évalué chaque solution selon des critères concrets ( complexité opérationnelle, dépendance externe, expressivité, impact runtime…) pour que vous puissiez faire le bon choix pour vous.
Critères d’évaluation
Avant de rentrer dans le détail de chaque solution, voici les critères sur lesquels on les a évaluées.
Complexité opérationnelle (Day 2) : maintenir la solution sur la durée (montées de version, monitoring, scaling, haute disponibilité…)
Dépendance externe : le fait que la solution ajoute ou non un composant externe dans le cluster contre une exécution native dans l’API server. L’impact sur la surface de défaillance (fail-open vs fail-closed en cas de panne) et la latence ajoutée sur chaque requête vers l’API server.
Cycle de vie des policies : l’outillage fourni par la solution pour tester, valider et déployer des policies en confiance : mode audit (observer sans bloquer), dry-run et test CLI (valider hors cluster), debuggabilité des rejets, transition progressive d’audit vers le mode enforce.
Expressivité des policies : la capacité du langage de policy à exprimer des règles complexes (logique conditionnelle avancée, pattern matching…) sans sacrifier la maintenabilité.
Mutation vs validation : la capacité de la solution à modifier les requêtes (injection de labels, annotations, valeurs par défaut sur des champs non renseignés…) en plus de les accepter ou de les rejeter.
Génération de ressources : la capacité à créer automatiquement des ressources Kubernetes en réaction à un événement d’admission (ex: création d’un namespace → génération automatique d’une NetworkPolicy, d’un ResourceQuota…).
Richesse du contexte décisionnel : ce que la policy voit au moment de l’évaluation, juste l’objet entrant, ou la capacité à interroger le cluster et des API externes. Avec les limites structurelles de l’admission (cache stale, race conditions, pas de notion de batch ni de transaction).
Courbe d’apprentissage : l’investissement nécessaire pour que l’équipe maîtrise la solution : langage (CEL, Rego, YAML déclaratif), concepts, outillage.
Auditabilité / compliance : capacité à prouver ce qui est appliqué, tracer les décisions, générer des rapports.
Portabilité : est-ce que le moteur de policies sert uniquement pour l’admission Kubernetes, ou il peut être utilisé ailleurs ? (Validation de manifests en CI, policies Terraform…).
Admission Policies natives (VAP / MAP)
Comment ça marche ?
ValidatingAdmissionPolicy (VAP) pour la validation, MutatingAdmissionPolicy (MAP) pour la mutation. Ce sont des ressources Kubernetes natives qui s’exécutent directement dans l’API server via CEL (Common Expression Language), un langage d’expression simple, typé et sandboxé conçu pour une évaluation en temps borné sans effets de bord. Chaque policy est associée à un binding qui définit sur quelles ressources elle s’applique.
Exemple: Interdire les images avec le tag “latest”
1# La politique
2apiVersion: admissionregistration.k8s.io/v1
3kind: ValidatingAdmissionPolicy
4metadata:
5 name: deny-latest-tag
6spec:
7 failurePolicy: Fail
8 matchConstraints:
9 resourceRules:
10 - apiGroups: [""]
11 apiVersions: ["v1"]
12 operations: ["CREATE", "UPDATE"]
13 resources: ["pods"]
14 validations:
15 - expression: >-
16 object.spec.containers.all(c,
17 !c.image.endsWith(':latest') && c.image.contains(':'))
18 message: "Les images avec le tag 'latest' ou sans tag explicite sont interdites."
19---
20# Le binding
21apiVersion: admissionregistration.k8s.io/v1
22kind: ValidatingAdmissionPolicyBinding
23metadata:
24 name: deny-latest-tag-binding
25spec:
26 policyName: deny-latest-tag
27 validationActions:
28 - Deny
29 matchResources: {}
Remarque : Deux ressources nécessaires (Policy + Binding), logique en CEL.
Atouts
- Zéro dépendance externe : pas de webhook qui peut tomber, pas de certificats TLS à gérer. Le Day 2 est quasi inexistant vu que c’est Kubernetes lui-même qui le porte.
- Performance : l’évaluation CEL se fait en mémoire en microsecondes.
- Courbe d’apprentissage raisonnable : Accessible pour une équipe qui a déjà touché à un langage d’expression.
Limites
- Expressivité plafonnée : volontairement, pour garantir l’exécution quasi instantanée et éliminer les effets de bord dans l’API server.
- Pas de génération de ressources : que validation et maintenant mutation, pas plus.
- Contexte décisionnel limité : accès à d’autres ressources via paramRef, mais c’est déclaré à l’avance et figé. Pas de lookup dynamique, pas d’appel API externe.
- Outillage spartiate : pas de policy reports, pas de test CLI dédié, pas de bibliothèque communautaire. Le debugging se résume au message configuré dans
spec.validations[].messageet aux audit annotations.
Quand choisir cette solution ?
Vos besoins en admission se concentrent sur de la validation et de la mutation standard (conventions de nommage, labels obligatoires, restrictions d’images, resource limits par défaut). Votre priorité c’est de réduire la surface opérationnelle au minimum, donc pas de composant externe à maintenir, pas de webhook à surveiller. C’est aussi le bon choix si vous cherchez un socle de base avant d’empiler une solution plus riche par-dessus (c’est abordé plus en détail en bas).
Quand passer son chemin ?
Vos policies ont besoin d’aller chercher du contexte au-delà de l’objet entrant ( lookup dynamique sur le cluster, appels API externes ) Vous comptez sur la génération automatique de ressources à la création d’un namespace ou d’un workload. Ou si votre équipe a besoin d’un outillage mature pour le cycle de vie des policies (mode audit avec reporting, test CLI).
Kyverno
Comment ça marche ?
Kyverno est un operator Kubernetes qui fonctionne via des webhooks d’admission enregistrés et gérés automatiquement. Le projet vient d’atteindre le niveau CNCF Graduated (mars 2026, annoncé à la KubeCon Amsterdam).
Depuis la version 1.17 (février 2026), le moteur bascule sur CEL comme langage principal avec de nouvelles CRDs stables (ValidatingPolicy, MutatingPolicy, GeneratingPolicy, ImageValidatingPolicy et DeletingPolicy). Les anciennes CRDs JMESPath (ClusterPolicy / Policy) sont deprecated, avec un retrait prévu en v1.20 (octobre 2026).
Les noms ressemblent aux Admission Policies natives de Kubernetes, et le langage est le même (CEL), mais le modèle d’exécution reste différent. Une ValidatingPolicy Kyverno est une CRD évaluée par le webhook Kyverno, pas une ressource native exécutée in-process dans l’API server. L’intérêt de passer par le webhook, c’est tout ce que VAP/MAP ne font pas (génération de ressources, vérification d’images, contexte externe, PolicyReports).
La roadmap vise à en faire un moteur de policies plus large au-delà de Kubernetes (Kyverno JSON, SDK, REST API), mais le cœur reste aujourd’hui l’admission.
Exemple: Interdire les images avec le tag “latest”
1apiVersion: policies.kyverno.io/v1
2kind: ValidatingPolicy
3metadata:
4 name: deny-latest-tag
5spec:
6 validationActions:
7 - Deny
8 matchConstraints:
9 resourceRules:
10 - apiGroups: [""]
11 apiVersions: ["v1"]
12 operations: ["CREATE", "UPDATE"]
13 resources: ["pods"]
14 validations:
15 - expression: >-
16 object.spec.containers.all(c,
17 !c.image.endsWith(':latest') && c.image.contains(':'))
18 message: "Les images avec le tag 'latest' ou sans tag explicite sont interdites."
Remarque : Même langage (CEL) et structure quasi identique aux Admission Policies natives, mais évalué par le webhook Kyverno et non in-process dans l’API server.
Atouts
- Outillage du cycle de vie : le plus intégré à l’écosystème Kubernetes. Mode audit avec
PolicyReports(des CRDs queryables, pas des logs bruts), CLI pour valider les policies hors cluster en CI, bibliothèque communautaire de plus de 300 policies prêtes à l’emploi. La facilité du débogage des rejets est claire, avec des messages exploitables et un reporting structuré. - Génération de ressources native : pour un namespace créé par exemple, Kyverno peut générer automatiquement d’autres ressources ( NetworkPolicies, ResourceQuotas, RoleBindings…). Un besoin que ni VAP/MAP natifs ni Gatekeeper ne couvrent.
- Contexte décisionnel riche : les policies peuvent interroger le cluster via des context entries et même appeler des API externes, ce qui permet des règles cross-resource dynamiques au runtime sans être limité à un paramRef figé.
- Vérification d’images intégrée : via
ImageValidatingPolicy(anciennement verifyImages), signatures et attestations (Cosign/Sigstore) se valident directement dans les policies d’admission sans dépendre d’un outil tiers. - Alignement CEL : avec le passage à CEL en GA (v1.17, février 2026), Kyverno s’aligne sur le même langage que VAP/MAP. Les équipes qui ont investi dans CEL retrouvent leurs repères, et celles qui viennent de JMESPath gagnent de meilleures performances d’évaluation et un alignement direct avec l’upstream Kubernetes.
Limites
- C’est un webhook — un composant à déployer, monitorer, scaler, maintenir en haute disponibilité. Si Kyverno tombe, c’est fail-closed par défaut et les requêtes vers l’API server sont bloquées tant que le webhook ne répond pas. Le Day 2 est réel.
- Latence structurelle — chaque requête fait un aller-retour réseau vers le webhook. En fonctionnement normal c’est quelques ms, mais sur un cluster très chargé, ça se cumule.
- API calls puissants mais piégeux — une policy qui fait un lookup sur l’API server à chaque requête d’admission ajoute de la charge et de la latence. Et les limites structurelles de l’admission restent entières, que ce soit le cache stale, les race conditions ou le traitement per-request sans notion de batch.
- Migration JMESPath obligatoire — la deprecation depuis la v1.17 impose une migration vers CEL d’ici octobre 2026 (v1.20). Sur un parc de plusieurs centaines de
ClusterPolicies, c’est un chantier à planifier avec un effort de réécriture et de revalidation.
Quand choisir cette solution ?
Vos besoins dépassent la validation et la mutation. Vous comptez sur la génération automatique de ressources, vous avez besoin d’un contexte décisionnel riche (lookups cluster, API externes) ou vous voulez intégrer la vérification d’images directement dans vos policies. Vous avez aussi besoin d’un outillage mature pour le cycle de vie des policies, avec du reporting structuré, du test CLI et une bibliothèque communautaire pour ne pas partir de zéro.
Quand passer son chemin ?
Vos policies se limitent à de la validation et de la mutation standard. Maintenant que Kyverno et VAP partagent le même langage (CEL), le webhook ne se justifie que par ce que VAP ne fait pas (génération, context externe, image verification, PolicyReports). Si vous n’utilisez aucune de ces fonctionnalités, le webhook est un coût sans contrepartie.
Ou à l’inverse, vos policies sont tellement complexes qu’un vrai langage de policy avec une logique programmatique complète (Rego) serait plus adapté que du CEL.
OPA Gatekeeper
Comment ça marche ?
Gatekeeper est la couche d’intégration entre Open Policy Agent (OPA) et Kubernetes. Comme Kyverno, c’est un webhook d’admission. La différence fondamentale, c’est que les policies s’écrivent en Rego, le langage de policy d’OPA.
Le modèle repose sur deux niveaux. Les ConstraintTemplates définissent la logique en Rego, réutilisable. Les Constraints instancient un template avec des paramètres concrets. Cette séparation permet aux équipes plateforme de fournir des templates, et aux équipes applicatives de les consommer sans toucher au Rego.
Depuis la v3.18, Gatekeeper supporte aussi CEL dans les ConstraintTemplates. Et depuis la v3.20 (toujours en beta), il peut générer des ValidatingAdmissionPolicies natives à partir de ces templates CEL, ce qui permet d’évaluer les policies simples in-process dans l’API server sans passer par le webhook.
Exemple: Interdire les images avec le tag “latest”
1# Le template
2apiVersion: templates.gatekeeper.sh/v1
3kind: ConstraintTemplate
4metadata:
5 name: k8sdenylatesttag
6spec:
7 crd:
8 spec:
9 names:
10 kind: K8sDenyLatestTag
11 targets:
12 - target: admission.k8s.gatekeeper.sh
13 rego: |
14 package k8sdenylatesttag
15
16 violation[{"msg": msg}] {
17 container := input.review.object.spec.containers[_]
18 endswith(container.image, ":latest")
19 msg := sprintf("Image '%v' utilise le tag 'latest'", [container.image])
20 }
21
22 violation[{"msg": msg}] {
23 container := input.review.object.spec.containers[_]
24 not contains(container.image, ":")
25 msg := sprintf("Image '%v' n'a pas de tag explicite", [container.image])
26 }
27---
28# La constraint (instanciation du template)
29apiVersion: constraints.gatekeeper.sh/v1beta1
30kind: K8sDenyLatestTag
31metadata:
32 name: deny-latest-tag
33spec:
34 enforcementAction: deny
35 match:
36 kinds:
37 - apiGroups: [""]
38 kinds: ["Pod"]
Remarque : Deux ressources nécessaires (ConstraintTemplate + Constraint), logique en Rego. Plus verbeux.
Atouts
- Rego, un vrai langage de policy : là où CEL plafonne volontairement, Rego permet d’exprimer de la logique arbitrairement complexe avec des itérations, des agrégations, de la négation, de la manipulation de structures imbriquées. Pour des policies sophistiquées, c’est l’outil le plus expressif sur le marché.
- Séparation template / constraint : le modèle
ConstraintTemplate/Constraintsépare la logique de policy de son implémentation. Les équipes plateforme écrivent le Rego, les équipes applicatives consomment des Constraints paramétrées sans toucher au code. Un modèle qui scale bien dans les organisations avec beaucoup d’équipes. - Portabilité de l’écosystème OPA : l’investissement dans Rego ne sert pas qu’à l’admission Kubernetes. Le même langage fonctionne pour valider des plans Terraform, des configurations CI, des appels API. Un retour sur investissement que ni CEL ni Kyverno ne peuvent offrir.
- Audit périodique natif : Gatekeeper scanne les ressources existantes du cluster en background et remonte les violations sur les Constraints elles-mêmes.
- Testing intégré :
opa testpermet d’écrire des unit tests avec assertions, test cases et coverage. C’est du test de code classique, pas du dry-run contre un cluster. - Bibliothèque communautaire : la Gatekeeper Library fournit un catalogue de
ConstraintTemplatesprêts à l’emploi couvrant les cas courants (labels obligatoires, restrictions d’images, limites de ressources, Pod Security Standards) sans écrire une ligne de Rego.
Limites
- Rego, force et faiblesse : la courbe d’apprentissage est raide. C’est un langage déclaratif logique, pas un langage impératif classique. L’évaluation fonctionne par unification, et pas par exécution séquentielle. Pour une équipe qui part de zéro, c’est un investissement réel, et une policy Rego mal écrite peut être difficile à debugger.
- Mutation limitée : Gatekeeper supporte la mutation via des CRDs déclaratives (Assign, AssignMetadata, ModifySet) qui permettent de setter des valeurs ou injecter des labels. Mais c’est du pattern matching simple, pas de la logique Rego. Pour des mutations complexes ou conditionnelles, c’est limité par rapport à Kyverno.
- Pas de génération de ressources : si vous comptez créer automatiquement des
NetworkPoliciesou desRoleBindingsà la création d’un namespace, il faut regarder ailleurs. - Même dépendance externe que Kyverno : webhook à déployer, monitorer, scaler. Fail-closed par défaut. Latence réseau sur chaque requête. Le Day 2 est comparable.
- Reporting moins intégré : les violations d’audit remontent dans le status de chaque Constraint, mais pour une vue consolidée il faut scraper chaque Constraint individuellement. Moins propre que des
PolicyReportsqueryables via une seule CRD. - Contexte décisionnel plus fermé : Gatekeeper maintient un cache in-memory local par pod, alimenté par des watches sur les types de ressources déclarés dans le sync config. Pas d’appels API externes natifs dans les policies. Le cache souffre des mêmes limites de staleness, et le choix des ressources à synchroniser ajoute une couche de complexité opérationnelle.
Quand choisir cette solution ?
Vos policies sont complexes et la logique dépasse ce que CEL peut exprimer proprement. Vous voulez un langage de policy universel qui sert aussi en CI, sur Terraform, sur Envoy, et votre équipe a la capacité d’investir dans Rego. Ou si vous avez besoin d’un modèle de gouvernance à l’échelle avec une séparation claire entre les auteurs de templates et les consommateurs de contraintes.
Quand passer son chemin ?
La mutation est un besoin critique pour vous. Les CRDs de mutation de Gatekeeper couvrent les cas simples, mais pour de la mutation programmatique, Kyverno ou les MutatingAdmissionPolicies natives sont plus adaptés.
Votre équipe n’a ni le temps ni l’appétit pour apprendre du Rego et vos policies sont assez simples pour que l’investissement ne se justifie pas.
Ou vous avez besoin de génération de ressources, que Gatekeeper ne couvre pas du tout.
Combiner les approches
Rien n’oblige à choisir une seule solution. L’approche la plus pertinente en 2026 consiste à utiliser VAP/MAP natifs comme socle pour les validations et mutations standards, puis empiler Kyverno ou Gatekeeper uniquement pour les capacités que le natif ne couvre pas.
Natif par défaut, webhook à la marge. Concrètement, sur un cluster de production, ça peut ressembler à cela, par exemple :
- Couche native (VAP/MAP) : tout ce qui est convention et garde-fou standard : conventions de nommage et labels obligatoires (ValidatingAdmissionPolicy), restriction des registries d’images autorisées (ValidatingAdmissionPolicy), injection de resource limits par défaut sur les containers qui n’en déclarent pas (MutatingAdmissionPolicy), enforcement des Pod Security Standards (ValidatingAdmissionPolicy, en remplacement du PSA basé sur les labels de namespace).
- Couche Kyverno (webhook) : uniquement ce que le natif ne sait pas faire :
génération automatique de
NetworkPolicies,ResourceQuotasetRoleBindingsà la création d’un namespace (GeneratingPolicy), vérification des signatures d’images Cosign/Sigstore avant déploiement (ImageValidatingPolicy), policies qui ont besoin de contexte externe, par exemple valider qu’un ServiceAccount référencé dans un Deployment existe bien dans le namespace cible (context entries avec lookup cluster).
La frontière est claire : si la policy peut s’exprimer en CEL avec l’objet entrant + unparamRef, elle reste en natif. Dès qu’il faut générer, vérifier une image ou aller chercher du contexte ailleurs, c’est le webhook qui prend le relais.
L’avantage de cette approche, c’est que le webhook ne traite qu’une fraction des requêtes d’admission. Le gros du trafic (les validations et mutations standards) passe in-process dans l’API server sans latence réseau ni dépendance externe. Et si le webhook tombe, l’impact est limité aux capacités avancées, les garde-fous de base continuent de fonctionner.
Pour Gatekeeper, le même raisonnement s’applique : VAP natif pour les policies simples, Gatekeeper pour les policies qui nécessitent la puissance de Rego ou le modèle ConstraintTemplate/Constraint à l’échelle.
Vue d’ensemble
| Critère | VAP / MAP | Kyverno | OPA Gatekeeper |
|---|---|---|---|
| Day 2 | Quasi nul | Réel | Réel |
| Dépendance externe | Aucune | Webhook, fail-closed | Webhook, fail-closed |
| Cycle de vie des policies | Audit -> Deny, pas de CLI | Audit → Enforce, CLI shift-left | dryrun → deny, CLI shift-left |
| Expressivité | CEL | CEL | Rego, le plus expressif |
| Mutation | Oui (GA 1.36) | Oui, programmatique | Limitée (CRDs déclaratives) |
| Génération | Non | Oui | Non |
| Contexte décisionnel | paramRef figé | Context entries + API externes | Cache sync, pas d’API externe |
| Courbe d’apprentissage | Raisonnable | Raisonnable | Raide |
| Auditabilité | Audit annotations | PolicyReports queryables | Violations par Constraint |
| Portabilité | Kubernetes uniquement | Émergente (Kyverno JSON, SDK) | La plus large (Terraform, CI…) |
| Communauté | Kubernetes upstream | CNCF Graduated (mars 2026) | OPA CNCF Graduated |
Évaluez votre besoin
Conclusion
Il n’y a pas de meilleure solution d’admission Kubernetes. Il y a celle qui correspond à votre contexte, la taille de l’équipe, la complexité des policies, la tolérance à la dépendance externe, l’investissement que vous êtes prêts à mettre dans un langage de policy.
Ce qui est nouveau en 2026, c’est que le choix s’est rééquilibré. Avec MutatingAdmissionPolicy en GA dans la 1.36, Kubernetes natif couvre désormais la validation et la mutation sans webhook. L’argument principal qui justifiait Kyverno ou Gatekeeper pour beaucoup d’équipes n’existe plus.
Cela ne rend pas ces outils obsolètes. La génération de ressources, le contexte décisionnel riche, la vérification d’images, les PolicyReports, la portabilité de Rego sont des capacités réelles que VAP n’a pas et n’aura probablement jamais. Mais le choix par défaut a changé.
En 2026, la question n’est plus quel outil j’installe pour faire de l’admission mais est-ce que j’ai vraiment besoin d’un outil en plus de ce que Kubernetes offre nativement.
Réévaluez vos choix. Le paysage a bougé.