<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Security on Valérian Pyckaert</title>
    <link>https://valerian-pyckaert.dev/tags/security/</link>
    <description>Recent content in Security on Valérian Pyckaert</description>
    <image>
      <title>Valérian Pyckaert</title>
      <url>https://valerian-pyckaert.dev/images/default-cover.svg</url>
      <link>https://valerian-pyckaert.dev/images/default-cover.svg</link>
    </image>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Mon, 08 Jun 2026 19:00:00 +0200</lastBuildDate>
    <atom:link href="https://valerian-pyckaert.dev/tags/security/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>SOPS - Comment gérer les secrets dans un repo GitOps?</title>
      <link>https://valerian-pyckaert.dev/posts/sops/</link>
      <pubDate>Mon, 08 Jun 2026 19:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/sops/</guid>
      <description>Comment gérer les secrets dans un repo GitOps avec SOPS.</description>
      <content:encoded><![CDATA[<h2 id="le-problème-des-secrets-en-gitops">Le problème des secrets en GitOps</h2>
<p>Dans une approche GitOps, tout passe par le repo Git : les manifests Kubernetes, les configurations, et idéalement les secrets aussi. Mais comment gérer les secrets de manière sécurisée dans un repo Git ?</p>
<hr>
<h2 id="sops--secrets-operations">SOPS : Secrets OPerationS</h2>
<h3 id="principe--chiffrement-côté-fichier">Principe : chiffrement côté fichier</h3>
<p><a href="https://github.com/mozilla/sops">SOPS</a> s&rsquo;intègre aux KMS, par exemple sur GCP <a href="https://cloud.google.com/security/products/security-key-management?hl=en">Cloud Key Management</a> via le principe d&rsquo;<a href="https://docs.cloud.google.com/kms/docs/envelope-encryption?hl=en">Envelope Encryption</a> : il génère une clé symétrique éphémère (DEK) pour chiffrer les secrets, et délègue à GCP KMS le chiffrement de cette DEK.</p>
<p>Le KMS ne voit jamais les secrets eux-mêmes, et le fichier commité dans Git contient les valeurs chiffrées ainsi que la DEK chiffrée.</p>
<p>En local, un <code>gcloud auth application-default login</code> suffit alors qu&rsquo;en production sur GKE il est plutot préférable d&rsquo;utiliser le <code>Workload Identity</code> pour lier le <code>ServiceAccount</code> Kubernetes au compte de service GCP.</p>
<p>Chaque opération est enfin tracée dans <a href="https://cloud.google.com/logging/docs/audit">Cloud Audit Logs</a>.</p>
<h3 id="limitations">Limitations</h3>
<ul>
<li>Nécessite une infrastructure de gestion de clés externe (KMS ou PGP/Age). Cela introduit une dépendance sur AWS KMS, GCP KMS, etc.</li>
<li>La rotation de clé implique de re-chiffrer tous les fichiers concernés (<code>sops updatekeys</code>).</li>
<li>SOPS ne crée pas de Secret Kubernetes directement. Il faut un outil intermédiaire : Helm Secrets, ArgoCD avec plugin, Kustomize + plugin, ou un job de déchiffrement en pipeline CI/CD.</li>
<li>Le déchiffrement se fait souvent dans le pipeline CI/CD ou sur le poste du développeur. La valeur en clair transite quelque part, ce qui élargit la surface d&rsquo;attaque.</li>
<li>Contrairement à Sealed Secrets + un opérateur GitOps, SOPS seul ne met pas à jour les secrets dans le cluster automatiquement.</li>
</ul>
<p><em>C&rsquo;est l&rsquo;outil que j&rsquo;ai le plus utilisé dans un contexte professionnel, je trouve que c&rsquo;est un bon compromis pour gérer les secrets en GitOps à condition d&rsquo;accepter la complexité de gestion des clés et de mettre en place les bonnes pratiques pour éviter les erreurs humaines (ex: commit de secrets en clair) qui <code>spoiler</code> finiront par arriver</em></p>
<h3 id="sops--argocd">SOPS + ArgoCD</h3>
<p>Sops s&rsquo;intègre très bien avec ArgoCD via le plugin <a href="https://argocd-vault-plugin.readthedocs.io/en/stable/">argocd-vault-plugin</a>.</p>
<p>Sinon il est aussi possible d&rsquo;installer Helm Secrets comme <a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/config-management-plugins/">Config Management Plugin</a>.</p>
<h3 id="exemple-dutilisation">Exemple d&rsquo;utilisation</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Chiffrer un fichier de secrets</span>
</span></span><span class="line"><span class="cl">sops -e secrets.yaml &gt; secrets.enc.yaml
</span></span><span class="line"><span class="cl"><span class="c1"># Déchiffrer un fichier de secrets</span>
</span></span><span class="line"><span class="cl">sops -d secrets.enc.yaml &gt; secrets.yaml
</span></span><span class="line"><span class="cl"><span class="c1"># Mettre à jour les clés de chiffrement</span>
</span></span><span class="line"><span class="cl">sops updatekeys secrets.enc.yaml
</span></span><span class="line"><span class="cl"><span class="c1"># Editer un fichier de secrets chiffré</span>
</span></span><span class="line"><span class="cl">sops edit secrets.enc.yaml
</span></span></code></pre></div><hr>
<h2 id="les-alternatives-et-leurs-limites">Les alternatives et leurs limites</h2>
<h3 id="sealed-secrets--côté-cluster-clé-non-portable">Sealed Secrets : côté cluster, clé non portable</h3>
<p>Les Sealed Secrets(<a href="https://github.com/bitnami-labs/sealed-secrets">GitHub</a>) de Bitnami permettent de chiffrer les secrets côté cluster.</p>
<p>Sealed Secrets est composé en 2 parties:</p>
<ul>
<li>Un controlleur côté cluster (installable via <a href="https://bitnami-labs.github.io/sealed-secrets">Helm</a>)</li>
<li>Une CLI côté client : <a href="https://kubeseal.com/">kubeseal</a> (<code>brew install kubeseal</code>)</li>
</ul>
<p>kubeseal utilise une clé asymétrique pour chiffrer les secrets que seul le contrôleur peut déchiffrer.
Ces secrets chiffrés sont ensuite encodés dans une ressource SealedSecret.</p>
<p><strong>Limitations</strong></p>
<p>Voici selon moi les principales limitations de Sealed Secrets :</p>
<ul>
<li>La clé de chiffrement est stockée dans le cluster, ce qui rend les secrets non portables entre clusters.</li>
<li>En cas de compromission du cluster, les secrets peuvent être à risque.</li>
<li>En cas de disaster recovery, la restauration du cluster doit inclure la restauration de la clé de chiffrement pour pouvoir accéder aux secrets.</li>
<li>Les secrets sont uniquement utilisable dans un contexte Kubernetes, pas de possibilité de les utiliser pour d&rsquo;autres usages (CI/CD, etc).</li>
</ul>
<p><em>Je n&rsquo;ai pas eu l&rsquo;occasion d&rsquo;utiliser Sealed Secrets dans un milieu professionnel, mais j&rsquo;ai pu l&rsquo;expérimenter dans des projets personnels.</em></p>
<h3 id="vault--puissant-mais-lourd-à-opérer">Vault : puissant mais lourd à opérer</h3>
<p><a href="https://developer.hashicorp.com/vault">Hashicorp Vault</a> est un serveur centralisé de gestion de secrets. Ils sont stockés, chiffrés et distribués dynamiquement via une API et les applications les récupèrent au runtime.</p>
<p><strong>Limitations</strong></p>
<ul>
<li>Complexité opérationnelle élevée : Vault est un service à part entière qu&rsquo;il faut déployer, configurer, superviser et maintenir.</li>
<li>Single point of failure potentiel : Si Vault est down, toutes les applications qui récupèrent leurs secrets dynamiquement peuvent être impactées.</li>
<li>C&rsquo;est un outil (trop) complet : Les concepts sont nombreux et nécessitent un temps de montée en compétence réel avant d&rsquo;opérer Vault sereinement.</li>
</ul>
<p><em>C&rsquo;est un outil que j&rsquo;ai eu l&rsquo;occasion d&rsquo;utiliser mais je n&rsquo;ai jamais eu la &ldquo;chance&rdquo; de le déployer et l&rsquo;opérer moi même de A à Z, je ne me sens pas légitime pour en parler plus en détail dans cet article.</em></p>
<h2 id="a-retenir">A Retenir</h2>
<p>SOPS est un outil de chiffrement de secrets qui peut s&rsquo;intégrer dans une approche GitOps. Comme tout outil, il vient avec ses avantages et ses inconvénients, il est important de les connaître pour faire un choix éclairé en fonction de son contexte et de ses besoins.</p>
<p>Pour résumer très grossièrement préférez <code>Sealed Secrets</code> pour démarrer et les cas d&rsquo;usage simples, <code>SOPS</code> pour les cas d&rsquo;usage plus complexes et les équipes qui ont déjà une bonne maîtrise de la gestion de clés, et <code>Vault</code> pour les besoins les plus avancés et les équipes qui ont les ressources pour l&rsquo;opérer sereinement.</p>
<hr>
<p><strong>Sources</strong></p>
<ul>
<li><a href="https://github.com/getsops/sops">SOPS GitHub</a></li>
<li><a href="https://blog.stephane-robert.info/docs/conteneurs/orchestrateurs/outils/sealed-secrets/">Blog de Stéphane Robert - Sealed Secrets</a></li>
<li><a href="https://developer.hashicorp.com/vault/docs">Vault Documentation</a></li>
<li><a href="https://argocd-vault-plugin.readthedocs.io/en/stable/backends/#sops">ArgoCD Vault Plugin</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Cmctl - La CLI pour Cert Manager</title>
      <link>https://valerian-pyckaert.dev/posts/cmctl/</link>
      <pubDate>Thu, 04 Jun 2026 19:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/cmctl/</guid>
      <description>Mes commandes préférées pour interagir avec Cert Manager via cmctl.</description>
      <content:encoded><![CDATA[<h2 id="quest-ce-que-cest-">Qu&rsquo;est-ce que c&rsquo;est ?</h2>
<p>CMCTL est un outil en ligne de commande pour interagir avec Cert Manager. CMCTL permet de gérer les ressources Cert Manager, de diagnostiquer les problèmes et d&rsquo;automatiser certaines tâches liées à la gestion des certificats.
Puisque nous l&rsquo;avons installé dans le précédent article il me parassait intéressant de partager mes commandes préférées pour interagir avec Cert Manager via cmctl.</p>
<h2 id="installation">Installation</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install cert-manager/cert-manager/cmctl
</span></span></code></pre></div><p>Sinon pour Windows via scoop</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">scoop install main/cmctl
</span></span></code></pre></div><h2 id="utilisation">Utilisation</h2>
<h3 id="commandes-préférées">Commandes préférées</h3>
<p>Afficher les certificats gérés par Cert Manager :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl get certificates -A
</span></span></code></pre></div><p>Afficher les certificate requests en cours :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl get certificaterequest -A
</span></span></code></pre></div><p>Renouveler un certificat manuellement :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cmctl renew  &lt;nom-du-certificat&gt;
</span></span></code></pre></div><p>Approuver/Désapprouver une demande de certificat manuellement :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ cmctl approve -n istio-system mesh-ca --reason <span class="s2">&#34;pki-team&#34;</span> --message <span class="s2">&#34;this certificate is valid&#34;</span>
</span></span><span class="line"><span class="cl">Approved CertificateRequest <span class="s1">&#39;istio-system/mesh-ca&#39;</span>
</span></span><span class="line"><span class="cl">$ cmctl deny -n my-app my-app --reason <span class="s2">&#34;example.com&#34;</span> --message <span class="s2">&#34;violates policy&#34;</span>
</span></span><span class="line"><span class="cl">Denied CertificateRequest <span class="s1">&#39;my-app/my-app&#39;</span>
</span></span></code></pre></div><p>Inspecter un certificat en détail :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cmctl inspect &lt;nom-du-certificat&gt;
</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>C&rsquo;est un article volontairement cours pour partager cet outil et les commandes que j&rsquo;utilise le plus souvent pour manipuler les ressources de Cert Manager.</p>
<hr>
<p>Sources</p>
<ul>
<li><a href="https://cert-manager.io/docs/reference/cmctl/">https://cert-manager.io/docs/reference/cmctl/</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>The Forge Project</title>
      <link>https://valerian-pyckaert.dev/posts/the-forge-project/</link>
      <pubDate>Fri, 22 May 2026 08:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/the-forge-project/</guid>
      <description>Projet fil rouge : construire une plateforme Kubernetes complète sur GCP, from scratch, avec les outils indispensables en 2026. Chaque article documente une étape, les obstacles rencontrés et comment je les ai résolus.</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>Stack</strong> : GCP · GKE · Terraform · Helm · ArgoCD · SOPS · Kube-Prom-Stack · Nginx Gateway Fabric · cert-manager</p>
</blockquote>
<hr>
<h2 id="pourquoi-ce-projet-">Pourquoi ce projet ?</h2>
<p>Je me lance en freelance DevOps / Platform Engineer / Cloud Engineer. Pour montrer ce que je sais faire (et documenter ce que j&rsquo;apprends en chemin), je démarre un projet fil rouge public : construire une plateforme Kubernetes complète sur GCP, from scratch, avec les outils que j&rsquo;estime indispensables en 2026.</p>
<p>Chaque article de la série documente <strong>une étape</strong>, les <strong>obstacles rencontrés</strong> et comment je les ai résolus. Format court, orienté pratique.</p>
<p>Je vais tenter de garder une approche pragmatique orientée &ldquo;best practices&rdquo; (mais pas dogmatique) pour que ce soit utile à d&rsquo;autres personnes qui veulent se lancer dans la même aventure.</p>
<hr>
<h2 id="ce-quon-va-construire">Ce qu&rsquo;on va construire</h2>
<p>Un cluster GKE avec la stack suivante, déployée en GitOps :</p>
<table>
	<thead>
			<tr>
					<th>Composant</th>
					<th>Rôle</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>Terraform</strong></td>
					<td>Provisionning du cluster et bootstrap</td>
			</tr>
			<tr>
					<td><strong>Helm + ArgoCD</strong></td>
					<td>GitOps, tout passe par là après le bootstrap</td>
			</tr>
			<tr>
					<td><strong>SOPS</strong></td>
					<td>Gestion des secrets chiffrés dans Git</td>
			</tr>
			<tr>
					<td><strong>kube-prometheus-stack</strong></td>
					<td>Monitoring &amp; alerting (Prometheus, Grafana, Alertmanager)</td>
			</tr>
			<tr>
					<td><strong>Nginx Gateway Fabric</strong></td>
					<td>Ingress via la Gateway API</td>
			</tr>
			<tr>
					<td><strong>cert-manager + Let&rsquo;s Encrypt</strong></td>
					<td>TLS automatique</td>
			</tr>
	</tbody>
</table>
<p>Je me focalise sur ce qui me semble essentiel pour adresser la majorité des besoins.
A termes j&rsquo;envisage d&rsquo;ajouter d&rsquo;autres composants destinés à des usages plus complexes : KEDA, Karpenter, Dapr, &hellip;</p>
<hr>
<h2 id="les-étapes-prévues">Les étapes prévues</h2>
<ol>
<li><strong>Création du cluster GKE via Terraform</strong></li>
<li><strong>Bootstrap Helm &amp; ArgoCD via Terraform</strong></li>
<li><strong>Déploiement de kube-prometheus-stack</strong> via ArgoCD</li>
<li><strong>Déploiement de Nginx Gateway Fabric / Gateway API</strong> via ArgoCD</li>
<li><strong>Déploiement de cert-manager + Let&rsquo;s Encrypt</strong> via ArgoCD</li>
<li><strong>Mise en place de SOPS</strong> pour la gestion des secrets</li>
</ol>
<p><em>J&rsquo;ajouterai probablement d&rsquo;autres étapes au fur et à mesure</em>* (ex: gestion des node pools, autoscaling, etc.) selon les besoins et les obstacles rencontrés*</p>
<hr>
<h2 id="principes-de-base">Principes de base</h2>
<ul>
<li><strong>Tout dans Git</strong> — aucune modification manuelle sur le cluster après le bootstrap</li>
<li><strong>Least privilege</strong> — les SA GCP auront le minimum requis</li>
<li><strong>Les secrets ne sont jamais en clair</strong> dans le repo</li>
<li><strong>KISS</strong> — Keep It Simple Stupid. Pas de sur-optimisation, pas de microservices inutiles, pas de complexité superflue</li>
</ul>
<hr>
<h2 id="prochaine-étape">Prochaine étape</h2>
<p>→ <a href="#">Création du cluster GKE avec Terraform</a> <em>(à venir)</em></p>
]]></content:encoded>
    </item>
    <item>
      <title>Renovate</title>
      <link>https://valerian-pyckaert.dev/posts/renovate/</link>
      <pubDate>Fri, 15 May 2026 10:16:01 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/renovate/</guid>
      <description>Automatisation des mises à jour de dépendances avec Renovate</description>
      <content:encoded><![CDATA[<h2 id="quest-ce-que-cest-">Qu&rsquo;est-ce que c&rsquo;est ?</h2>
<p><a href="https://www.mend.io/renovate/">Renovate</a> est un outil d&rsquo;automatisation des mises à jour de dépendances. Il permet de garder les dépendances à jour en créant automatiquement des pull requests pour les nouvelles versions, les correctifs de sécurité et les mises à jour majeures.</p>
<p><strong>Exemple de PR avec Renovate</strong></p>
<p><img alt="Renovate PR" loading="lazy" src="/renovate-pr.png"></p>
<h2 id="comment-ça-fonctionne-">Comment ça fonctionne ?</h2>
<p>Renovate fonctionne en scannant à intervalles réguliers les dépôts Git pour détecter les mises à jour de dépendances. Lorsqu&rsquo;une mise à jour est disponible, il crée automatiquement une pull request avec les changements nécessaires, y compris un changelog et des notes de version.</p>
<p>Ensuite, la pull request peut être automatiquement fusionnée si les contrôles de CI sont verts, ou elle peut nécessiter une revue humaine avant d&rsquo;être fusionnée.</p>
<p>Parfois une image vaut milles mots, alors voici une illustration du workflow de Renovate :</p>
<pre class="mermaid">
  flowchart TD
    A([Planificateur cron]) --&gt; B[Scan du dépôt Git / Lecture des fichiers de config]
    B --&gt; C[Détection des mises à jour]
    C --&gt; D{Mises à jour disponibles ?}
    D -- Non --&gt; E[Aucune PR]
    D -- Oui --&gt; F[Création de la PR Branche + changelog]
    F --&gt; G[CI / Tests automatiques]
    G --&gt; H[Automerge]
    G -.ou.- I[Review humaine]
</pre>

<p><em>Ce schéma a été généré avec <a href="https://mermaid-js.github.io/mermaid/#/">Mermaid</a>. J&rsquo;en ferai certainement un article dédié dans le futur.</em></p>
<h2 id="un-changement-de-paradigme">Un changement de paradigme</h2>
<p>Dans le monde du développement logiciel, la gestion des dépendances est un défi constant. Les bibliothèques et les frameworks évoluent rapidement, et il est crucial de maintenir les dépendances à jour pour bénéficier des dernières fonctionnalités, des correctifs de sécurité et des améliorations de performance.</p>
<p>Autrefois (et encore aujourd&rsquo;hui dans de nombreux projets), la mise à jour des dépendances n&rsquo;est pas maitrisée et se fait de manière manuelle, souvent de manière ad-hoc. Cela peut entraîner des retards dans l&rsquo;adoption des nouvelles versions, des risques de sécurité et une dette technique croissante.</p>
<p>Renovate change complètement la donne en automatisant ce processus. Plutôt que de dépendre d&rsquo;une intervention humaine pour surveiller les mises à jour, Renovate prend en charge cette tâche de manière proactive. Il scanne régulièrement les dépôts, détecte les mises à jour disponibles et crée automatiquement des pull requests pour les intégrer.</p>
<h3 id="supply-chain-attacks">Supply chain attacks</h3>
<p>Ces derniers mois, nous avons vu une augmentation significative des attaques de la chaîne d&rsquo;approvisionnement (supply chain attacks). Ces attaques ciblent les dépendances utilisées par les projets, en injectant du code malveillant dans des librairies souvent méconnues mais utilisées par tous.</p>
<p><strong>En voici quelques unes :</strong></p>
<ul>
<li><a href="https://korben.info/backdoor-linux-faille-securite-critique-xz-utils.html">XZ Utils</a></li>
<li><a href="https://www.trendmicro.com/fr_fr/research/26/c/axios-npm-package-compromised.html">Axios</a></li>
<li><a href="https://www.trendmicro.com/en_us/research/26/e/analyzing-teampcp-supply-chain-attacks.html">Github Actions</a></li>
</ul>
<h3 id="la-fin-des-wildcards-pour-les-versions">La fin des wildcards pour les versions</h3>
<p>L&rsquo;un des avantages (ou inconvénients) majeurs de Renovate est qu&rsquo;il encourage une gestion plus rigoureuse des versions. Plutôt que d&rsquo;utiliser des wildcards (comme <code>^1.0.0</code> ou <code>~1.0.0</code>) qui peuvent introduire des changements inattendus, Renovate propose de spécifier des versions exactes pour les dépendances.</p>
<p>Cela permet de mieux contrôler les mises à jour et de réduire les risques liés à l&rsquo;introduction de changements non désirés.</p>
<h2 id="les-concurrents">Les concurrents</h2>
<h3 id="dependabot">Dependabot</h3>
<p><a href="https://github.com/dependabot/dependabot-core">Dependabot</a> est un outil similaire à Renovate qui propose également une automatisation des mises à jour de dépendances. Cependant, il est principalement intégré à GitHub et ne supporte pas autant de plateformes que Renovate. De plus, Renovate offre une plus grande flexibilité en termes de configuration et de personnalisation des règles de mise à jour.</p>
<p>C&rsquo;est toutefois un excellent choix pour les projets hébergés sur GitHub qui souhaitent une solution simple et intégrée, sans avoir à maintenir soit même un outil supplémentaire.</p>
<p><strong>Exemple d&rsquo;une pull request générée par Dependabot</strong></p>
<p><img alt="Dependabot PR" loading="lazy" src="/dependabot.png"></p>
<p><em>Vous remarquerez que le résultat est très similaire à celui de Renovate.</em></p>
<h2 id="le-mot-de-la-fin">Le mot de la fin</h2>
<p>Dans cet article, nous avons vu comment Renovate révolutionne la gestion des dépendances en automatisant les mises à jour et en encourageant une approche plus rigoureuse du versioning.
C&rsquo;est un maillon supplémentaire dans une chaîne de CI/CD qui permet à la fois de réduire les risques liés à l&rsquo;introduction de changements non désirés et de réduire la friction liée à la maintenance des dépendances.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Dependency Track - Déploiement en GitOps avec FluxCD</title>
      <link>https://valerian-pyckaert.dev/posts/dependency-track-flux/</link>
      <pubDate>Thu, 07 May 2026 08:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/dependency-track-flux/</guid>
      <description>Déploiement de Dependency Track en mode GitOps avec FluxCD.</description>
      <content:encoded><![CDATA[<p>Si vous ne savez pas ce qu&rsquo;est Dependency Track, je vous invite à lire mon article d&rsquo;introduction à Dependency Track <a href="https://www.valerian.dev/posts/dependency-track/">ici</a>.</p>
<h3 id="configuration">Configuration</h3>
<p>Les éléments à déployer sont très simples :</p>
<ul>
<li>Un namespace pour isoler les ressources de Dependency Track</li>
<li>Un HelmRepository pour indiquer à FluxCD où trouver les charts de Dependency Track</li>
<li>Un HelmRelease pour déployer Dependency Track avec les valeurs de configuration souhaitées</li>
</ul>
<p><em>dependency-track.yaml</em></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Namespace</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">source.toolkit.fluxcd.io/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">HelmRepository</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">interval</span><span class="p">:</span><span class="w"> </span><span class="l">1h</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="l">https://dependencytrack.github.io/helm-charts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">helm.toolkit.fluxcd.io/v2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">HelmRelease</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">interval</span><span class="p">:</span><span class="w"> </span><span class="l">1h</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">timeout</span><span class="p">:</span><span class="w"> </span><span class="l">15m</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">chart</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">chart</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0.44.0&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">sourceRef</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">HelmRepository</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">values</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">frontend</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">image</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">tag</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;4.14.1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">apiServer</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">image</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">tag</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;4.14.1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">persistentVolume</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">size</span><span class="p">:</span><span class="w"> </span><span class="l">20Gi</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">requests</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;500m&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l">1Gi</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">limits</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l">5Gi</span><span class="w">
</span></span></span></code></pre></div><p>On applique la configuration avec :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl apply -f dependency-track.yaml
</span></span></code></pre></div><h3 id="verification-de-linstallation">Verification de l&rsquo;installation</h3>
<p>On contrôle que l&rsquo;installation s&rsquo;est bien passée avec :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl get deployment -n dependency-track
</span></span><span class="line"><span class="cl"><span class="c1"># dependency-track-frontend   1/1     1            1           47h</span>
</span></span><span class="line"><span class="cl">kubectl get statefulset -n dependency-track
</span></span><span class="line"><span class="cl"><span class="c1"># dependency-track-api-server   1/1     47h</span>
</span></span></code></pre></div><h3 id="accès-au-service">Accès au service</h3>
<p>Puis on lance le port forward pour accéder au service :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl port-forward -n dependency-track svc/dependency-track-api-server 8080:8080
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Dans un autre terminal</span>
</span></span><span class="line"><span class="cl">kubectl port-forward -n dependency-track svc/dependency-track-frontend 8081:8080
</span></span></code></pre></div><p>Je vous laisse constater le <a href="http://localhost:8081">résultat</a> (login : admin / password : admin).</p>
<h4 id="problèmes-rencontrés">Problèmes rencontrés</h4>
<p><strong>Manque de droits pour FluxCD</strong></p>
<p>Mon FluxCD n&rsquo;avait pas les droits nécessaires pour créer des ressources dans le namespace <code>dependency-track</code> ce qui a conduit à des erreurs lors du déploiement.
J&rsquo;ai du spécifier les rbac suivantes :</p>
<p><em>rbac.yaml</em></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">rbac.authorization.k8s.io/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">ClusterRoleBinding</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">flux-pv-manager-dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">roleRef</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">apiGroup</span><span class="p">:</span><span class="w"> </span><span class="l">rbac.authorization.k8s.io</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">ClusterRole</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">flux-pv-manager</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">subjects</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">ServiceAccount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">flux-applier</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">rbac.authorization.k8s.io/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Role</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">helm-release-manager</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">rules</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">apiGroups</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">resources</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;secrets&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">verbs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;get&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;list&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;create&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;update&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;patch&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;delete&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">apiGroups</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">resources</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;configmaps&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">verbs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;get&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;list&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;create&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;update&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;patch&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;delete&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">apiGroups</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">resources</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;services&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;serviceaccounts&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;pods&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;persistentvolumeclaims&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">verbs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;get&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;list&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;create&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;update&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;patch&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;delete&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">apiGroups</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;apps&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">resources</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;deployments&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;statefulsets&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;replicasets&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">verbs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;get&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;list&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;create&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;update&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;patch&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;delete&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">apiGroups</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;networking.k8s.io&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">resources</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;ingresses&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">verbs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;get&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;list&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;create&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;update&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;patch&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;delete&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">apiGroups</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;rbac.authorization.k8s.io&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">resources</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;roles&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;rolebindings&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">verbs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;get&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;list&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;create&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;update&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;patch&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;delete&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">rbac.authorization.k8s.io/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">RoleBinding</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">flux-helm-release-manager</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">roleRef</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">apiGroup</span><span class="p">:</span><span class="w"> </span><span class="l">rbac.authorization.k8s.io</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Role</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">helm-release-manager</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">subjects</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">ServiceAccount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">flux-applier</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span></code></pre></div><h4 id="manque-de-ressource">Manque de ressource</h4>
<p>J&rsquo;ai toujours pour réflexe lorsque je déploie une outil de jeter un oeil aux ressources nécessaires pour le faire tourner.
<a href="https://github.com/DependencyTrack/helm-charts/blob/main/charts/dependency-track/values.yaml#L41">La chart officielle de Dependency Track réclame 2 CPU et 5Gi de RAM</a> pour l&rsquo;api server ce qui me semblait énorme pour mon petit cluster.</p>
<p>J&rsquo;ai donc commencé par réduire les ressources demandées à 500m de CPU et 1Gi de RAM pour les tests, mais cela a conduit à des lenteurs extrêmes et des timeouts dans les logs de l&rsquo;api server.</p>
<p>La solution, laisser la configuration RAM par défaut (5Go requested), 500m de cpu suffise par contre pour un petit cluster de test.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">      </span><span class="nt">resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">requests</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;500m&#34;</span><span class="w">
</span></span></span></code></pre></div><h2 id="le-mot-de-la-fin">Le mot de la fin</h2>
<p>Pour aller plus loin vous pouvez configurer un ingress(déprécié) ou httpRoute pour accéder à l&rsquo;interface de Dependency Track sans passer par un port forward, ou encore configurer une base de données externe pour la persistance des données.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Dependency Track - Déploiement en GitOps avec ArgoCD</title>
      <link>https://valerian-pyckaert.dev/posts/dependency-track-argo/</link>
      <pubDate>Wed, 06 May 2026 08:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/dependency-track-argo/</guid>
      <description>Déploiement de Dependency Track en mode GitOps avec ArgoCD.</description>
      <content:encoded><![CDATA[<p>Si vous ne savez pas ce qu&rsquo;est Dependency Track, je vous invite à lire mon article d&rsquo;introduction à Dependency Track <a href="https://www.valerian.dev/posts/dependency-track/">ici</a>.</p>
<h3 id="prerequis">Prerequis</h3>
<ul>
<li>Un cluster Kubernetes fonctionnel (Cloud (AWS, GCP, Azure) ou local (Kind, Minikube, K3s)</li>
<li>Helm installé et configuré</li>
<li>Une instance ArgoCD pour le déploiement en GitOps</li>
</ul>
<h3 id="pattern-app-of-apps">Pattern App of Apps</h3>
<p>Le pattern App of Apps consiste à créer une application principale (appelée &ldquo;App of Apps&rdquo;) qui référence d&rsquo;autres applications (appelées &ldquo;child apps&rdquo;).
Cela permet de regrouper plusieurs applications sous une même hiérarchie et de les gérer de manière centralisée.</p>
<h4 id="architecture-dun-repo-gitops-avec-app-of-apps">Architecture d&rsquo;un repo GitOps avec App of Apps</h4>
<pre tabindex="0"><code class="language-root/" data-lang="root/">├── apps/
│   ├── monapp.yaml (Ici dependency-track dans notre cas)
├── root-app.yaml/
</code></pre><p>Dans cet exemple, <code>root-app.yaml</code> est l&rsquo;application principale (App of Apps) qui référence <code>monapp.yaml</code> (child app) qui contient la configuration pour déployer Dependency Track.</p>
<p>Si je souhaite déployer d&rsquo;autres applications je n&rsquo;ai qu&rsquo;à créer une nouvelle ressource <em>Application</em> dans le dossier <code>apps/</code>.</p>
<h3 id="configuration">Configuration</h3>
<p>Mon fichier root-app.yaml :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">argoproj.io/v1alpha1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Application</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">root-app</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">argocd</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">project</span><span class="p">:</span><span class="w"> </span><span class="l">default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">repoURL</span><span class="p">:</span><span class="w"> </span><span class="l">https://github.com/votre-user/votre-repo</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targetRevision</span><span class="p">:</span><span class="w"> </span><span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">apps         </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">destination</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">server</span><span class="p">:</span><span class="w"> </span><span class="l">https://kubernetes.default.svc</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">argocd   </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">syncPolicy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">automated</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">prune</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">selfHeal</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div><p>Mon dependency-track.yaml (apps/dependency-track.yaml) :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">argoproj.io/v1alpha1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Application</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">argocd</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">project</span><span class="p">:</span><span class="w"> </span><span class="l">default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">repoURL</span><span class="p">:</span><span class="w"> </span><span class="l">https://github.com/votre-user/votre-repo</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targetRevision</span><span class="p">:</span><span class="w"> </span><span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">helm</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">valueFiles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="l">values.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">destination</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">server</span><span class="p">:</span><span class="w"> </span><span class="l">https://kubernetes.default.svc</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">dependency-track</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">syncPolicy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">automated</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">prune</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">selfHeal</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">syncOptions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">CreateNamespace=true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">ServerSideApply=true</span><span class="w">
</span></span></span></code></pre></div><p>On applique la configuration avec (seule étape manuelle):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl apply -f root-app.yaml
</span></span></code></pre></div><p>A ce stade vous devriez voir la chart se déployer dans ArgoCD et après quelques minutes l&rsquo;application devrait être en état &ldquo;Healthy&rdquo; et &ldquo;Synced&rdquo;.</p>
<p>Pour y accéder, vous pouvez faire un port forward sur le service frontend ou api server comme vu dans la section FluxCD.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl port-forward -n dependency-track svc/dependency-track-api-server 8080:8080
</span></span><span class="line"><span class="cl"><span class="c1"># Dans un autre terminal</span>
</span></span><span class="line"><span class="cl">kubectl port-forward -n dependency-track svc/dependency-track-frontend 8081:8080
</span></span></code></pre></div><p>Et voilà le <a href="http://localhost:8081">résultat</a> (login : admin / password : admin).
<img alt="Page de login dependency track" loading="lazy" src="/dependency-track-dashboard.png"></p>
]]></content:encoded>
    </item>
    <item>
      <title>Dependency Track - Monitorer les vulnérabilités de vos applications</title>
      <link>https://valerian-pyckaert.dev/posts/dependency-track/</link>
      <pubDate>Tue, 05 May 2026 08:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/dependency-track/</guid>
      <description>Monitorer les vulnérabilités de vos applications avec Dependency Track.</description>
      <content:encoded><![CDATA[<p>Voici la première partie d&rsquo;une série d&rsquo;articles dédiés à <a href="https://dependencytrack.org/">Dependency Track</a> et à son déploiement en mode GitOps avec ArgoCD ou FluxCD sur un cluster Kubernetes.</p>
<h2 id="quest-ce-que-cest-">Qu&rsquo;est ce que c&rsquo;est ?</h2>
<p>C&rsquo;est une plateforme qui permet de suivre les composants logiciels utilisés dans nos applications, d&rsquo;identifier les vulnérabilités associées et de gérer les risques liés à ces dépendances.</p>
<p>C&rsquo;est un outil particulièrement utile pour répondre aux exigences de sécurité et de conformité de nos systèmes comme le <a href="https://cyber.gouv.fr/reglementation/cybersecurite-des-produits/cyber-resilience-act/">Cyber Resilience Act</a> (CRA) en Europe ou l&rsquo;<a href="https://www.iso.org/fr/standard/76097.html">IEC 81001-5-1</a> pour les dispositifs médicaux.</p>
<h2 id="comment-ça-fonctionne-">Comment ça fonctionne ?</h2>
<pre class="mermaid">
  flowchart LR
    subgraph Sources[&#34;Sources SBOM&#34;]
        CI[CI/CD Pipeline]
        CLI[cdxgen / syft]
    end

    subgraph DT[&#34;Dependency-Track&#34;]
        API[API Server]
        ANA[Analyzers]
        DB[(Base de données\nH2 / PostgreSQL)]

        API --&gt;|stocke| DB
        API --&gt;|déclenche| ANA
    end

    subgraph Vuln[&#34;Bases de vulnérabilités&#34;]
        NVD[NVD]
        OSV[OSV]
        GHSA[GitHub Advisory]
        OSS[OSS Index]
    end

    subgraph Alerting[&#34;Alerting&#34;]
        NOTIF[Notifications]
        POLICY[Policy Violations]
    end

    CI --&gt;|POST /api/v1/bom| API
    CLI --&gt;|POST /api/v1/bom| API

    ANA &lt;--&gt;|sync CVEs| NVD
    ANA &lt;--&gt;|sync CVEs| OSV
    ANA &lt;--&gt;|sync CVEs| GHSA
    ANA &lt;--&gt;|sync CVEs| OSS

    ANA --&gt;|vulnérabilités détectées| NOTIF
    ANA --&gt;|violation de politique| POLICY
</pre>

<p>Dependency Track ingère des SBOM et analyse en continu les composants logiciels pour détecter les vulnérabilités connues. Il s&rsquo;appuie sur des bases de données de vulnérabilités telles que le <a href="https://nvd.nist.gov/">NVD (National Vulnerability Database)</a> pour fournir des informations à jour sur les risques liés aux composants logiciels.</p>
<h3 id="la-sbom">La SBOM</h3>
<p>Une SBOM (Software Bill of Materials) est un fichier qui liste tous les composants logiciels utilisés dans un projet, y compris leurs versions et leurs dépendances. C&rsquo;est un peu comme une liste d&rsquo;ingrédients pour une recette de cuisine, mais pour les logiciels.</p>
<p>J&rsquo;y ai dédié un article complet que vous pouvez consulter <a href="https://valerianpyckaert.com/posts/sbom/">ici</a>.</p>
<h2 id="pourquoi-cest-important-">Pourquoi c&rsquo;est important ?</h2>
<p>Dans un monde où les applications sont de plus en plus complexes et dépendent de nombreux composants tiers, il est crucial de pouvoir identifier rapidement les vulnérabilités potentielles pour protéger nos systèmes et nos données.
Le contexte géopolitique actuel accentue encore plus l&rsquo;importance de la sécurité des logiciels, avec des attaques de plus en plus sophistiquées comme plus récemment celles sur la supply chain.</p>
<p>Quelques sources sur le sujet :</p>
<ul>
<li>Trivy supply chain attack: <a href="https://www.paloaltonetworks.com/blog/cloud-security/trivy-supply-chain-attack/">https://www.paloaltonetworks.com/blog/cloud-security/trivy-supply-chain-attack/</a></li>
<li>Checkmarx security update: <a href="https://checkmarx.com/blog/checkmarx-security-update/">https://checkmarx.com/blog/checkmarx-security-update/</a></li>
<li>Axios NPM package compromised: <a href="https://www.trendmicro.com/fr_fr/research/26/c/axios-npm-package-compromised.html">https://www.trendmicro.com/fr_fr/research/26/c/axios-npm-package-compromised.html</a></li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Maintenant que vous savez ce qu&rsquo;est une SBOM, Dependency track et l&rsquo;importance de ce type d&rsquo;outil nous verrons dans les prochains articles comment déployer Dependency Track en mode GitOps sur Kubernetes avec ArgoCD ou FluxCD, et comment l&rsquo;intégrer dans une pipeline CI/CD pour automatiser la gestion des vulnérabilités de vos applications.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Grype</title>
      <link>https://valerian-pyckaert.dev/posts/grype/</link>
      <pubDate>Fri, 01 May 2026 08:00:00 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/grype/</guid>
      <description>Grype est un outil de scan de vulnérabilités à partir de SBOM.</description>
      <content:encoded><![CDATA[<h2 id="préambule">Préambule</h2>
<p>Si vous ne savez pas ce qu&rsquo;est une SBOM (Software Bill of Materials), je vous invite à lire mon article sur <a href="https://www.valerian.dev/posts/sbom/">SBOM</a>.</p>
<h2 id="grype---quest-ce-que-cest-">Grype - Qu&rsquo;est-ce que c&rsquo;est ?</h2>
<p>Dans l&rsquo;article précédant je vous ai présenté <a href="https://github.com/anchore/syft">Syft</a> pour générer ces fameuses SBOM, <a href="https://github.com/anchore/grype">Grype</a> est un outil complémentaire et développé par la même équipe, qui permet de scanner ces SBOM à la recherche de vulnérabilités connues.
Il est notamment utile dans une chaine de CI/CD pour automatiser la détection de vulnérabilités dans les dépendances utilisées par votre projet.</p>
<h2 id="en-local">En Local</h2>
<h3 id="installation">Installation</h3>
<p>Là encore les étapes ressemblent beaucoup à l&rsquo;installation de Syft.</p>
<p>Sur Linux ou macOS, vous pouvez installer Syft en utilisant Homebrew :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew tap anchore/grype
</span></span><span class="line"><span class="cl">brew install grype
</span></span></code></pre></div><p>ou via curl :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -sSfL https://get.anchore.io/grype <span class="p">|</span> sudo sh -s -- -b /usr/local/bin
</span></span></code></pre></div><p>Sur Windows j&rsquo;aime utiliser Scoop :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">scoop bucket add main
</span></span><span class="line"><span class="cl">scoop install grype
</span></span></code></pre></div><p>Un petit coup de <code>grype version</code> pour vérifier que tout est bien installé et c&rsquo;est parti !</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Application:         grype
</span></span><span class="line"><span class="cl">Version:             0.111.1
</span></span><span class="line"><span class="cl">BuildDate:           2026-04-22T17:16:07Z
</span></span><span class="line"><span class="cl">GitCommit:           89819276e8ebf63b4f607ca3a1b0faa3fc75f28d
</span></span><span class="line"><span class="cl">GitDescription:      v0.111.1
</span></span><span class="line"><span class="cl">Platform:            windows/amd64
</span></span><span class="line"><span class="cl">GoVersion:           go1.26.2
</span></span><span class="line"><span class="cl">Compiler:            gc
</span></span><span class="line"><span class="cl">Syft Version:        v1.43.0
</span></span><span class="line"><span class="cl">Supported DB Schema: <span class="m">6</span>
</span></span></code></pre></div><h3 id="utilisation">Utilisation</h3>
<p>Le cas simple à partir d&rsquo;une image docker :</p>
<p>Le résultat :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">grype alpine:latest
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> ✔ Vulnerability DB                <span class="o">[</span>updated<span class="o">]</span>  
</span></span><span class="line"><span class="cl"> ✔ Parsed image                                                                                                                                         sha256:3cb067eab609612d81b4d82ff8ad71d73482bb3059a87b642d7e14f0ed659cde 
</span></span><span class="line"><span class="cl"> ✔ Cataloged contents                                                                                                                                          4d889c14e7d5a73929ab00be2ef8ff22437e7cbc545931e52554a7b00e123d8b 
</span></span><span class="line"><span class="cl">   ├── ✔ Packages                        <span class="o">[</span><span class="m">16</span> packages<span class="o">]</span>  
</span></span><span class="line"><span class="cl">   ├── ✔ File metadata                   <span class="o">[</span><span class="m">79</span> locations<span class="o">]</span>  
</span></span><span class="line"><span class="cl">   ├── ✔ Executables                     <span class="o">[</span><span class="m">17</span> executables<span class="o">]</span>  
</span></span><span class="line"><span class="cl">   └── ✔ File digests                    <span class="o">[</span><span class="m">79</span> files<span class="o">]</span>  
</span></span><span class="line"><span class="cl"> ✔ Scanned <span class="k">for</span> vulnerabilities     <span class="o">[</span><span class="m">3</span> vulnerability matches<span class="o">]</span>  
</span></span><span class="line"><span class="cl">   ├── by severity: <span class="m">0</span> critical, <span class="m">0</span> high, <span class="m">3</span> medium, <span class="m">0</span> low, <span class="m">0</span> negligible
</span></span><span class="line"><span class="cl">   └── by status:   <span class="m">0</span> fixed, <span class="m">3</span> not-fixed, <span class="m">0</span> ignored 
</span></span><span class="line"><span class="cl">NAME           INSTALLED   TYPE  VULNERABILITY   SEVERITY  EPSS           RISK   
</span></span><span class="line"><span class="cl">busybox        1.37.0-r30  apk   CVE-2025-60876  Medium    &lt; 0.1% <span class="o">(</span>15th<span class="o">)</span>  &lt; 0.1  
</span></span><span class="line"><span class="cl">busybox-binsh  1.37.0-r30  apk   CVE-2025-60876  Medium    &lt; 0.1% <span class="o">(</span>15th<span class="o">)</span>  &lt; 0.1  
</span></span><span class="line"><span class="cl">ssl_client     1.37.0-r30  apk   CVE-2025-60876  Medium    &lt; 0.1% <span class="o">(</span>15th<span class="o">)</span>  &lt; 0.1
</span></span></code></pre></div><p>Et pour une analyse encore plus rapide, vous pouvez directement scanner une SBOM générée par Syft :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">syft alpine:latest -o cyclonedx-json &gt; sbom.json <span class="c1"># génère une SBOM pour l&#39;image alpine:latest</span>
</span></span><span class="line"><span class="cl">grype sbom:./sbom.json <span class="c1"># scanne la SBOM à la recherche de vulnérabilités²</span>
</span></span></code></pre></div><h2 id="en-ci-github-actions">En CI (GitHub Actions)</h2>
<p>Savoir détecté les vulnérabilités en local c&rsquo;est bien mais automatiser leurs détection dans une pipeline CI/CD c&rsquo;est encore mieux !
On applique ainsi les bonnes pratiques DevOps : détecter tôt les problèmes lors du cycle de développement, corriger vite et avant déploiement en production.</p>
<p>Voici un exemple de workflow GitHub Actions qui utilise Grype pour scanner une image Docker à la recherche de vulnérabilités et échoue si une vulnérabilité critique est détectée.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build, SBOM and Grype scan</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">workflow_dispatch</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">build-scan</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build image, generate SBOM and scan with Grype</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">permissions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">contents</span><span class="p">:</span><span class="w"> </span><span class="l">read</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">env</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">IMAGE_NAME</span><span class="p">:</span><span class="w"> </span><span class="l">demo-node-app</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">IMAGE_TAG</span><span class="p">:</span><span class="w"> </span><span class="l">${{ github.sha }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Checkout repository</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Set up Docker Buildx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">docker/setup-buildx-action@v4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build Node.js Docker image (load locally)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">docker/build-push-action@v7</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">context</span><span class="p">:</span><span class="w"> </span><span class="l">.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">file</span><span class="p">:</span><span class="w"> </span><span class="l">./Dockerfile</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">push</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">load</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">tags</span><span class="p">:</span><span class="w"> </span><span class="l">${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Generate SBOM with Syft (SPDX JSON)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">anchore/sbom-action@v0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="l">spdx-json</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">output-file</span><span class="p">:</span><span class="w"> </span><span class="l">sbom.spdx.json</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">upload-artifact</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Upload SBOM artifact</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/upload-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">sbom</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">sbom.spdx.json</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">if-no-files-found</span><span class="p">:</span><span class="w"> </span><span class="l">error</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Scan SBOM with Grype (fail on critical)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">id</span><span class="p">:</span><span class="w"> </span><span class="l">grype</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">anchore/scan-action@v7</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">sbom</span><span class="p">:</span><span class="w"> </span><span class="l">sbom.spdx.json</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">fail-build</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">severity-cutoff</span><span class="p">:</span><span class="w"> </span><span class="l">critical</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">output-format</span><span class="p">:</span><span class="w"> </span><span class="l">sarif</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">output-file</span><span class="p">:</span><span class="w"> </span><span class="l">grype-report.sarif</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Upload Grype report artifact</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">always()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/upload-artifact@v7</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">grype-report</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">grype-report.sarif</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">if-no-files-found</span><span class="p">:</span><span class="w"> </span><span class="l">error</span><span class="w">
</span></span></span></code></pre></div><p>Vous pouvez retrouver un exemple fonctionnel sur mon <a href="https://github.com/Bernedotcom2312/grype">GitHub</a>.</p>
<p>Il est également possible d&rsquo;arriver au même résultat en jouant les commandes présentées ci dessous mais Anchore propose des actions GitHub pré-construites pour faciliter l&rsquo;intégration de Syft et Grype dans vos workflows CI/CD.
Encore une fois autant privilégier la facilité et éviter de réinventer la roue.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Grype est un outil à la fois simple et puissant pour analyser vos SBOM à la recherche de vulnérabilités.
Il s&rsquo;intègre facilement en CI et peut même être configuré en tant que commit hook pour scanner vos images ou votre code avant même de pousser vos changements, réduisant ainsi la boucle de feedback.</p>
<p><strong>Sources</strong></p>
<ul>
<li><a href="https://github.com/anchore/grype">Grype GitHub Repository</a></li>
<li><a href="https://oss.anchore.com/docs/guides/vulnerability/getting-started/">Grype Documentation</a></li>
<li><a href="https://github.com/anchore/scan-action">Anchore GitHub Actions</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>SBOM (Software Bill of Materials)</title>
      <link>https://valerian-pyckaert.dev/posts/sbom/</link>
      <pubDate>Thu, 30 Apr 2026 10:29:03 +0200</pubDate>
      <guid>https://valerian-pyckaert.dev/posts/sbom/</guid>
      <description>Description, outils et utilisation</description>
      <content:encoded><![CDATA[<h2 id="quest-ce-que-cest-">Qu&rsquo;est-ce que c&rsquo;est ?</h2>
<p>Une SBOM (Software Bill of Materials) est un fichier qui liste tous les composants logiciels utilisés dans un projet, y compris leurs versions et leurs dépendances. C&rsquo;est un peu comme une liste d&rsquo;ingrédients pour une recette de cuisine, mais pour les logiciels.</p>
<p>Elles peuvent exister sous plusieurs formats notamment pour les plus connus : <a href="https://cyclonedx.org/">CycloneDX</a>, <a href="https://spdx.org/">SPDX</a>.</p>
<h2 id="les-différents-formats">Les différents formats</h2>
<h3 id="cyclonedx">CycloneDX</h3>
<p>CycloneDX est un format de SBOM conçu pour être facile à lire et à analyser. Il utilise une structure hiérarchique pour représenter les composants logiciels et leurs dépendances, ce qui facilite la compréhension des relations entre les différents éléments d&rsquo;un projet.
Il est notamment développé par la fondation OWASP et est largement utilisé dans l&rsquo;industrie pour la gestion des vulnérabilités et la conformité.</p>
<h3 id="spdx">SPDX</h3>
<p>SPDX (Software Package Data Exchange) quant à lui est un format développé par la Linux Foundation. Il est conçu pour être un standard ouvert et largement adopté pour la représentation des informations sur les composants logiciels, y compris les licences, les vulnérabilités et les dépendances.</p>
<p>Exemple d&rsquo;une SBOM au format SPDX :</p>
<h3 id="lequel-choisir-">Lequel choisir ?</h3>
<p>Le choix entre SPDX et CycloneDX dépend de vos besoins spécifiques en matière de gestion des composants logiciels. Si vous recherchez un format facile à lire et à analyser, CycloneDX peut être un bon choix. Si vous avez besoin d&rsquo;un format plus complet qui inclut des informations sur les licences et les vulnérabilités, SPDX pourrait être plus adapté.</p>
<p>Voici un tableau récapitulatif pour vous aider à choisir :</p>
<table>
	<thead>
			<tr>
					<th>Caractéristique</th>
					<th>SPDX</th>
					<th>CycloneDX</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Facilité de lecture</td>
					<td>Moins lisible pour les humains ❌</td>
					<td>Plus lisible ✅</td>
			</tr>
			<tr>
					<td>Analyse automatisée</td>
					<td>Plus adapté pour l&rsquo;analyse</td>
					<td>Adapté pour l&rsquo;analyse</td>
			</tr>
			<tr>
					<td>Adoption</td>
					<td>Large adoption dans l&rsquo;industrie</td>
					<td>Adoption croissante</td>
			</tr>
			<tr>
					<td>Support des licences</td>
					<td>Oui ✅</td>
					<td>Non ❌</td>
			</tr>
			<tr>
					<td>Support des vulnérabilités</td>
					<td>Oui ✅</td>
					<td>Non ❌</td>
			</tr>
	</tbody>
</table>
<h2 id="comment-la-générer-">Comment la générer ?</h2>
<p>Un de mes outils préférés pour générer des SBOM est <a href="https://github.com/anchore/syft">Syft</a>, développé par Anchore. Syft est un outil en ligne de commande qui peut analyser les images de conteneurs, les systèmes de fichiers et les projets de code source pour générer des SBOM au format CycloneDX ou SPDX.</p>
<p>Il supporte une multitude de langages et de gestionnaires de paquets.</p>
<p>Les autres standards du marché sont <a href="https://github.com/CycloneDX/cdxgen">cdxgen</a> et <a href="https://trivy.dev/">trivy</a>, ce dernier ayant été impacté par une faille de sécurité récemment, je préfère ne pas l&rsquo;utiliser pour le moment (cf. <a href="https://blog.stephane-robert.info/post/trivy-depot-github-vide/">l&rsquo;excellent article de Stéphane Robert</a> à ce sujet).</p>
<h3 id="installation">Installation</h3>
<p>Sur Linux ou macOS, vous pouvez installer Syft en utilisant Homebrew :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install anchore/syft/syft
</span></span></code></pre></div><p>ou via curl :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh <span class="p">|</span> sh -s -- -b /usr/local/bin
</span></span></code></pre></div><p>Sur Windows j&rsquo;aime utiliser Scoop :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">scoop bucket add main
</span></span><span class="line"><span class="cl">scoop install syft
</span></span></code></pre></div><p>Un petit coup de <code>syft version</code> pour vérifier que tout est bien installé et c&rsquo;est parti !</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">syft version
</span></span><span class="line"><span class="cl">Application:   syft
</span></span><span class="line"><span class="cl">Version:       1.38.0
</span></span><span class="line"><span class="cl">BuildDate:     2025-11-17T17:42:49Z
</span></span><span class="line"><span class="cl">GitCommit:     a033ae525f6c7ef937c6f49513e3403f07a1d6c0
</span></span><span class="line"><span class="cl">GitDescription: v1.38.0
</span></span><span class="line"><span class="cl">Platform:      windows/amd64
</span></span><span class="line"><span class="cl">GoVersion:     go1.25.4
</span></span><span class="line"><span class="cl">Compiler:      gc
</span></span><span class="line"><span class="cl">SchemaVersion: 16.1.0
</span></span></code></pre></div><h3 id="utilisation">Utilisation</h3>
<p><strong>Voici comment générer une SBOM pour une image Docker</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Le plus simple pour commencer est de s<span class="err">&#39;</span>appuyer sur une image docker standard comme alpine.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sb">```</span>bash
</span></span><span class="line"><span class="cl">syft alpine:latest -o cyclonedx-json &gt; sbom.json
</span></span></code></pre></div><p><em>Ici la commande pull alpine:latest et génère une SBOM au format CycloneDX en JSON, qui est ensuite redirigée vers un fichier sbom.json.</em></p>
<p><strong>Voici comment générer une SBOM pour un projet de code source</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">syft dir:/path/to/your/project -o cyclonedx-json &gt; sbom.json
</span></span></code></pre></div><p>ou pour cibler sur un fichier en particulier :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">syft file:/path/to/your/project/package.json -o cyclonedx-json &gt; sbom.json <span class="c1"># pour un projet Node.js</span>
</span></span><span class="line"><span class="cl">syft file:/path/to/your/project/pyproject.toml -o cyclonedx-json &gt; sbom.json <span class="c1"># pour un projet Python</span>
</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>La SBOM est un outil essentiel pour la gestion des composants logiciels et la sécurité des applications. En fournissant une vue d&rsquo;ensemble claire de tous les composants utilisés dans un projet, elle permet aux équipes de développement et de sécurité de mieux comprendre les risques associés à leurs logiciels et de prendre des mesures proactives pour les atténuer.</p>
<p>Cette SBOM peut ensuite être intégrée dans votre pipeline CI/CD et analysée avec des outils comme Dependency Track pour détecter les vulnérabilités connues et assurer la conformité de vos logiciels.</p>
<p><em>Sources</em></p>
<ul>
<li><a href="https://owasp.org/www-project-cyclonedx/">SBOM - OWASP</a></li>
<li><a href="https://www.nist.gov/itl/sbom">SBOM - NIST</a></li>
<li><a href="https://spdx.dev/">SBOM - SPDX</a></li>
<li><a href="https://github.com/anchore/syft">Syft - Anchore</a></li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>
