Aller au contenu

SBOM : comprendre le Software Bill of Materials

Mise à jour :

« Est-ce qu’on utilise ce composant ? » — Combien de fois ai-je entendu cette question en urgence, après l’annonce d’une CVE critique ? À chaque incident supply chain, c’est la même course : fouiller les package.json, les requirements.txt, les images Docker… sans jamais être certain d’avoir tout couvert.

Le SBOM (Software Bill of Materials) répond à ce problème. C’est un inventaire exhaustif et machine-readable de tout ce qui compose un logiciel : bibliothèques, paquets OS, dépendances transitives, versions, licences. En clair : si on ne sait pas ce qu’on exécute, on ne peut ni corriger vite, ni prouver ce qu’on livre.

Dans ce guide, je montre concrètement :

  • C’est quoi un SBOM ?
  • Comment générer un SBOM avec Syft (Anchore)
  • Comment l’exploiter pour détecter des vulnérabilités avec Grype, Trivy, Dependency Track
  • Comment le distribuer (fichier, artefact CI, attestation OCI signée)
  • Comment l’intégrer en CI/CD pour automatiser tout ça

C’est quoi un SBOM, exactement ?

Un SBOM, c’est un document qui décrit :

  • Les composants (nom, version, fournisseur/éditeur quand possible)
  • Des identifiants stables (ex. purl, parfois CPE)
  • Les relations (dépendances directes/transitives)
  • Des métadonnées utiles (licences, hashes, emplacements, type de composant…)

L’objectif n’est pas « faire un fichier pour la conformité ». L’objectif est d’avoir un SBOM actionnable : chercher, corréler, prouver, automatiser.

Ce que le SBOM n’est pas

  • Ce n’est pas un scan de vulnérabilités.
  • Ce n’est pas une preuve d’intégrité (ça, c’est la signature/attestation).
  • Ce n’est pas une garantie d’exploitabilité (ça, c’est plutôt le rôle d’un VEX).

Pourquoi le SBOM devient incontournable ?

Le problème : réagir à l’aveugle

Quand une CVE critique tombe (Log4Shell, XZ Utils, Polyfill.io…), la première question est toujours la même : « Est-ce qu’on est impactés ? ». Sans inventaire centralisé, on doit :

  • fouiller manuellement chaque package.json, requirements.txt, go.mod
  • scanner toutes mes images Docker une par une
  • interroger chaque équipe pour savoir ce qu’elle utilise
  • espérer n’avoir rien oublié

Résultat : des heures (voire des jours) perdues à chercher, pendant que la vulnérabilité reste exploitable.

Les attaques supply chain : le contexte

Une attaque supply chain cible la chaîne d’approvisionnement logicielle : dépendances, outils de build, registres de paquets, pipelines CI/CD. L’attaquant comprommet un composant en amont pour toucher tous les projets qui en dépendent.

Pour comprendre les vecteurs d’attaque et les exemples récents (XZ Utils, Polyfill.io, tj-actions…), consulte mon guide complet sur la sécurité de la supply chain.

Le point commun de ces incidents : sans inventaire fiable, on passe son temps à répondre à « est-ce qu’on est touchés ? » au lieu de corriger.

La réponse : un inventaire interrogeable

Avec un SBOM par artefact, on peut en quelques secondes :

Terminal window
# Rechercher un composant vulnérable dans tous mes SBOM
grep -l "xz-utils" *.sbom.json

Le SBOM transforme donc une question floue (« on utilise quoi ? ») en une requête précise sur des données structurées.

Formats standardisés : SPDX ou CycloneDX ?

Deux formats dominent l’écosystème SBOM. Chacun a son histoire, ses forces et son écosystème d’outils. Comprendre leurs différences permet de choisir le bon format selon le contexte.

CycloneDX (OWASP)

CycloneDX est un standard développé par l’OWASP (Open Web Application Security Project), conçu dès le départ pour la sécurité applicative et la supply chain logicielle.

Versions et évolution :

  • CycloneDX 1.4 (2022) : ajout du support VEX (Vulnerability Exploitability eXchange) pour qualifier l’exploitabilité des vulnérabilités
  • CycloneDX 1.5 (2023) : support des attestations de formulation (build environment, sources, configurations)
  • CycloneDX 1.6 (2024) : amélioration du support cryptographique (CBOM) et des services (SaaSBOM)

Points forts :

  • Orienté sécurité : intégration native de VEX, hashes, signatures
  • Écosystème DevSecOps : support natif dans Trivy, Grype, Dependency Track, Snyk, GitHub
  • Léger et pragmatique : schéma JSON/XML simple, facile à parser
  • Évolution rapide : nouvelles fonctionnalités tous les 6-12 mois

Formats de sortie : JSON, XML, Protocol Buffers

Terminal window
# Générer un SBOM CycloneDX 1.5 avec Syft
syft mon-image:latest -o cyclonedx-json@1.5 > sbom.cdx.json

SPDX (Linux Foundation / ISO)

SPDX (Software Package Data Exchange) est un standard de la Linux Foundation, devenu norme ISO/IEC 5962:2021. Il est historiquement très fort sur la conformité des licences et la traçabilité juridique.

Versions et évolution :

  • SPDX 2.2 (2020) : version largement adoptée, base de la norme ISO
  • SPDX 2.3 (2022) : ajout d’annotations, relations enrichies, meilleur support des conteneurs
  • SPDX 3.0 (2024) : refonte majeure avec profils modulaires (Core, Software, Security, Licensing, Build, AI/ML), support natif de VEX et des attestations

Points forts :

  • Standard ISO : reconnu internationalement, requis par certains gouvernements et industries réglementées
  • Licences exhaustives : liste SPDX des identifiants de licences (MIT, Apache-2.0, GPL-3.0…) utilisée universellement
  • Provenance détaillée : traçabilité complète de l’origine des composants
  • SPDX 3.0 : rattrape CycloneDX sur la sécurité avec les profils Security et Build

Formats de sortie : JSON, RDF/XML, Tag-Value (texte plat), YAML

Terminal window
# Générer un SBOM SPDX 2.3 avec Syft
syft mon-image:latest -o spdx-json@2.3 > sbom.spdx.json

Tableau comparatif

CritèreCycloneDXSPDX
OrganismeOWASPLinux Foundation / ISO
Version actuelle1.6 (2024)3.0 (2024)
Focus principalSécurité, supply chainLicences, conformité
Support VEXNatif depuis 1.4Natif depuis 3.0
Norme ISONonOui (ISO/IEC 5962)
Adoption DevSecOpsTrès largeEn croissance
ComplexitéSimplePlus verbeux

Un choix pragmatique

En pratique, le choix dépend du contexte :

  • Sécurité et DevSecOps : CycloneDX est souvent plus « plug-and-play » avec les outils de scan (Trivy, Grype, Snyk, Dependency Track)
  • Conformité réglementaire : SPDX est requis par certains secteurs (défense, automobile, médical) et reconnu ISO
  • Licences open source : SPDX reste la référence pour l’audit de licences
  • Gouvernement US : les deux formats sont acceptés par la CISA et le NIST

Ma recommandation : génèrez les deux formats quand c’est possible. Syft et Trivy le font facilement, ce qui permet de répondre à tous les consommateurs (équipes sécurité, juridique, clients, autorités).

Terminal window
# Générer les deux formats en une seule commande
syft mon-image:latest -o cyclonedx-json > sbom.cdx.json
syft mon-image:latest -o spdx-json > sbom.spdx.json

Outils de génération de SBOM

Plusieurs outils permettent de générer des SBOM. Voici les principaux que j’utilise en production :

Outils de génération

OutilÉditeurPoints fortsFormats
SyftAnchoreImages conteneur, archives, filesystem. Très rapideCycloneDX, SPDX
TrivyAqua SecurityScanner de vulnérabilités + génération SBOM intégréeCycloneDX, SPDX
cdxgenOWASP/CycloneDXOfficiel CycloneDX, excellent support multi-langagesCycloneDX
spdx-sbom-generatorSPDX ProjectOfficiel SPDX, focus conformité licencesSPDX
Terminal window
# Syft : image conteneur vers CycloneDX et SPDX
syft nginx:latest -o cyclonedx-json > sbom.cdx.json
syft nginx:latest -o spdx-json > sbom.spdx.json
# Trivy : génération SBOM intégrée
trivy image --format cyclonedx nginx:latest > sbom.cdx.json
# cdxgen : projet source multi-langages
cdxgen -o sbom.json ./mon-projet

Outils d’analyse de SBOM

Une fois le SBOM généré, ces outils permettent de l’exploiter :

OutilFonctionGuide
GrypeScan de vulnérabilités sur SBOM existantGuide Grype
TrivyScan multi-cibles (SBOM, images, IaC, secrets)Guide Trivy
Dependency-TrackPlateforme de gestion continue des SBOMGuide Dependency-Track
Terminal window
# Grype : scanner un SBOM existant
grype sbom:./sbom.cdx.json
# Gate CI : échouer si vulnérabilité high+ avec correctif disponible
grype sbom:./sbom.cdx.json --only-fixed --fail-on high

Distribuer un SBOM

Générer un SBOM ne suffit pas. Un SBOM qui reste sur le poste du développeur ou dans un artefact CI oublié ne sert à rien le jour où une CVE critique tombe.

Pour qu’un SBOM soit utile, il doit être :

  • Accessible : les équipes sécurité, les clients, les auditeurs doivent pouvoir le récupérer sans demander à personne
  • Associé à l’artefact : savoir quel SBOM correspond à quelle version déployée (sinon, c’est le chaos)
  • Vérifiable : garantir que le SBOM n’a pas été modifié après sa génération

Sans distribution structurée, on se retrouve à chercher « c’est où le SBOM de la version 2.3.1 en prod ? » pendant qu’une vulnérabilité est activement exploitée.

Trois stratégies de distribution

StratégieAvantagesInconvénients
Fichier à côté (CI, S3, release)Simple à mettre en placeDissocié de l’image, risque de désynchronisation
SBOM attaché OCICo-localisé avec l’image, même registryNécessite des outils compatibles OCI
Attestation signéeIntégrité garantie, traçabilité cryptographiqueSetup plus complexe (clés, Sigstore)

Ma recommandation : démarrez avec un fichier artefact CI pour avoir quelque chose rapidement, puis évoluez vers OCI attach + attestation signée dès que votre pipeline est stable.

Attacher un SBOM à une image avec Cosign

L’attachement OCI place le SBOM dans la même registry que l’image, avec une référence liée. Quand on pull l’image, on peut récupérer son SBOM sans chercher ailleurs. Pour maîtriser Cosign, consulte mon guide sur la signature d’images conteneur.

Terminal window
# Générer un SBOM (ex: SPDX)
syft packages mon-registry/mon-image:1.0.0 -o spdx > sbom.spdx
# Attacher le SBOM à l'image dans la registry
cosign attach sbom --sbom sbom.spdx mon-registry/mon-image:1.0.0
# Vérifier que le SBOM est bien attaché
cosign download sbom mon-registry/mon-image:1.0.0

SBOM en attestation signée

L’attestation va plus loin : elle signe cryptographiquement le SBOM et l’associe à l’image. Impossible de le modifier sans casser la signature.

Terminal window
# Attestation CycloneDX JSON (keyless via **Sigstore**/**OIDC**)
syft attest --output cyclonedx-json mon-registry/mon-image:1.0.0
# Vérifier l'attestation
cosign verify-attestation mon-registry/mon-image:1.0.0

Pourquoi cette approche plutôt qu’un simple fichier ?

Parce qu’on crée un graphe d’artefacts vérifiable autour de l’image : SBOM, signatures, provenance SLSA… tout est au même endroit, lié cryptographiquement. Le jour où un client demande « prouvez-moi ce que contient cette image », on a une réponse immédiate et vérifiable.

Réagir vite à une CVE : rechercher dans les SBOM

Le scénario classique

Vendredi 17h, une CVE critique tombe sur un composant très répandu. Mon manager me demande : « On est impactés ? Combien de systèmes ? C’est quoi la priorité ? ». Sans SBOM, je passe mon week-end à fouiller des package-lock.json et des images Docker. Avec des SBOM centralisés, j’ai ma réponse en quelques minutes.

Étape 1 : identifier les artefacts impactés

La première question est : quels projets/images utilisent ce composant ?

Terminal window
# Rechercher un composant dans tous mes SBOM CycloneDX
for sbom in *.cdx.json; do
if jq -e '.components[] | select(.name=="log4j-core")' "$sbom" > /dev/null 2>&1; then
echo "⚠️ $sbom contient log4j-core"
fi
done

Pour une recherche plus précise avec la version :

Terminal window
# Trouver les versions exactes de log4j-core dans chaque SBOM
for sbom in *.cdx.json; do
jq -r --arg file "$sbom" '
.components[]
| select(.name=="log4j-core")
| "\($file): \(.name) \(.version)"
' "$sbom" 2>/dev/null
done

Étape 2 : vérifier si la version est vulnérable

Une fois les artefacts identifiés, vérifiez si leurs versions sont dans la plage vulnérable. Pour Log4Shell (CVE-2021-44228), les versions 2.0-beta9 à 2.14.1 étaient impactées.

Terminal window
# Extraire composant + version + purl pour corrélation
jq -r '
.components[]
| select(.name=="log4j-core")
| "\(.name) \(.version) \(.purl // "no-purl")"
' mon-app.cdx.json
# Résultat exemple :
# log4j-core 2.14.1 pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1

Le purl (Package URL) est particulièrement utile : il permet une corrélation directe avec les bases de vulnérabilités (OSV, NVD, GitHub Advisory).

Étape 3 : prioriser la remédiation

Tous les artefacts impactés ne sont pas égaux. On priorise selon les critères décrits dans mon guide CVE, CVSS et EPSS :

CritèrePriorité hautePriorité basse
ExpositionProd exposée InternetEnv de dev interne
Criticité métierService critique 24/7Batch mensuel
ExploitabilitéCVE avec exploit publicCVE théorique
Effort de correctionBump de version simpleRefactoring majeur
Terminal window
# Exemple : lister les images de prod contenant le composant vulnérable
for sbom in prod-*.cdx.json; do
if jq -e '.components[] | select(.name=="log4j-core" and .version=="2.14.1")' "$sbom" > /dev/null 2>&1; then
echo "🔴 CRITIQUE: $sbom (prod)"
fi
done

Étape 4 : automatiser avec Dependency-Track

Pour une gestion à l’échelle, on centralise les SBOM dans Dependency-Track. La plateforme :

  • Ingère les SBOM automatiquement (API, CI/CD)
  • Corrèle avec les bases de vulnérabilités en continu
  • Alerte quand une nouvelle CVE impacte un composant existant
  • Historise l’évolution des vulnérabilités par projet
Terminal window
# Upload d'un SBOM vers Dependency-Track via API
curl -X POST "https://dtrack.example.com/api/v1/bom" \
-H "X-Api-Key: $DTRACK_API_KEY" \
-H "Content-Type: application/json" \
-d @sbom.cdx.json

Exemple concret : réponse à Log4Shell

Prenons l’exemple de Log4Shell (CVE-2021-44228, score CVSS 10.0). Avec des SBOM centralisés, le workflow de réponse devient :

  1. Identifier : rechercher log4j-core dans tous les SBOM pour lister les artefacts concernés
  2. Filtrer : parmi ces artefacts, isoler ceux avec une version vulnérable (< 2.15.0)
  3. Prioriser : distinguer les environnements de production exposés des environnements de développement internes
  4. Corriger : déployer les patches en commençant par les services critiques

Sans SBOM, chaque étape nécessite des recherches manuelles dans les dépôts, les images et les configurations. Avec des SBOM à jour, on passe de plusieurs jours de recherche à quelques heures de traitement.

Réduire le bruit : SBOM + VEX

Le problème : l’alert fatigue

Un scan de vulnérabilités sur un SBOM complet peut remonter des centaines de CVE. En pratique, la majorité ne sont pas exploitables dans le contexte :

  • Dépendance présente mais jamais appelée : le code vulnérable existe dans l’image mais aucun chemin d’exécution ne l’atteint
  • Composant désactivé : une feature flag ou une configuration désactive la fonction concernée
  • Contexte d’exploitation absent : la CVE nécessite un accès réseau que mon conteneur n’a pas
  • Déjà mitigé : un WAF, un contrôle réseau ou une sandbox neutralise l’attaque

Sans moyen de qualifier ces vulnérabilités, mes équipes passent leur temps à trier du bruit au lieu de corriger les vrais problèmes. C’est l’alert fatigue : à force de faux positifs, on finit par ignorer les vraies alertes.

VEX : qualifier l’exploitabilité

Le VEX (Vulnerability Exploitability eXchange) est un format standardisé pour documenter l’état d’exploitabilité d’une vulnérabilité dans un contexte donné. C’est le compagnon indispensable du SBOM.

Un document VEX associe une CVE à un statut :

StatutSignification
not_affectedLe produit n’est pas impacté (composant non utilisé, config désactivée…)
affectedLe produit est impacté et nécessite une action
fixedLa vulnérabilité a été corrigée dans cette version
under_investigationL’analyse est en cours

Exemple concret

Imaginons que Grype remonte CVE-2024-1234 sur libxml2 dans une image. Après analyse, on constate que :

  • l’application n’appelle jamais les fonctions XML concernées
  • le binaire vulnérable est présent mais jamais exécuté

On peut créer un VEX pour documenter cette décision :

{
"document": {
"category": "vex",
"title": "VEX pour mon-app:1.2.0"
},
"statements": [
{
"vulnerability": { "name": "CVE-2024-1234" },
"products": ["pkg:oci/mon-app@1.2.0"],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"impact_statement": "libxml2 est présent dans l'image de base mais notre application n'utilise aucune fonction de parsing XML."
}
]
}

Formats VEX

Deux formats principaux existent :

  • OpenVEX : format léger porté par Chainguard et l’écosystème Sigstore
  • CycloneDX VEX : intégré nativement dans CycloneDX depuis la version 1.4
  • CSAF VEX : format OASIS utilisé par les grands éditeurs (Red Hat, Cisco…)

Intégrer VEX dans le workflow

Terminal window
# Générer un scan avec Grype
grype sbom:./sbom.cdx.json -o json > vulns.json
# Appliquer un VEX pour filtrer les faux positifs
grype sbom:./sbom.cdx.json --vex ./mon-app.vex.json
# Le scan ne remonte plus les CVE marquées not_affected

Conclusion

Un SBOM utile, ce n’est pas « un fichier JSON de plus ». C’est un levier d’automatisation qui transforme une question floue (« on utilise quoi ? ») en données structurées et interrogeables.

Les bénéfices sont concrets :

  • Visibilité : on sait exactement ce que contient chaque artefact
  • Réactivité : en quelques minutes, on identifie les systèmes impactés par une CVE
  • Traçabilité : on peut prouver ce qu’on livre à ses clients et auditeurs
  • Conformité : on répond aux exigences CRA, NIS2 et Executive Order 14028

Ma checklist minimale :

  1. Générer un SBOM sur chaque artefact final (image, binaire)
  2. Scanner automatiquement avec Grype ou Trivy en CI/CD
  3. Distribuer le SBOM (artefact CI → OCI attach → attestation signée)
  4. Centraliser dans Dependency-Track pour la gestion continue
  5. Qualifier les faux positifs avec des documents VEX
  6. Surveiller les nouvelles CVE sur mes composants existants

La question n’est plus « faut-il adopter les SBOM ? » mais « comment les rendre actionnables ? ». Ce guide t’a donné les bases — à toi de les adapter à ton contexte.

Ressources

Voici quelques ressources pour aller plus loin :

Références officielles (USA)

Standards et spécifications

Guides et bonnes pratiques

VEX (utile en complément SBOM)

Réglementation Européenne