⚠️ Traduction non officielle - Cette documentation est une traduction communautaire non officielle de Docker.

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",
  ...
}
Tip

Si 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> .
Tip

Le 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"
  }
}