Schritt 1: Die Stückliste im Build erzeugen
Eine SBOM, die nachträglich über eine Registry läuft, beschreibt nur, was der Scanner erkennt. Eine SBOM aus dem Build kennt zusätzlich den Quellstand und die Bauumgebung. Deshalb gehört sie in denselben Job, der das Image erzeugt.
# Image bauen und den unveraenderlichen Digest merken
DIGEST=$(buildah bud --format docker -t registry.example.de/plattform/app:1.4.2 . \
&& buildah push --digestfile /dev/stdout registry.example.de/plattform/app:1.4.2)
# Variante A: Syft, Ausgabe im SPDX-Format
syft scan registry.example.de/plattform/app@${DIGEST} \
-o spdx-json=sbom.spdx.json
# Variante B: Trivy, Ausgabe im CycloneDX-Format
trivy image --format cyclonedx \
--output sbom.cdx.json registry.example.de/plattform/app@${DIGEST}
# Variante C: direkt beim Bauen mit Buildkit
docker buildx build --sbom=true --provenance=mode=max \
-t registry.example.de/plattform/app:1.4.2 --push .Beziehe die Stückliste immer auf den Digest, nie auf ein Tag. Tags werden überschrieben, Digests nicht. Eine SBOM, die auf app:latest zeigt, beschreibt nach dem nächsten Build ein anderes Image und ist als Nachweis wertlos.
Welches Format du wählst, ist weniger wichtig, als es konsequent durchzuhalten. SPDX ist als ISO-Norm verbreitet und in Beschaffungsprozessen häufig gefordert, CycloneDX ist im Sicherheitsumfeld näher an den Werkzeugen und trägt VEX-Aussagen direkt mit. Beide lassen sich ineinander überführen. Die technische Richtlinie TR-03183-2 des BSI beschreibt, welche Felder eine Stückliste mindestens enthalten muss, und ist damit die praktikabelste Vorlage für den deutschen Kontext.