<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Politique on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/politique/</link><description>Recent content in Politique on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr-fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Mon, 27 Mar 2023 17:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/politique/index.xml" rel="self" type="application/rss+xml"/><item><title>Réforme des retraites - lettre ouverte à Bérangère Couillard</title><link>https://blog.zwindler.fr/2023/03/27/lettre-ouverte-berangere-couillard/</link><pubDate>Mon, 27 Mar 2023 17:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/03/27/lettre-ouverte-berangere-couillard/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/03/evil-castle.webp" alt="Featured image of post Réforme des retraites - lettre ouverte à Bérangère Couillard" /&gt;&lt;h2 id="note-dintroduction"&gt;Note d&amp;rsquo;introduction
&lt;/h2&gt;&lt;p&gt;Une fois n&amp;rsquo;est pas coutume, je publie sur mon blog une lettre ouverte, postée il y a quelques jours, à une ministre en activité. ce billet a donc un aspect fortement &lt;strong&gt;politique&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Je sais d&amp;rsquo;avance que certains d&amp;rsquo;entre vous vont râler qu&amp;rsquo;un tech ne devrait parler que de tech sur son blog.&lt;/p&gt;
&lt;p&gt;Réjouissez-vous pas avance, j&amp;rsquo;ai donc une astuce &amp;ldquo;purement tech&amp;rdquo; pour vous ! Si vous cliquez sur l&amp;rsquo;icône en forme de petite croix sur l&amp;rsquo;onglet actif de votre navigateur, cette page disparaitra et vous ne me verrez pas parler de politique. Pas mal hein ?&lt;/p&gt;
&lt;h2 id="lettre-ouverte"&gt;Lettre ouverte
&lt;/h2&gt;&lt;p&gt;&lt;em&gt;A l’attention de Bérangère Couillard - Secrétaire d&amp;rsquo;État auprès du ministre de la Transition écologique et de la Cohésion des territoires, chargée de l&amp;rsquo;Écologie&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Chère Madame Couillard,&lt;/p&gt;
&lt;p&gt;Avant d&amp;rsquo;être nommée ministre, vous avez été élue députée de ma circonscription, et je souhaite donc m&amp;rsquo;adresser à vous, indépendamment de mon vote lors des élections législatives.&lt;/p&gt;
&lt;p&gt;Allons droit au but : il est nécessaire que vous fassiez tout ce qui est en votre pouvoir pour empêcher la réforme des retraites (voulue par le gouvernement dont vous faites partie) ne voit le jour. Je vais détailler ici pourquoi.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;abord, c&amp;rsquo;est une réforme inutile. C&amp;rsquo;est l&amp;rsquo;argument principal mis en avant par la première ministre pour la justifier : &amp;ldquo;il faudrait réformer le système pour le sauver&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cependant, une rapide recherche montre que les divers experts, conseil d&amp;rsquo;orientation des retraites inclus, montrent que ce n&amp;rsquo;est pas le cas (1). Selon les hypothèses, le système est faiblement déficitaire (on parle de quelques euros par mois et par actif) et retrouve l&amp;rsquo;équilibre à moyen terme. L’espérance de vie n’augmente plus et le papy boom prendra fin vers 2035.&lt;/p&gt;
&lt;p&gt;Ensuite, la mécanisation, l&amp;rsquo;automatisation, le numérique, les gains de productivité en tous genres font qu&amp;rsquo;il y a de moins en moins de travail. Ce n&amp;rsquo;est pas une fatalité, c&amp;rsquo;est même souhaitable.&lt;/p&gt;
&lt;p&gt;Travailler moins, c&amp;rsquo;est d&amp;rsquo;ailleurs travailler mieux. La récente étude sur la semaine de 4 jours en Angleterre en est un bon exemple. Forcer les gens à travailler plus, plus longtemps, c&amp;rsquo;est aller contre le sens de l&amp;rsquo;histoire.&lt;/p&gt;
&lt;p&gt;Cette réforme va aussi créer de nouveaux problèmes.&lt;/p&gt;
&lt;p&gt;Le premier est l&amp;rsquo;emploi des seniors (ou plutôt son absence) et des coûts supplémentaires pour l&amp;rsquo;assurance maladie. Aujourd&amp;rsquo;hui, le taux de chômage chez les seniors en France, même s&amp;rsquo;il s&amp;rsquo;améliore, reste catastrophique par rapport à nos partenaires européens.&lt;/p&gt;
&lt;p&gt;Pousser l&amp;rsquo;âge de départ, c&amp;rsquo;est aggraver ces problèmes, sans apporter de réelles solutions.&lt;/p&gt;
&lt;p&gt;Des membres du gouvernement ont également reconnu que la réforme allait pénaliser les femmes, notamment en annulant l&amp;rsquo;effet positif des trimestres de majoration pour naissance.&lt;/p&gt;
&lt;p&gt;Pour rappel, l&amp;rsquo;objectif affiché de la majoration de trimestre est de réduire les inégalités (actuelles, réelles) à la retraite (future) entre les hommes et les femmes, notamment à cause des impacts négatifs qu&amp;rsquo;ont pu avoir les naissances d&amp;rsquo;enfants sur les carrières des femmes (induisant ainsi un revenu inférieur à terme). Il ne semble pas réaliste d’imaginer qu’on trouvera une baguette magique pour effacer rétroactivement les différences de salaires entre les hommes et les femmes.&lt;/p&gt;
&lt;p&gt;Les membres du gouvernement ont été incapables de montrer en quoi cette réforme allait apporter des avancées en contrepartie des efforts demandés. Il a été prouvé que les 1200€ ne bénéficieraient qu&amp;rsquo;à une infime part de retraités. Olivier Dussopt l&amp;rsquo;a lui-même reconnu. Il n&amp;rsquo;y a aucun détail sur ce qui est fait pour les carrières hachées. Les seules certitudes sont les reculs sociaux. (2)&lt;/p&gt;
&lt;p&gt;Pour toutes ces raisons, j&amp;rsquo;en appelle à votre responsabilité en tant qu&amp;rsquo;élue, en tant que membre du gouvernement et peut être même avant tout en tant que femme ?&lt;/p&gt;
&lt;p&gt;Vous vous définissez d&amp;rsquo;ailleurs vous même comme féministe, je suis convaincu que défendre les droits des femmes à vivre dans un monde plus juste vous tient à coeur.&lt;/p&gt;
&lt;p&gt;Il est de votre devoir de tout faire pour empêcher que cette réforme, aussi injuste qu&amp;rsquo;inutile, ne voit le jour.&lt;/p&gt;
&lt;p&gt;Dans l&amp;rsquo;espoir de vous lire, je vous présente, madame la ministre, l&amp;rsquo;expression de mes salutations distinguées. Denis GERMAIN, ingénieur en informatique, habitant de la septième circonscription de Gironde.&lt;/p&gt;
&lt;h2 id="notes"&gt;Notes
&lt;/h2&gt;&lt;p&gt;(1) : post publication de cette lettre ouverte, on m&amp;rsquo;a fait remarqué que le COR ne dit pas totalement qu&amp;rsquo;il n&amp;rsquo;est pas nécessaire de réformer. En revanche, il dit qu&amp;rsquo;il n&amp;rsquo;est pas URGENT de réformer, car le système n&amp;rsquo;est pas sur le point d&amp;rsquo;imploser&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;les résultats de ce rapport ne valident pas le bien-fondé des discours qui mettent en avant l’idée d’une dynamique non contrôlée des dépenses de retraite&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.cor-retraites.fr/sites/default/files/2023-02/RA_COR2022_def.pdf" target="_blank" rel="noopener"
&gt;https://www.cor-retraites.fr/sites/default/files/2023-02/RA_COR2022_def.pdf&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or, c&amp;rsquo;était bien l&amp;rsquo;argument matraqué dans les médias par la PM et le reste du gouvernement.&lt;/p&gt;
&lt;p&gt;(2): on m&amp;rsquo;a aussi fait remarquer que le problème des séniors et du chômage était aussi un problème lié à la pénibilité. J&amp;rsquo;ai effectivement oublié de parler de ce point. Les plus touchés par cette réforme seront ceux dont les métiers sont les plus pénibles, pas les cols blancs (dont Madame Couillard et moi même faisons partie).&lt;/p&gt;
&lt;h2 id="note-finale"&gt;Note finale
&lt;/h2&gt;&lt;p&gt;Si d&amp;rsquo;aventure j&amp;rsquo;avais une réponse de Mme Couillard ou de son cabinet, je ne manquerais pas de vous en faire part.&lt;/p&gt;</description></item><item><title>Vos politiques de conformité sur Kubernetes avec Kyverno - part 2</title><link>https://blog.zwindler.fr/2022/09/05/vos-politiques-de-conformite-sur-kubernetes-avec-kyverno-part2/</link><pubDate>Mon, 05 Sep 2022 06:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2022/09/05/vos-politiques-de-conformite-sur-kubernetes-avec-kyverno-part2/</guid><description>&lt;img src="https://blog.zwindler.fr/2022/07/Kyverno_Horizontal.webp" alt="Featured image of post Vos politiques de conformité sur Kubernetes avec Kyverno - part 2" /&gt;&lt;h2 id="récap-de-la-partie-1"&gt;Récap&amp;rsquo; de la partie 1
&lt;/h2&gt;&lt;p&gt;Dans le &lt;a class="link" href="https://blog.zwindler.fr/2022/08/01/vos-politiques-de-conformite-sur-kubernetes-avec-kyverno" target="_blank" rel="noopener"
&gt;précédent article&lt;/a&gt;, j&amp;rsquo;ai introduit &lt;a class="link" href="https://kyverno.io/" target="_blank" rel="noopener"
&gt;Kyverno&lt;/a&gt;, un outil &amp;ldquo;cloud native&amp;rdquo; pour gérer des politiques de conformité sur Kubernetes.&lt;/p&gt;
&lt;p&gt;Pour illustrer les capacités de l&amp;rsquo;outil, j&amp;rsquo;avais pris un exemple : empêcher deux Ingress d&amp;rsquo;utiliser la même URL d&amp;rsquo;entrée. J&amp;rsquo;avais fait le même exercice avec OPA dans un article précédent (&lt;a class="link" href="https://blog.zwindler.fr/2020/07/20/vos-politiques-de-conformite-sur-kubernetes-avec-opa-et-gatekeeper/" &gt;Open Policy Agent (OPA) et de son pendant dans Kubernetes, Gatekeeper&lt;/a&gt;) et j&amp;rsquo;avais comparé à la fin les deux syntaxes (Kyverno vs rego).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/07/rego_vs_kyverno.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai une nette préférence pour la syntaxe de Kyverno, même si OPA est là depuis plus longtemps et n&amp;rsquo;est pas limité à Kubernetes (Kyverno c&amp;rsquo;est uniquement pour Kube).&lt;/p&gt;
&lt;h2 id="aller-un-peu-plus-loin"&gt;Aller un peu plus loin
&lt;/h2&gt;&lt;p&gt;Au-delà de mon exemple, j&amp;rsquo;ai indiqué que Kyverno mettait à disposition un très grand nombre de politiques déjà écrites pour vous (191 au moment où j&amp;rsquo;écris l&amp;rsquo;article).&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://kyverno.io/policies/" target="_blank" rel="noopener"
&gt;kyverno.io/policies&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Par défaut, la plupart des politiques disponibles sont positionnées en mode &amp;ldquo;audit&amp;rdquo; dans un premier temps. N&amp;rsquo;oubliez pas de la passer en mode &amp;ldquo;enforce&amp;rdquo; quand vous serez assez mature sur votre cluster.&lt;/p&gt;
&lt;p&gt;Évidemment, quand on débute on ne sait pas trop par quoi commencer. Le plus simple dans ce cas-là est de déployer la chart Helm &lt;code&gt;kyverno/kyverno-policies&lt;/code&gt;, qui contient l&amp;rsquo;équivalent des Kyverno des &amp;ldquo;Pod Security Standards&amp;rdquo; (les PSP étant officiellement obsolètes depuis la 1.21 je crois, et plus utilisables en 1.25).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm install kyverno-policies kyverno/kyverno-policies -n kyverno
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Thank you &lt;span class="k"&gt;for&lt;/span&gt; installing kyverno-policies v2.5.2 😀
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;We have installed the &lt;span class="s2"&gt;&amp;#34;baseline&amp;#34;&lt;/span&gt; profile of Pod Security Standards and &lt;span class="nb"&gt;set&lt;/span&gt; them in audit mode.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Visit https://kyverno.io/policies/ to find more sample policies.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Voilà ce que ça nous a déployé (la dernière étant déjà là à cause de l&amp;rsquo;article précédent)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get clusterpolicy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME BACKGROUND ACTION READY
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-capabilities &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-host-namespaces &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-host-path &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-host-ports &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-host-process &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-privileged-containers &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-proc-mount &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disallow-selinux &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;restrict-apparmor-profiles &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;restrict-seccomp &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;restrict-sysctls &lt;span class="nb"&gt;true&lt;/span&gt; audit &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unique-ingress-host &lt;span class="nb"&gt;false&lt;/span&gt; enforce &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Avec ça, on va déjà avoir pas mal de pain sur la planche pour éduquer nos utilisateurs (les développeurs) à produire des déploiements Kubernetes sécurisés.&lt;/p&gt;
&lt;h2 id="user-experience"&gt;User experience
&lt;/h2&gt;&lt;p&gt;Un des points ennuyeux de ces deux outils, c&amp;rsquo;est que de base, ils ne sont pas très user friendly. Moi, faire une commande &lt;code&gt;kubectl get events&lt;/code&gt; (voire &lt;code&gt;kubectl get events --field-selector=reason=PolicyViolation&lt;/code&gt; dans le cas de Kyverno) pour savoir pourquoi un déploiement a échoué, ça ne m&amp;rsquo;ennuie pas trop (ça m&amp;rsquo;amuse, presque).&lt;/p&gt;
&lt;p&gt;Mais pour certaines personnes, c&amp;rsquo;est un peu rebutant et je peux l&amp;rsquo;entendre.&lt;/p&gt;
&lt;p&gt;Mon but c&amp;rsquo;est de rendre l&amp;rsquo;infrastructure plus simple à des gens dont qui ce n&amp;rsquo;est pas le métier et imposer ma façon de travailler n&amp;rsquo;est pas forcément la meilleure méthode.&lt;/p&gt;
&lt;p&gt;Souvent, pour aider à adopter un nouvel outil / usage, le plus simple c&amp;rsquo;est de lui fournir une interface graphique.&lt;/p&gt;
&lt;p&gt;Et ça tombe bien, Kyverno dispose d&amp;rsquo;un outil pour faire ça.&lt;/p&gt;
&lt;h2 id="kyverno-policy-reporter"&gt;Kyverno policy reporter
&lt;/h2&gt;&lt;p&gt;En réalité, l&amp;rsquo;outil ne sert pas tout à fait à ça, à la base. Mais vous allez voir que c&amp;rsquo;est même encore mieux.&lt;/p&gt;
&lt;p&gt;Historiquement, l&amp;rsquo;outil s&amp;rsquo;appelle policy reporter, car les développeurs avaient besoin d&amp;rsquo;un outil permettant d&amp;rsquo;exporter facilement et rapidement les &lt;em&gt;PolicyReports&lt;/em&gt; dont je parle dans l&amp;rsquo;article précédent :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;kubectl describe policyreport polr-ns-default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Name: polr-ns-default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Namespace: default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Labels: managed-by=kyverno
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Annotations: &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;API Version: wgpolicyk8s.io/v1alpha2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Kind: PolicyReport
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Results:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Category: Sample
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Message: The Ingress host name must be unique.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Policy: unique-ingress-host
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Resources:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; API Version: networking.k8s.io/v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Kind: Ingress
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Name: ingress2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Summary:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Error: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Fail: 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Pass: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Skip: 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Warn: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le policy reporter a donc pour rôle d&amp;rsquo;exporter les PolicyReports vers plusieurs sources externes pour les traiter plus facilement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grafana Loki&lt;/li&gt;
&lt;li&gt;Elasticsearch&lt;/li&gt;
&lt;li&gt;Slack&lt;/li&gt;
&lt;li&gt;Discord&lt;/li&gt;
&lt;li&gt;MS Teams&lt;/li&gt;
&lt;li&gt;Policy Reporter UI&lt;/li&gt;
&lt;li&gt;S3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je vais vous en parler de 2 : &lt;strong&gt;slack&lt;/strong&gt; et &lt;strong&gt;Policy Reporter UI&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="policy-reporter-ui"&gt;Policy Reporter UI
&lt;/h2&gt;&lt;p&gt;Je commence par l&amp;rsquo;UI, car c&amp;rsquo;est le plus simple à configurer. Il suffit juste de déployer la Chart helm de Policy Reporter en oubliant pas de spécifier qu&amp;rsquo;on veut l&amp;rsquo;UI :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo add policy-reporter https://kyverno.github.io/policy-reporter
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm install -n kyverno policy-reporter policy-reporter/policy-reporter --set kyvernoPlugin.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; --set ui.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; --set ui.plugins.kyverno&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n kyverno get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kyverno-5f8bfd6fc5-xp6bm 1/1 Running &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;59m ago&lt;span class="o"&gt;)&lt;/span&gt; 33d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;policy-reporter-74cc9bf4b9-9ggwh 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 18s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;policy-reporter-kyverno-plugin-6b48c4bc5f-5rwfb 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 18s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;policy-reporter-ui-5c9449d58-f9fwf 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 18s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On peut évidemment ajouter un Ingress mais si on est fénéant comme moi dans cette démo un simple port-forward suffit 🙃.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl port-forward service/policy-reporter-ui 8082:8080 -n kyverno
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;L&amp;rsquo;UI en elle-même est assez intuitive. On a notamment :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un Dashboard avec un gros indicateur global pour savoir combien on a de violation de politiques&lt;/li&gt;
&lt;li&gt;une page avec nos &amp;ldquo;policy reports&amp;rdquo;, dans lequel on peut filtrer par namespace ou par politique&lt;/li&gt;
&lt;li&gt;la liste de nos politiques&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/09/kyverno-policy-reporter-ui.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/09/kyverno-policy-reporter-ui-2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="slack"&gt;Slack
&lt;/h2&gt;&lt;p&gt;On voit tout de suite l&amp;rsquo;intérêt d&amp;rsquo;alerter les administrateurs dans Slack (ou Teams 😭) si jamais une violation de la politique arrive.&lt;/p&gt;
&lt;p&gt;On voit que la configuration est assez triviale, on a juste à ajouter un webhook dans Slack et un petit bout de configuration dans Kyverno&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kyvernoPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kyverno&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;webhook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://hooks.slack.com/services/T0xxxxxxxx&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;minimumPriority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;medium&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;skipExistingOnStartup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;kyverno&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et on re-applique tout ça à notre release helm&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm upgrade -n kyverno policy-reporter policy-reporter/policy-reporter -f kyverno-values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: Si vous ne savez pas comment faire, il faut être admin du workspace Slack, créer une application dans &lt;a class="link" href="https://api.slack.com/apps" target="_blank" rel="noopener"
&gt;https://api.slack.com/apps&lt;/a&gt;, activer les &lt;code&gt;Incoming Webhooks&lt;/code&gt; et en créer un en lui donnant les droits sur un channel.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/09/slack-create-app.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/09/slack-create-app-2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/09/slack-app-webhooks.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/09/slack-app-webhooks-2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="et-si-on-faisait-une-violation-de-politique-pour-voir-"&gt;Et si on faisait une violation de politique, pour voir ?
&lt;/h2&gt;&lt;p&gt;Pour faire simple, je suis reparti de l&amp;rsquo;exemple de l&amp;rsquo;article précédent. Je repasse ma politique &lt;strong&gt;unique-ingress-host&lt;/strong&gt; en mode &lt;strong&gt;audit&lt;/strong&gt; et je recréé l&amp;rsquo;ingress problématique :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl edit clusterpolicy unique-ingress-host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f ingress2.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instantanément, j&amp;rsquo;ai bien 2 échecs qui apparaissent dans l&amp;rsquo;UI de Kyverno, ainsi que des messages dans Slack&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/09/kyverno-fail.avif"
loading="lazy"
&gt;
&lt;img src="https://blog.zwindler.fr/2022/09/kyverno-slack.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Victoire :)&lt;/p&gt;
&lt;h2 id="ressources-complémentaires"&gt;Ressources complémentaires
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kyverno.io/policies/" target="_blank" rel="noopener"
&gt;&amp;ldquo;Catalogue&amp;rdquo; des Politiques officielles de Kyverno&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://dev.to/aurelievache/understanding-kubernetes-part-44-tools-kyverno-52mc" target="_blank" rel="noopener"
&gt;Aurélie Vache - Understanding Kubernetes: part 44 – Tools - Kyverno &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Vos politiques de conformité sur Kubernetes avec Kyverno</title><link>https://blog.zwindler.fr/2022/08/01/vos-politiques-de-conformite-sur-kubernetes-avec-kyverno/</link><pubDate>Mon, 01 Aug 2022 06:00:00 +0000</pubDate><guid>https://blog.zwindler.fr/2022/08/01/vos-politiques-de-conformite-sur-kubernetes-avec-kyverno/</guid><description>&lt;img src="https://blog.zwindler.fr/2022/07/Kyverno_Horizontal.webp" alt="Featured image of post Vos politiques de conformité sur Kubernetes avec Kyverno" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Si le titre de cet article vous dit quelque chose, c&amp;rsquo;est peut-être parce que je l&amp;rsquo;ai déjà utilisé il y a 2 ans tout pile pour parler d&amp;rsquo;un autre logiciel de gestion de politiques de conformité : &lt;a class="link" href="https://blog.zwindler.fr/2020/07/20/vos-politiques-de-conformite-sur-kubernetes-avec-opa-et-gatekeeper/" &gt;Open Policy Agent (OPA) et de son pendant dans Kubernetes, Gatekeeper&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Et je ne vais pas mentir, je n&amp;rsquo;ai pas beaucoup refait de l&amp;rsquo;OPA depuis cet article de 2020&amp;hellip;&lt;/p&gt;
&lt;p&gt;La première raison est que j&amp;rsquo;ai changé d&amp;rsquo;entreprise pile à ce moment-là et que j&amp;rsquo;avais d&amp;rsquo;autres priorités dans la nouvelle entreprise qui m&amp;rsquo;emploie.&lt;/p&gt;
&lt;p&gt;La seconde, certainement plus vraie mais peut être aussi moins avouable, c&amp;rsquo;est qu&amp;rsquo;OPA c&amp;rsquo;est quand même pas super user friendly. Notamment à cause du &lt;strong&gt;rego&lt;/strong&gt;, le langage des politiques de conformités.&lt;/p&gt;
&lt;p&gt;Depuis, j&amp;rsquo;ai découvert &lt;a class="link" href="https://kyverno.io/" target="_blank" rel="noopener"
&gt;Kyverno&lt;/a&gt;, un petit nouveau dans le &amp;ldquo;cloud native&amp;rdquo; game (promu au niveau de &amp;ldquo;sandbox CNCF&amp;rdquo; depuis peu) et qui propose des politiques de conformité pour Kubernetes uniquement (contrairement à OPA + rego qui sont généralistes), écrites en YAML.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With Kyverno, policies are managed as Kubernetes resources and no new language is required to write policies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Prends toi ça, &lt;strong&gt;rego&lt;/strong&gt; ;-)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note :&lt;/strong&gt; Cet article va rester relativement simple, c&amp;rsquo;est une introduction. On ira plus loin dans les articles suivants (coder sa propre politique, l&amp;rsquo;UI, etc).&lt;/p&gt;
&lt;p&gt;Je ne vais pas beaucoup innover par rapport à l&amp;rsquo;article sur OPA et repartir du même cas d&amp;rsquo;usage : interdire à deux développeurs d&amp;rsquo;utiliser la même URL pour leur app web déployée dans Kubernetes (car on a vu que c&amp;rsquo;était assez nul quand ça arrive).&lt;/p&gt;
&lt;p&gt;Et vous allez voir que la première marche d&amp;rsquo;apprentissage est BEAAAAUCOUP plus accessible avec Kyverno que OPA (même si ça va faire râler la moitié de mon Twitter que je parle encore de YAML 🤣).&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;Même topo que pour OPA / Gatekeeper, il faut la 1.14 de Kube pour utiliser Kyverno. La 1.14 était déjà pas la plus récente en 2020, c&amp;rsquo;est carrément la préhistoire maintenant ;-).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your Kubernetes cluster version must be above v1.14 which adds webhook timeouts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bien évidemment, il faut également avoir les droits d’accès admin sur le cluster, car on va devoir créer des &lt;em&gt;Validating Admission Webhooks&lt;/em&gt; et des &lt;em&gt;CRDs&lt;/em&gt;. Là encore, je vous renvoie &lt;a class="link" href="https://blog.zwindler.fr/2020/07/20/vos-politiques-de-conformite-sur-kubernetes-avec-opa-et-gatekeeper/" &gt;au précédent article&lt;/a&gt; et à la doc officielle si ça ne vous parle pas.&lt;/p&gt;
&lt;p&gt;Pour faire bref, on va s&amp;rsquo;insérer dans le processus de déploiement de Kubernetes pour interdire aux gens de faire des choses qui ne respectent pas vos bonnes pratiques (avec les webhooks) et on va ajouter des APIs supplémentaires pour étendre Kubernetes (les CRDs), de manière à pouvoir décrire qu&amp;rsquo;est ce qui n&amp;rsquo;est pas autorisé.&lt;/p&gt;
&lt;h2 id="déploiement"&gt;Déploiement
&lt;/h2&gt;&lt;p&gt;Niveau installation, on reste sur du simple et efficace.&lt;/p&gt;
&lt;p&gt;Kyverno propose plusieurs Charts helm :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une pour &lt;strong&gt;Kyverno&lt;/strong&gt; même&lt;/li&gt;
&lt;li&gt;une pour &lt;strong&gt;Policy Reporter&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;une contenant un &amp;ldquo;pack&amp;rdquo; de règles par défaut, configurées comme &amp;ldquo;non bloquantes&amp;rdquo; (en vrai, l&amp;rsquo;équivalent de ce qu&amp;rsquo;on pouvait faire avec les Pods Security policies)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dans le cadre de cet article, je ne m&amp;rsquo;intéresse qu&amp;rsquo;à Kyverno même. Mais comme je l&amp;rsquo;ai dis plus haut, on reparlera des 2 suivantes dans un prochain numéro.&lt;/p&gt;
&lt;p&gt;On commence donc par ajouter Kyverno lui-même :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; helm repo add kyverno https://kyverno.github.io/kyverno/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; helm install kyverno kyverno/kyverno --namespace kyverno --create-namespace
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; NAME: kyverno
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; LAST DEPLOYED: Mon Jul 25 21:55:11 2022
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; NAMESPACE: kyverno
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; STATUS: deployed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; REVISION: 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; NOTES:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Chart version: v2.5.2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Kyverno version: v1.7.2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Thank you for installing kyverno! Your release is named kyverno.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ⚠️ WARNING: Setting replicas count below 3 means Kyverno is not running in high availability mode.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 💡 Note: There is a trade-off when deciding which approach to take regarding Namespace exclusions. Please see the documentation at https://kyverno.io/docs/installation/#security-vs-operability to understand the risks.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note :&lt;/strong&gt; vous remarquerez le &lt;strong&gt;WARNING&lt;/strong&gt; à l&amp;rsquo;install. Par défaut, Kyverno est déployé avec un seul replica. S&amp;rsquo;il crashe, vous ne pouvez plus rien déployer ou modifier sur votre cluster (ça m&amp;rsquo;est arrivé). La solution pour s&amp;rsquo;en sortir est de supprimer les &lt;strong&gt;webhooks&lt;/strong&gt; de Kyverno pour débloquer la situation. Et bien sûr, de lui donner plus d&amp;rsquo;air (de plus grandes limites, surtout niveau RAM) et surtout 3 réplicas (ou plus)&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note 2 :&lt;/strong&gt; Il est probablement préférable d&amp;rsquo;exclure certains namespaces (kube-system, kyverno, &amp;hellip;) du scope de Kyverno pour éviter de mauvaises surprises. Le blogpost &lt;em&gt;Thibault Lengagne&lt;/em&gt; de chez Padok en parle aussi (lien en bas de l&amp;rsquo;article).&lt;/p&gt;
&lt;h2 id="quest-ce-quon-a-déployé-"&gt;Qu&amp;rsquo;est-ce qu&amp;rsquo;on a déployé ?
&lt;/h2&gt;&lt;p&gt;A première vue, pas grande chose. Si on fait un &lt;code&gt;kubectl -n kyverno get all&lt;/code&gt;, on trouve juste un &lt;em&gt;Pod&lt;/em&gt; (+&lt;em&gt;ReplicaSet&lt;/em&gt; +&lt;em&gt;Deplopyment&lt;/em&gt;) et deux &lt;em&gt;Services&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Mais en coulisse, on a déployé bien plus que ça ;)&lt;/p&gt;
&lt;p&gt;Si on cherche des CRDs, on voit qu&amp;rsquo;on a pas mal de nouveaux objets à notre disposition.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl api-resources --api-group&lt;span class="o"&gt;=&lt;/span&gt;kyverno.io
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; NAME SHORTNAMES APIVERSION NAMESPACED KIND
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; clusterpolicies cpol kyverno.io/v1 false ClusterPolicy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; clusterreportchangerequests crcr kyverno.io/v1alpha2 false ClusterReportChangeRequest
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; generaterequests gr kyverno.io/v1 true GenerateRequest
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; policies pol kyverno.io/v1 true Policy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; reportchangerequests rcr kyverno.io/v1alpha2 true ReportChangeRequest
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; updaterequests ur kyverno.io/v1beta1 true UpdateRequest
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;De même, on a également des nouveaux webhooks&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; NAME WEBHOOKS AGE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; kyverno-policy-validating-webhook-cfg 1 8m48s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; kyverno-resource-validating-webhook-cfg 2 8m48s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; NAME WEBHOOKS AGE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; kyverno-policy-mutating-webhook-cfg 1 11m
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; kyverno-resource-mutating-webhook-cfg 2 11m
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; kyverno-verify-mutating-webhook-cfg 1 11m
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;A quoi ça sert ? Comment ça marche ?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour simplifier, on va décrire ce qu&amp;rsquo;on ne veut pas autoriser dans notre cluster à l&amp;rsquo;aide de la CRD &lt;em&gt;ClusterPolicy&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;En fonction des règles qu&amp;rsquo;on aura écrites dedans, les &lt;strong&gt;webhooks&lt;/strong&gt; vont s&amp;rsquo;insérer dans le processus normal de déploiement de ressources de Kubernetes pour les autoriser ou pas.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/07/admission-controller-phases.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a class="link" href="https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/" target="_blank" rel="noopener"
&gt;Kubernetes Blog - A Guide to Kubernetes Admission Controllers&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="exemple-des-ingress-avec-la-même-url"&gt;Exemple des Ingress avec la même URL
&lt;/h2&gt;&lt;p&gt;Assez de théorie, le plus simple c&amp;rsquo;est que je vous montre. Je vous l&amp;rsquo;ai dit au début de l&amp;rsquo;article, de manière à comparer les deux produits, je vais repartir du même cas d&amp;rsquo;usage.&lt;/p&gt;
&lt;p&gt;Dans mes clusters Kubernetes, je veux interdire à deux applications de créer un &lt;em&gt;Ingress&lt;/em&gt; avec la même URL, car dans mon cas personnel, ce n&amp;rsquo;est pas autorisé. C&amp;rsquo;est le signe d&amp;rsquo;une erreur de copié-collé d&amp;rsquo;une Chart Helm vers une autre (ou tout autre erreur humaine).&lt;/p&gt;
&lt;p&gt;La conséquence de cette erreur est un conflit dans le routage des requêtes HTTP entrantes et on se retrouve avec &lt;em&gt;un genre de round robin chelou&lt;/em&gt; où la moitié des requêtes tapent le mauvais backend. En prod, ça la fout mal, et on risque de se retrouver avec des clients qui râlent sur Twitter que l&amp;rsquo;application est down ;-).&lt;/p&gt;
&lt;p&gt;Au même titre qu&amp;rsquo;OPA propose de régler ce problème dans les politiques mises à disposition par la communauté, &lt;a class="link" href="https://kyverno.io/policies/other/unique-ingress-paths/unique-ingress-paths/" target="_blank" rel="noopener"
&gt;il existe la même avec Kyverno&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On verra plus en détails dans l&amp;rsquo;article suivant comment sont construites ces règles. Dans un premier temps, on va juste déployer cette règle en mode &amp;ldquo;audit&amp;rdquo; et voir si ça fonctionne.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;spec:
validationFailureAction: audit&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl apply -f https://raw.githubusercontent.com/kyverno/policies/main/other/unique-ingress-paths/unique-ingress-paths.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; clusterpolicy.kyverno.io/unique-ingress-host created
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si vous avez un cluster kubernetes sous la main, je vous propose donc d&amp;rsquo;appliquer ces deux &lt;em&gt;Ingress&lt;/em&gt;, configurés pour récupérer du trafic depuis la même URL (toto.example.org) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; counter in &lt;span class="m"&gt;1&lt;/span&gt; 2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;cat &amp;gt; ingress${counter}.yaml &amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;apiVersion: networking.k8s.io/v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;kind: Ingress
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; name: ingress${counter}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; rules:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; - host: toto.example.org
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; http:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; paths:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; - path: /
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; pathType: Prefix
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; backend:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; service:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; name: service${counter}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; port:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; number: 4200
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl apply -f ingress1.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ingress.networking.k8s.io/ingress1 created
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl apply -f ingress2.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ingress.networking.k8s.io/ingress2 created
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Normalement, rien ne se passe. Kyverno ne vous empêche pas de créer ces deux &lt;em&gt;Ingress&lt;/em&gt; puisqu&amp;rsquo;on est en mode &amp;ldquo;validationFailureAction: audit&amp;rdquo; (même si les backends n&amp;rsquo;existent pas derrière, ça n&amp;rsquo;a pas d&amp;rsquo;importance).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl get ingress
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; NAME CLASS HOSTS ADDRESS PORTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ingress1 &amp;lt;none&amp;gt; toto.example.org 80 90s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ingress2 &amp;lt;none&amp;gt; toto.example.org 80 87s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En revanche, en allant lire les &lt;strong&gt;Events&lt;/strong&gt;, vous allez trouver des &lt;strong&gt;PolicyViolation&lt;/strong&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl get events --field-selector&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PolicyViolation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;LAST SEEN TYPE REASON OBJECT MESSAGE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;118s Warning PolicyViolation ingress/ingress1 policy unique-ingress-host/check-single-host fail: The Ingress host name must be unique.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;118s Warning PolicyViolation ingress/ingress1 policy unique-ingress-host/check-single-host fail: The Ingress host name must be unique.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;118s Warning PolicyViolation clusterpolicy/unique-ingress-host Ingress default/ingress1: [check-single-host] fail
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;115s Warning PolicyViolation clusterpolicy/unique-ingress-host Ingress default/ingress2: [check-single-host] fail
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le fait qu&amp;rsquo;on ait 2 &lt;em&gt;Ingress&lt;/em&gt; pointant sur la même URL est bien détecté et est remonté dans les &lt;em&gt;Events&lt;/em&gt; Kubernetes. Chouette :)&lt;/p&gt;
&lt;p&gt;En beaucoup plus verbeux, on pourra également récupérer les &lt;em&gt;PolicyReports&lt;/em&gt;, qui disent la même chose en (encore ?) moins lisible.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;kubectl describe policyreport polr-ns-default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Name: polr-ns-default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Namespace: default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Labels: managed-by=kyverno
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Annotations: &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;API Version: wgpolicyk8s.io/v1alpha2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Kind: PolicyReport
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Results:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Category: Sample
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Message: The Ingress host name must be unique.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Policy: unique-ingress-host
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Resources:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; API Version: networking.k8s.io/v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Kind: Ingress
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Name: ingress2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Summary:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Error: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Fail: 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Pass: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Skip: 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; Warn: 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On nettoie pour la suite :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl delete ingress ingress1 ingress2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="la-loi-cest-moi"&gt;&amp;ldquo;La loi, c&amp;rsquo;est moi&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;Imaginons que vous avez maintenant bien testé vos politiques, que vos devs ne génèrent plus de manifests ne correspondant pas à vos bonnes pratiques (ex. pas de containers en root, des labels obligatoires présents, limits/requests correctes, etc). Votre cluster est propre !&lt;/p&gt;
&lt;p&gt;Vous pouvez passer vos politiques de conformités en mode &amp;ldquo;enforcing&amp;rdquo;. Contrairement au mode &amp;ldquo;audit&amp;rdquo;, ce mode est bloquant et les manifests qui ne respectent pas les politiques en questions seront refusés par Kubernetes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl patch clusterpolicies.kyverno.io unique-ingress-host --patch &lt;span class="s1"&gt;&amp;#39;{&amp;#34;spec&amp;#34;:{&amp;#34;validationFailureAction&amp;#34;:&amp;#34;enforce&amp;#34;}}&amp;#39;&lt;/span&gt; --type merge
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Oui, je fais un &amp;ldquo;patch&amp;rdquo; plutôt qu&amp;rsquo;un &amp;ldquo;edit&amp;rdquo; pour me la péter ;-)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Et on teste à nouveau :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl apply -f ingress1.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ingress.networking.k8s.io/ingress1 created
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So far, so good&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; kubectl apply -f ingress2.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Error from server: error when creating &amp;#34;ingress2.yaml&amp;#34;: admission webhook &amp;#34;validate.kyverno.svc-fail&amp;#34; denied the request:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;resource Ingress/default/ingress2.yaml was blocked due to the following policies
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;unique-ingress-host:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; check-single-host: The Ingress host name must be unique.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ET PAF 💥🍫!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/chocapic.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Dans cet exemple basique (mais réellement utile), on arrive aussi facilement qu&amp;rsquo;avec OPA à empêcher les utilisateurs de créer des &lt;em&gt;Ingress&lt;/em&gt; ayant la même URL.&lt;/p&gt;
&lt;p&gt;On peut alors se demander &amp;ldquo;pourquoi préférer Kyverno ?&amp;rdquo;. Au-delà d&amp;rsquo;autres trucs sympas que nous verrons dans les billets suivants, ma réponse va tenir en une seule image.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/07/rego_vs_kyverno.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Mon point de vue (très personnel), c&amp;rsquo;est que le &lt;strong&gt;rego&lt;/strong&gt;, c&amp;rsquo;est illisible et verbeux, et donc pas maintenable. Là encore, c&amp;rsquo;est personnel, mais je n&amp;rsquo;ai jamais réussi à m&amp;rsquo;y mettre.&lt;/p&gt;
&lt;p&gt;Sans aller jusqu&amp;rsquo;à idéaliser le langage de Kyverno*, je trouve que c&amp;rsquo;est quand même clairement &lt;strong&gt;beaucoup plus simple&lt;/strong&gt; à écrire, mais surtout, à lire. Dans le cas où vous devriez modifier/écrire/maintenir vos propres politiques, cela sera très utile.&lt;/p&gt;
&lt;p&gt;(*Oui, il y a un langage, notamment pour le pattern matching&amp;hellip; et point irritant, ce n&amp;rsquo;est &lt;strong&gt;pas&lt;/strong&gt; jsonpath comme pour &lt;code&gt;kubectl&lt;/code&gt;, mais &lt;a class="link" href="https://kyverno.io/docs/writing-policies/variables/" target="_blank" rel="noopener"
&gt;JMESPath&lt;/a&gt;, similaire mais pas identique&amp;hellip;)&lt;/p&gt;
&lt;h2 id="ressources-complémentaires"&gt;Ressources complémentaires
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kyverno.io/policies/" target="_blank" rel="noopener"
&gt;&amp;ldquo;Catalogue&amp;rdquo; des Politiques officielles de Kyverno&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.padok.fr/blog/securite-kubernetes-kyverno" target="_blank" rel="noopener"
&gt;Blog de Padok - Kyverno : Sécuriser vos environnements Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://dev.to/aurelievache/understanding-kubernetes-part-44-tools-kyverno-52mc" target="_blank" rel="noopener"
&gt;Aurélie Vache - Understanding Kubernetes: part 44 – Tools - Kyverno &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/" target="_blank" rel="noopener"
&gt;Kubernetes Blog - A Guide to Kubernetes Admission Controllers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Vos politiques de conformité sur Kubernetes avec OPA et Gatekeeper</title><link>https://blog.zwindler.fr/2020/07/20/vos-politiques-de-conformite-sur-kubernetes-avec-opa-et-gatekeeper/</link><pubDate>Mon, 20 Jul 2020 06:35:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/07/20/vos-politiques-de-conformite-sur-kubernetes-avec-opa-et-gatekeeper/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/05/gatekeeper.webp" alt="Featured image of post Vos politiques de conformité sur Kubernetes avec OPA et Gatekeeper" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Un des problèmes que j’ai rencontré en administrant des clusters Kubernetes mutualisés entre plusieurs équipes était que les manifests qui étaient déployés n’étaient pas toujours parfaitement maîtrisés.&lt;/p&gt;
&lt;p&gt;Dans certains cas, les manifests étaient copiés/collés d’autres équipes, provoquant parfois de petites surprises (pas de label pour indiquer l’équipe responsable de l’appli, mauvaises infos pour les Ingress&amp;hellip;). Une des solutions trouvée a été de maintenir à jour un Chart Helm le plus générique possible, avec seulement des values à rentrer pour les développeurs. Ce Chart est maintenu conjointement par les Ops et les techleads.&lt;/p&gt;
&lt;p&gt;Cependant, maintenir ce template est complexe et certaines applis s’éloignent trop du cadre général pour s’y conformer, même en forkant et en modifiant une partie des infos. Et certains problèmes comme la vérification des images ou des registries tournant sur la plateforme n’étaient pas traités par cette solution.&lt;/p&gt;
&lt;h2 id="open-policy-agent--gatekeeper"&gt;Open Policy Agent / Gatekeeper
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/07/opa.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a class="link" href="https://www.thingiverse.com/thing:1236133" target="_blank" rel="noopener"
&gt;https://www.thingiverse.com/thing:1236133&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Plutôt que de vouloir unifier à tout prix la façon dont sont déployées les applications dans le cluster (et devoir gérer les exceptions), une autre façon de voir les choses est d’ajouter un outil qui permettrait de vérifier, au moment où on déploie, que ce qui est déployé respecte les bonnes pratiques de l’entreprise en termes de sécurité et de configuration.&lt;/p&gt;
&lt;p&gt;Vous l’avez deviné, l’outil pour faire ça, c’est Open Policy Agent (ou OPA). Il s’agit d’un moteur de politiques générique open source (projet CNCF au stade Incubating).&lt;/p&gt;
&lt;p&gt;Comme c’est un moteur générique, il existe également un autre projet,&lt;a class="link" href="https://github.com/open-policy-agent/gatekeeper" target="_blank" rel="noopener"
&gt;Gatekeeper&lt;/a&gt;, qui lui permet de gérer l’interaction entre OPA et Kubernetes.&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;To use Gatekeeper, you should have a minimum Kubernetes version of 1.14, which adds webhook timeouts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Si vous êtes dans une version antérieure, ça se complique. Il existe un bug, fixé en 1.14, qui pourra faire planter votre OPA/Gatekeeper. Pour cette raison, si vous n’êtes pas en 1.14 (et que vous ne pouvez pas mettre à jour votre plateforme), il faudra se passer de Gatekeeper (via K8s Policy Controller par exemple). C’est un peu plus touchy et hors du scope de ce tutoriel.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/k8spolicycontroller.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;La « V2 », sans Gatekeeper, avec Kube-Mgmt et OPA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bien évidemment, il faut également avoir les droits d’accès admin sur le cluster. Gatekeeper propose de tester que vous avez des droits adéquats simplement en essayant de vous attribuer à vous-même les droits admins.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/inception.gif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;wait for it&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole cluster-admin \
--user [votre user]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Petite astuce, si vous ne connaissez pas le nom du compte d’accès que vous utilisez actuellement, vous pouvez lancer cette commande :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl config view --template=&amp;#39;{{ range .contexts }}{{ if eq .name &amp;#34;&amp;#39;$(kubectl config current-context)&amp;#39;&amp;#34; }}Current user: {{ .context.user }}{{ end }}{{ end }}&amp;#39;
Current user: clusterUser_zwindlerk8s_rg_zwindlerk8s
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="installation"&gt;Installation
&lt;/h2&gt;&lt;p&gt;Je me suis donc créé pour l’occasion un petit cluster sur AKS en version 1.14 et j’ai déployé la version prépackagée de Gatekeeper.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Tadam ! Et hop, Gatekeeper est installé dans votre cluster.
Note : La documentation officielle donne les étapes pour &lt;a class="link" href="https://github.com/open-policy-agent/gatekeeper#deploying-head-using-make" target="_blank" rel="noopener"
&gt;construire vous-même votre image&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="ya-quoi-dans-mon-cluster-"&gt;Ya quoi dans mon cluster ?
&lt;/h2&gt;&lt;p&gt;En se penchant de plus près sur ce que fait le &lt;em&gt;manifest&lt;/em&gt;, voici ce que vous déployez lorsque vous lancez la commande ci-dessus :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un Namespace &lt;code&gt;gatekeeper-system&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;un ServiceAccount &lt;code&gt;gatekeeper-admin&lt;/code&gt;, associé à un Role et un ClusterRole &lt;code&gt;gatekeeper-manager-role&lt;/code&gt; via (respectivement) un RoleBinding et ClusterRoleBinding &lt;code&gt;gatekeeper-manager-rolebinding&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;un Deployment &lt;code&gt;gatekeeper-controller-manager&lt;/code&gt; et &lt;code&gt;gatekeeper-audit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;un Service &lt;code&gt;gatekeeper-webhook-service&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;un Secret &lt;code&gt;gatekeeper-webhook-server-cert&lt;/code&gt; qui contient un certificat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jusque-là rien d’exceptionnel. Là où ça commence à devenir intéressant c’est :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;deux CRD (Custom Resource Definition) &lt;code&gt;configs.config.gatekeeper.sh&lt;/code&gt; et &lt;code&gt;constrainttemplates.templates.gatekeeper.sh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;un validating webhook configuration &lt;code&gt;gatekeeper-validating-webhook-configuration&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="validating-webhook"&gt;Validating Webhook
&lt;/h2&gt;&lt;p&gt;Le validation webhook d’abord. La première fois que j’ai entendu parler de validating webhooks, c’était lors du talk &lt;a class="link" href="https://www.youtube.com/watch?v=likHm-KHGWQ" target="_blank" rel="noopener"
&gt;101 Ways to “Break and Recover” Kubernetes Cluster&lt;/a&gt; à la Kubecon 2018.&lt;/p&gt;
&lt;p&gt;Les problèmes de ces employés de Oath (ex-Yahoo) étaient identiques aux miens. Certaines équipes, en récupérant (aka copiant/collant) des manifests provenant d’autres équipes, oubliaient de changer les URL des Ingress. On se retrouvait ainsi avec des requêtes d’utilisateurs qui se retrouvaient distribuées de manière aléatoires vers 2 services totalement différents.&lt;/p&gt;
&lt;p&gt;La solution proposée à cette conf était d’utiliser des Validating/Mutating Admission Webhooks de Kubernetes (à peu près stable depuis la 1.11).&lt;/p&gt;
&lt;p&gt;En 2018, en creusant le sujet, j’ai trouvé assez peu de documentation là-dessus, au-delà de la doc officielle (j’en ai trouvé un peu plus depuis). Autre problème, les Admissions webhooks nécessitent de développer son propre Controller, ce qui n’était pas très accessible (cf les liens en fin d’article).&lt;/p&gt;
&lt;p&gt;Heureusement pour nous, Gatekeeper et OPA vont s’occuper de ça pour nous.&lt;/p&gt;
&lt;h2 id="custom-resource-definition"&gt;Custom Resource Definition
&lt;/h2&gt;&lt;p&gt;Pour ceux qui ne connaissent pas les CRD, il s’agit pour faire simple des extensions de l’API de Kubernetes. Le gros avantage des CRDs est que ces objets sont un moyen pour les éditeurs tiers d’ajouter de la logique qui leur est propre &lt;em&gt;dans&lt;/em&gt; Kubernetes.
J’ai déjà un peu parlé de CRD dans cet article sur &lt;a class="link" href="https://blog.zwindler.fr/2019/09/10/du-ceph-dans-mon-kubernetes/" &gt;Rook&lt;/a&gt; qui permet de gérer de manière automatisée des clusters Ceph (et pas que !) via le CRD CephCluster. Toutes les tâches d’administration courantes sont intégrées à Kubernetes (alors que de base Kube n’en a aucune connaissance), gérées par un Controller inclus dans Rook et configurées via des CRDs.&lt;/p&gt;
&lt;p&gt;Gatekeeper va donc ajouter 3 composants à notre Kubernetes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un objet Config&lt;/li&gt;
&lt;li&gt;un objet ConstraintTemplate&lt;/li&gt;
&lt;li&gt;un objet Constraint&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="config"&gt;Config
&lt;/h2&gt;&lt;p&gt;Le principe de Gatekeeper, comme on le voit dans le schéma suivant, est qu’il se branche sur l’API server de votre Kubernetes et qu’il &amp;ldquo;synchronise&amp;rdquo; les événements de création de nouveaux objets, à la recherche d’objets qui ne respecteraient pas vos politiques de conformité.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/gatekeeper_v3.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Source : &lt;a class="link" href="https://kubernetes.io/blog/2019/08/06/opa-gatekeeper-policy-and-governance-for-kubernetes/" target="_blank" rel="noopener"
&gt;kubernetes.io/blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Par défaut, si vous ne lui dites rien, Gatekeeper n’écoute les événements d’aucuns objets Kubernetes&amp;hellip; il ne fera donc&amp;hellip; rien du tout !&lt;/p&gt;
&lt;p&gt;On change ça tout de suite en disant à Gatekeeper d’écouter tous les événements sur les Ingress :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat gatekeeper/demo/basic/sync.yaml
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: &amp;#34;gatekeeper-system&amp;#34;
spec:
sync:
syncOnly:
- group: &amp;#34;extensions&amp;#34;
version: &amp;#34;v1beta1&amp;#34;
kind: &amp;#34;Ingress&amp;#34;
- group: &amp;#34;networking.k8s.io&amp;#34;
version: &amp;#34;v1beta1&amp;#34;
kind: &amp;#34;Ingress&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="constrainttemplate"&gt;ConstraintTemplate
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Before you can define a constraint, you must first define a ConstraintTemplate, which describes both the Rego that enforces the constraint and the schema of the constraint.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;L’idée ici, c’est qu’avant de commencer à créer des contraintes sur le cluster, il va falloir créer des templates de contraintes. Il faut voir ces templates comme l’objet qui va relier d’un côté la fonction (le code en rego d’OPA) d’un côté et des paramètres de l’autre.&lt;/p&gt;
&lt;p&gt;Cette étape supplémentaire nous permettra éventuellement de réutiliser le même template pour plusieurs contraintes différentes.&lt;/p&gt;
&lt;h2 id="votre-premier-template"&gt;Votre premier template
&lt;/h2&gt;&lt;p&gt;Pour la première fois, on peut se contenter d’utiliser les templates fournis en exemple sur le Github de OPA/Gatekeeper et qui permet d’imposer la présence d’un label dans un type d’objet Kube donné, car il est plus simple (&lt;a class="link" href="https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/demo/basic/templates/k8srequiredlabels_template.yaml" target="_blank" rel="noopener"
&gt;k8srequiredlabels_template.yaml&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Cependant, depuis tout à l’heure, je vous parle d&amp;rsquo;empêcher les équipes d’utiliser le même FQDN dans des Ingress pour plusieurs services. Car si ça venait à arriver, je le rappelle, on aurait un genre de loadbalancer chelou qui redirigerait la moitié des requêtes des utilisateurs sur une application ou sur l’autre pour une même URL.&lt;/p&gt;
&lt;p&gt;Et ça tombe bien, ce &lt;a class="link" href="https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/demo/agilebank/dryrun/k8suniqueingresshost_template.yaml" target="_blank" rel="noopener"
&gt;template&lt;/a&gt; va nous permettre de nous en assurer !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8suniqueingresshost
spec:
crd:
spec:
names:
kind: K8sUniqueIngressHost
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8suniqueingresshost
identical(obj, review) {
obj.metadata.namespace == review.object.metadata.namespace
obj.metadata.name == review.object.metadata.name
}
violation[{&amp;#34;msg&amp;#34;: msg}] {
input.review.kind.kind == &amp;#34;Ingress&amp;#34;
re_match(&amp;#34;^(extensions|networking.k8s.io)$&amp;#34;, input.review.kind.group)
host := input.review.object.spec.rules[_].host
other := data.inventory.namespace[ns][otherapiversion][&amp;#34;Ingress&amp;#34;][name]
re_match(&amp;#34;^(extensions|networking.k8s.io)/.+$&amp;#34;, otherapiversion)
other.spec.rules[_].host == host
not identical(other, input.review)
msg := sprintf(&amp;#34;ingress host conflicts with an existing ingress &amp;lt;%v&amp;gt;&amp;#34;, [host])
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Au premier abord, c’est quand même assez touffu. Bon après, j’ai pas pris l’exemple le plus simple non plus, et si vous re-regardez la vidéo &lt;a class="link" href="https://www.youtube.com/watch?v=Yup1FUc2Qn0&amp;amp;feature=youtu.be" target="_blank" rel="noopener"
&gt;Kubecon 2019 | Intro: Open Policy Agent - Rita Zhang, Microsoft &amp;amp; Max Smythe, Google&lt;/a&gt;, c’est en fait assez simple à comprendre.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/demo/agilebank/dryrun/k8suniqueingresshost_template.yaml
constrainttemplate.templates.gatekeeper.sh/k8suniqueingresshost created
kubectl get constrainttemplate
NAME AGE
k8suniqueingresshost 23m
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="et-une-constraint"&gt;Et une Constraint
&lt;/h2&gt;&lt;p&gt;Maintenant qu’on a notre template, on peut donc simplement l’instancier avec les variables qui nous intéressent.&lt;/p&gt;
&lt;p&gt;Pour rester dans l’exemple en démo, on s’assure que dans tout le cluster, il n’existe pas 2 fois la même URL pour 2 Ingress différents en instanciant cette contrainte :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sUniqueIngressHost
metadata:
name: unique-ingress-host
spec:
enforcementAction: dryrun
match:
kinds:
- apiGroups: [&amp;#34;extensions&amp;#34;, &amp;#34;networking.k8s.io&amp;#34;]
kinds: [&amp;#34;Ingress&amp;#34;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Je vais un tout petit peu modifier cette Contrainte car comme vous pouvez le voir, elle définie une enforcementAction: &lt;code&gt;dryrun&lt;/code&gt;, qui n’a pas d’effet immédiat (ça logue juste une erreur pour un audit futur). C’est une super feature qui permet de monter en compétence sur OPA, mais pour ma démo c’est moins fun&amp;hellip;&lt;/p&gt;
&lt;p&gt;Donc j’applique le fichier et je modifie l’enforcementAction&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/demo/agilebank/dryrun/unique-ingress-host.yaml
kubectl patch K8sUniqueIngressHost.constraints.gatekeeper.sh unique-ingress-host -p &amp;#39;{&amp;#34;spec&amp;#34;:{&amp;#34;enforcementAction&amp;#34;:&amp;#34;deny&amp;#34;}}&amp;#39; --type=merge
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="et-enfin-on-essaye"&gt;Et enfin, on essaye
&lt;/h2&gt;&lt;p&gt;Normalement on a tout maintenant. Gatekeeper écoute sur l’API server tous les événements des objets de type Ingress (via la Config). On a un ContraintTemplate avec du code &lt;code&gt;rego&lt;/code&gt; qui va vérifier qu’on a pas déjà une autre URL identique dans les Ingress existant et une Constraint qui définie ce qu’on doit faire (dryrun) et sur quels objets (Ingress).&lt;/p&gt;
&lt;p&gt;On peut donc dérouler la démo :D&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Creation du namespace qui contiendra les objets de la demo
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/demo/agilebank/bad_resources/namespace.yaml
namespace/production created
# Creation d&amp;#39;un Ingress avec une URL qui n&amp;#39;existe pas encore
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/demo/agilebank/dryrun/existing_resources/example.yaml
ingress.extensions/ingress-host created
# Creation d&amp;#39;un second Ingress avec la MEME URL
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/demo/agilebank/dryrun/bad_resource/duplicate_ing.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et paf !&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[denied by unique-ingress-host] ingress host conflicts with an existing ingress &amp;lt;example-host.example.org&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/chocapic.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Je l’expliquais en introduction, ajouter des politiques de conformités et des contraintes sur un cluster Kubernetes n’était pas trivial.&lt;/p&gt;
&lt;p&gt;Sans aller jusqu’à dire que ça devient simple, OPA et Gatekeeper facilitent le travail (plus besoin de développer puis d’héberger soi-même un microservice pour chaque Admission/validation Webhook). Il reste est nécessaire de s’approprier un nouveau langage (rego) pour commencer à faire des choses sympa, mais pour autant, rien qu’avec les templates par défaut, il y a déjà de quoi faire.&lt;/p&gt;
&lt;p&gt;Un autre point vraiment intéressant avec OPA, c’est la possibilité de loguer et d’auditer toutes les erreurs de conformités avec le mode &lt;code&gt;dryrun&lt;/code&gt; à la place du &lt;code&gt;deny&lt;/code&gt;, sans bloquer.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get K8sUniqueIngressHost.constraints.gatekeeper.sh unique-ingress-host -o yaml
[...]
- enforcementAction: dryrun
kind: Ingress
message: ingress host conflicts with an existing ingress &amp;lt;example-host.example.org&amp;gt;
name: ingress-host2
namespace: default
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="sources"&gt;Sources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/blog/2019/08/06/opa-gatekeeper-policy-and-governance-for-kubernetes/" target="_blank" rel="noopener"
&gt;Kubernetes.io | OPA Gatekeeper: Policy and Governance for Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=Yup1FUc2Qn0&amp;amp;feature=youtu.be" target="_blank" rel="noopener"
&gt;Kubecon 2019 | Intro: Open Policy Agent - Rita Zhang, Microsoft &amp;amp; Max Smythe, Google&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/" target="_blank" rel="noopener"
&gt;A Guide to Kubernetes Admission Controllers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.container-solutions.com/some-admission-webhook-basics" target="_blank" rel="noopener"
&gt;Blog container-solutions | Some Admission Webhook Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://medium.com/ibm-cloud/diving-into-kubernetes-mutatingadmissionwebhook-6ef3c5695f74" target="_blank" rel="noopener"
&gt;IBM Cloud | Diving into Kubernetes MutatingAdmissionWebhook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>