Introduction
Un SBOM (Software Bill of Materials) est un inventaire exhaustif et structuré des composants logiciels d'une application, incluant bibliothèques, versions et dépendances transitives. En 2026, avec l'Executive Order 14028 aux USA et le Cyber Resilience Act en Europe, les SBOMs sont obligatoires pour toute chaîne d'approvisionnement logicielle critique. Imaginez votre application comme une recette culinaire : sans liste précise des ingrédients (et fournisseurs), impossible de détecter un poison (vulnérabilité zero-day comme Log4Shell). Ce tutoriel avancé vous guide de la génération basique avec Syft à la signature cryptographique SLSA3, en passant par la validation et l'intégration CI/CD. À la fin, vous produirez des SBOMs conformes CycloneDX/SPDX, prêts pour des scans automatisés et audits réglementaires. Idéal pour DevSecOps seniors gérant des déploiements conteneurisés.
Prérequis
- Docker installé (version 24+ pour buildkit)
- Go 1.22+ (pour compiler Syft/Trivy)
- Compte GitHub avec repository privé
- Node.js 20+ et npm (pour exemple projet)
- Outils CLI :
cosignetjqvia brew/apt - Connaissances en supply chain security (SLSA, in-toto)
Installer Syft et outils SBOM
#!/bin/bash
# Installer Syft (Anchore) via Go
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin v1.10.0
# Installer Grype pour scanning vulnérabilités
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.94.0
# Installer CycloneDX CLI pour validation
curl -sSfL https://github.com/CycloneDX/cyclonedx-cli/releases/latest/download/cyclonedx-linux-amd64.tar.gz | tar -xz -C /usr/local/bin cyclonedx
chmod +x /usr/local/bin/cyclonedx
# Vérifier installations
syft version
grype version
cyclonedx versionCe script installe Syft pour générer des SBOMs à partir d'images ou sources, Grype pour scanner les vulnérabilités, et CycloneDX CLI pour valider le format. Utilisez des versions pinned pour reproductibilité en CI/CD ; évitez les installs root en prod via conteneurs.
Générer un SBOM pour une image Docker
Commençons par un cas concret : une image Alpine avec Nginx. Syft scanne les layers Docker pour lister paquets OS, libs et métadonnées. Le SBOM sort en JSON CycloneDX 1.6, standard ouvert et machine-readable.
Build image et générer SBOM
#!/bin/bash
# Dockerfile simple pour test
docker run --rm -d --name test-nginx nginx:alpine sleep 3600
# Générer SBOM en CycloneDX JSON
syft nginx:alpine -o cyclonedx-json=sbom-docker.json
# Scanner vulnérabilités avec Grype
grype sbom:./sbom-docker.json -o table
# Nettoyer
docker rm -f test-nginxSyft extrait le SBOM de l'image nginx:alpine sans build manuel, produisant un fichier JSON complet avec hashes SHA256 et PURLs. Grype croise ce SBOM contre bases CVE/NVD ; en CI, pipez vers Slack pour alertes critiques. Piège : oubliez pas les images multi-arch.
Générer SBOM pour projet source Node.js
Passez à un projet applicatif. Créez un repo Node.js, installez dépendances, puis générez SBOM source-level. Cela capture package-lock.json pour transitives.
Setup projet Node et SBOM source
#!/bin/bash
mkdir myapp && cd myapp
npm init -y
npm install express lodash
# Générer SBOM depuis répertoire source
syft dir:. -o cyclonedx-json=sbom-node.json --exclude ".git"
# Exemple extraction avec jq (pour vérif)
jq '.components | length' sbom-node.json
jq '.metadata.component.name' sbom-node.jsonSyft scanne node_modules et lockfile pour un SBOM précis, excluant .git pour sécurité. jq vérifie comptage composants (~150 pour Express+Lodash). Avantage : détecte vulns avant build ; piège, npm ci en CI pour lockfile consistant.
Exemple SBOM JSON généré
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-3953-4ab3-b6bb-17e9dd61fd62",
"metadata": {
"timestamp": "2026-01-01T00:00:00Z",
"tools": [{"vendor": "anchore", "name": "syft", "version": "v1.10.0"}],
"component": {
"type": "application",
"name": "myapp",
"version": "1.0.0"
}
},
"components": [
{
"type": "library",
"name": "lodash",
"version": "4.17.21",
"purl": "pkg:npm/lodash@4.17.21",
"hashes": [{"alg": "SHA-256", "value": "fe5854e6f14bece6c494d9753f0f069c5a5d6fb8d910261ee94611be79630ede"}]
}
],
"dependencies": []
}Ce SBOM CycloneDX minimal illustre structure : metadata (outils, timestamp), components (PURL, hashes), dependencies (graphe). Copiez-collez pour tests ; en prod, signez pour non-répudiation.
Valider le SBOM généré
La validation assure conformité schema et intégrité. CycloneDX CLI vérifie JSON/XML contre specs officielles.
Validation et conversion SBOM
#!/bin/bash
# Valider CycloneDX JSON
cyclonedx-cli validate --input-file sbom-node.json --schema-file https://raw.githubusercontent.com/CycloneDX/specification/main/json/schema/cyclonedx-1.6-strict.json
# Convertir vers SPDX JSON
syft dir:. -o spdx-json=sbom-spdx.json
cyclonedx-cli convert --input-file sbom-node.json --output-file sbom-cyclonedx.xml --output-format xml
# Vérifier SPDX
cat sbom-spdx.json | jq '.packages | length'Validation contre schema strict rejette erreurs ; conversion permet dual-format (CycloneDX pour outils, SPDX pour gov). Téléchargez schemas localement en air-gapped ; piège : versions spec mismatch causent faux négatifs.
Intégrer SBOM en GitHub Actions CI/CD
Automatisez en pipeline : build, SBOM, scan, publish Artifact. Utilisez GitHub Dependency Submission API pour graph auto.
Workflow GitHub Actions SBOM
name: Generate and Validate SBOM
on: [push, pull_request]
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- name: Install Syft
uses: anchore/sbom-action/download-syft@v0.15.4
- name: Generate SBOM
run: syft dir:. -o cyclonedx-json=sbom.json
- name: Validate SBOM
uses: CycloneDX/cyclonedx-cli-action@v3
with:
input: 'sbom.json'
command: validate
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.json
- name: Submit to GitHub
uses: actions/dependency-submission@v1
with:
dependency-graph: sbom.jsonCe workflow génère/validate/upload SBOM à chaque push/PR, soumet à Dependency Graph pour scans GitHub Advanced Security. Cache npm accélère ; ajoutez if: github.ref == 'refs/heads/main' pour prod-only.
Signer SBOM avec Cosign/SLSA
#!/bin/bash
export COSIGN_EXPERIMENTAL=true
# Générer clé (une fois)
cosign generate-key-pair
# Signer SBOM (SLSA provenance + SBOM)
syft packages nginx:alpine -o cyclonedx-json | cosign sign --key cosign.key - |
cosign verify --key cosign.pub
# Pour artifact OICI (OCI registry)
docker create nginx:alpine nginx.tar
cosign sign --yes nginx.tar --key cosign.keyCosign signe SBOM avec clés asymétriques pour SLSA Level 2/3, vérifiable publiquement. COSIGN_EXPERIMENTAL active SBOM signing ; intégrez en GitHub avec sigstore/cosign-installer. Piège : rotatez clés via KMS.
Bonnes pratiques
- Générez SBOM à chaque build : intégrez en CI early, pas post-prod.
- Utilisez PURLs normalisés : CycloneDX/SPDX pour interop (ex:
pkg:npm/lodash@4.17.21). - Signez et timestamp : Cosign + TSA pour audits non-répudiables.
- Stockez en registry : GitHub Packages ou Harbor pour versioning.
- Automatisez scans : Grype/Trivy en boucle, seuil CVSS>7 alerte.
Erreurs courantes à éviter
- SBOM incomplet : oublie transitives ? Forcez
npm ci --frozen-lockfile. - Formats incompatibles : CycloneDX 1.5 vs 1.6 ; pinnez outils.
- Pas de validation : schemas lax crash en prod ; toujours
--strict. - Ignore multi-platform : testez
docker buildxpour arm64/x86.
Pour aller plus loin
Plongez dans SLSA Framework v1.0 sur slsa.dev. Intégrez OPA/Gatekeeper pour policies SBOM en K8s. Consultez nos formations Learni DevSecOps pour certifications avancées. Ressources : CycloneDX spec, Anchore docs.