Attestations SBOM
Les attestations Software Bill of Materials (SBOM) décrivent quels artefacts logiciels une image contient, et les artefacts utilisés pour créer l'image. Les métadonnées incluses dans un SBOM pour décrire les artefacts logiciels peuvent inclure :
- Nom de l'artefact
- Version
- Type de licence
- Auteurs
- Identifiant unique du package
Il y a des avantages à indexer le contenu d'une image pendant le build, par opposition à scanner une image finale. Lorsque le scan se produit dans le cadre du build, vous êtes capable de détecter les logiciels que vous utilisez pour construire l'image, qui peuvent ne pas apparaître dans l'image finale.
Les SBOMs générés par BuildKit suivent le standard SPDX. Les SBOMs s'attachent à l'image finale comme un document SPDX encodé JSON, en utilisant le format défini par le prédicat SPDX in-toto.
Créer des attestations SBOM
Pour créer une attestation SBOM, passez l'option --attest type=sbom
à la commande docker buildx build
:
$ docker buildx build --tag <namespace>/<image>:<version> \
--attest type=sbom --push .
Alternativement, vous pouvez utiliser l'option raccourcie --sbom=true
au lieu de --attest type=sbom
.
Pour un exemple sur comment ajouter des attestations SBOM avec GitHub Actions, voir Ajouter des attestations avec GitHub Actions.
Vérifier les attestations SBOM
Validez toujours le SBOM généré pour votre image avant de pousser votre image vers un registre.
Pour valider, vous pouvez construire l'image en utilisant l'exportateur local
. Construire avec l'exportateur local
sauvegarde le résultat de build sur votre système de fichiers local au lieu de créer une image. Les attestations sont écrites dans un fichier JSON dans le répertoire racine de votre export.
$ docker buildx build \
--sbom=true \
--output type=local,dest=out .
Le fichier SBOM apparaît dans le répertoire racine de la sortie, nommé sbom.spdx.json
:
$ ls -1 ./out | grep sbom
sbom.spdx.json
Arguments
Par défaut, BuildKit ne scanne que l'étape finale d'une image. Le SBOM résultant n'inclut pas les dépendances de build-time installées dans les étapes précédentes, ou qui existent dans le contexte de build. Cela peut vous faire passer à côté de vulnérabilités dans ces dépendances, qui pourraient impacter la sécurité de vos artefacts de build finaux.
Par exemple, vous pourriez utiliser des
builds multi-étapes, avec une instruction FROM scratch
pour votre étape finale pour obtenir une taille d'image plus petite.
FROM alpine AS build
# construire le logiciel ...
FROM scratch
COPY --from=build /path/to/bin /bin
ENTRYPOINT [ "/bin" ]
Scanner l'image résultante construite en utilisant cet exemple de Dockerfile ne révélerait pas les dépendances de build-time utilisées dans l'étape build
.
Pour inclure les dépendances de build-time de votre Dockerfile, vous pouvez définir les arguments de build BUILDKIT_SBOM_SCAN_CONTEXT
et BUILDKIT_SBOM_SCAN_STAGE
. Cela étend la portée de scan pour inclure le contexte de build et des étapes supplémentaires.
Vous pouvez définir les arguments comme arguments globaux (après avoir déclaré la directive de syntaxe Dockerfile, avant la première commande FROM
) ou individuellement dans chaque étape. Si définis globalement, la valeur se propage à chaque étape dans le Dockerfile.
Les arguments de build BUILDKIT_SBOM_SCAN_CONTEXT
et BUILDKIT_SBOM_SCAN_STAGE
sont des valeurs spéciales. Vous ne pouvez pas effectuer de substitution de variable en utilisant ces arguments, et vous ne pouvez pas les définir en utilisant des variables d'environnement depuis l'intérieur du Dockerfile. La seule façon de définir ces valeurs est d'utiliser une commande ARG
explicite dans le Dockerfile.
Scanner le contexte de build
Pour scanner le contexte de build, définissez BUILDKIT_SBOM_SCAN_CONTEXT
à true
.
# syntax=docker/dockerfile:1
ARG BUILDKIT_SBOM_SCAN_CONTEXT=true
FROM alpine AS build
# ...
Vous pouvez utiliser l'option CLI --build-arg
pour remplacer la valeur spécifiée dans le Dockerfile.
$ docker buildx build --tag <image>:<version> \
--attest type=sbom \
--build-arg BUILDKIT_SBOM_SCAN_CONTEXT=false .
Notez que passer l'option comme argument CLI seulement, sans l'avoir déclarée en utilisant ARG
dans le Dockerfile, n'aura aucun effet. Vous devez spécifier l'ARG
dans le Dockerfile, par lequel vous pouvez remplacer le comportement de scan du contexte en utilisant --build-arg
.
Scanner les étapes
Pour scanner plus que juste l'étape finale, définissez l'argument BUILDKIT_SBOM_SCAN_STAGE
à true, soit globalement soit dans les étapes spécifiques que vous voulez scanner. Le tableau suivant démontre les différents paramètres possibles pour cet argument.
Valeur | Description |
---|---|
BUILDKIT_SBOM_SCAN_STAGE=true |
Active le scan pour l'étape actuelle |
BUILDKIT_SBOM_SCAN_STAGE=false |
Désactive le scan pour l'étape actuelle |
BUILDKIT_SBOM_SCAN_STAGE=base,bin |
Active le scan pour les étapes nommées base et bin |
Seules les étapes qui sont construites seront scannées. Les étapes qui ne sont pas des dépendances de l'étape cible ne seront pas construites, ou scannées.
L'exemple de Dockerfile suivant utilise des builds multi-étapes pour construire un site web statique avec Hugo.
# syntax=docker/dockerfile:1
FROM alpine as hugo
ARG BUILDKIT_SBOM_SCAN_STAGE=true
WORKDIR /src
COPY <<config.yml ./
title: My Hugo website
config.yml
RUN apk add --upgrade hugo && hugo
FROM scratch
COPY --from=hugo /src/public /
Définir ARG BUILDKIT_SBOM_SCAN_STAGE=true
dans l'étape hugo
assure que le SBOM final inclut l'information qu'Alpine Linux et Hugo ont été utilisés pour créer le site web.
Construire cette image avec l'exportateur local
crée deux fichiers JSON :
$ docker buildx build \
--sbom=true \
--output type=local,dest=out .
$ ls -1 out | grep sbom
sbom-hugo.spdx.json
sbom.spdx.json
Inspecter les SBOMs
Pour explorer les SBOMs créés exportés via l'exportateur image
, vous pouvez utiliser
imagetools inspect
.
En utilisant l'option --format
, vous pouvez spécifier un template pour la sortie. Toutes les données liées au SBOM sont disponibles sous l'attribut .SBOM
. Par exemple, pour obtenir le contenu brut d'un SBOM au format SPDX :
$ docker buildx imagetools inspect <namespace>/<image>:<version> \
--format "{{ json .SBOM.SPDX }}"
{
"SPDXID": "SPDXRef-DOCUMENT",
...
}
TipSi l'image est multi-plateforme, vous pouvez vérifier le SBOM pour un index spécifique à une plateforme en utilisant
--format '{{ json (index .SBOM "linux/amd64").SPDX }}'
.
Vous pouvez aussi construire des expressions plus complexes en utilisant la fonctionnalité complète des templates Go. Par exemple, vous pouvez lister tous les packages installés et leurs identifiants de version :
$ docker buildx imagetools inspect <namespace>/<image>:<version> \
--format "{{ range .SBOM.SPDX.packages }}{{ .name }}@{{ .versionInfo }}{{ println }}{{ end }}"
[email protected]
[email protected]
[email protected]
[email protected]
...
Générateur SBOM
BuildKit génère le SBOM en utilisant un plugin de scanner. Par défaut, il utilise le plugin BuildKit Syft scanner. Ce plugin est construit au-dessus de Syft d'Anchore, un outil open source pour générer un SBOM.
Vous pouvez sélectionner un plugin différent à utiliser avec l'option generator
, en spécifiant une image qui implémente le protocole de scanner SBOM BuildKit.
$ docker buildx build --attest type=sbom,generator=<image> .
TipLe générateur SBOM Docker Scout est disponible. Voir SBOMs Docker Scout.
Exemple d'attestation SBOM
L'exemple JSON suivant montre à quoi une attestation SBOM pourrait ressembler.
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "https://spdx.dev/Document",
"subject": [
{
"name": "pkg:docker/<registry>/<image>@<tag/digest>?platform=<platform>",
"digest": {
"sha256": "e8275b2b76280af67e26f068e5d585eb905f8dfd2f1918b3229db98133cb4862"
}
}
],
"predicate": {
"SPDXID": "SPDXRef-DOCUMENT",
"creationInfo": {
"created": "2022-12-16T15:27:25.517047753Z",
"creators": ["Organization: Anchore, Inc", "Tool: syft-v0.60.3"],
"licenseListVersion": "3.18"
},
"dataLicense": "CC0-1.0",
"documentNamespace": "https://anchore.com/syft/dir/run/src/core/sbom-cba61a72-fa95-4b60-b63f-03169eac25ca",
"name": "/run/src/core/sbom",
"packages": [
{
"SPDXID": "SPDXRef-b074348b8f56ea64",
"downloadLocation": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:org:repo:\\(devel\\):*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "PACKAGE_MANAGER",
"referenceLocator": "pkg:golang/github.com/org/repo@(devel)",
"referenceType": "purl"
}
],
"filesAnalyzed": false,
"licenseConcluded": "NONE",
"licenseDeclared": "NONE",
"name": "github.com/org/repo",
"sourceInfo": "acquired package info from go module information: bin/server",
"versionInfo": "(devel)"
},
{
"SPDXID": "SPDXRef-1b96f57f8fed62d8",
"checksums": [
{
"algorithm": "SHA256",
"checksumValue": "0c13f1f3c1636491f716c2027c301f21f9dbed7c4a2185461ba94e3e58443408"
}
],
"downloadLocation": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:go-chi:chi\\/v5:v5.0.0:*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:go_chi:chi\\/v5:v5.0.0:*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:go:chi\\/v5:v5.0.0:*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "PACKAGE_MANAGER",
"referenceLocator": "pkg:golang/github.com/go-chi/chi/[email protected]",
"referenceType": "purl"
}
],
"filesAnalyzed": false,
"licenseConcluded": "NONE",
"licenseDeclared": "NONE",
"name": "github.com/go-chi/chi/v5",
"sourceInfo": "acquired package info from go module information: bin/server",
"versionInfo": "v5.0.0"
}
],
"relationships": [
{
"relatedSpdxElement": "SPDXRef-1b96f57f8fed62d8",
"relationshipType": "CONTAINS",
"spdxElementId": "SPDXRef-043f7360d3c66bc31ba45388f16423aa58693289126421b71d884145f8837fe1"
},
{
"relatedSpdxElement": "SPDXRef-b074348b8f56ea64",
"relationshipType": "CONTAINS",
"spdxElementId": "SPDXRef-043f7360d3c66bc31ba45388f16423aa58693289126421b71d884145f8837fe1"
}
],
"spdxVersion": "SPDX-2.2"
}
}