--- title: SBOM attestations keywords: build, attestations, sbom description: SBOM build attestations --- {% include build-feature-state.md buildkit_v=">=0.11" buildx_v=">=0.10" %} Software Bill of Materials (SBOM) attestations describe what software artifacts an image contains, and artifacts used to create the image. Metadata included in an SBOM for describing software artifacts may include: - Name of the artifact - Version - License type - Authors - Unique package identifier There are benefits to indexing contents of an image during the build, as opposed to scanning a final image. When scanning happens as part of the build, you're able to detect software you use to build the image, that may not show up in the final image. The SBOMs generated by BuildKit follow the SPDX standard. SBOMs attach to the final image as a JSON-encoded SPDX document, using the format defined by the [in-toto SPDX predicate](https://github.com/in-toto/attestation/blob/main/spec/predicates/spdx.md){: target="blank" rel="noopener" }. ## Create SBOM attestations To create a provenance attestation, pass the `--attest type=sbom` option to the `docker buildx build` command: ```console $ docker buildx build --tag /: \ --attest type=sbom --push . ``` Alternatively, you can use the shorthand `--sbom=true` option instead of `--attest type=sbom`. ## Verify SBOM attestations Always validate the generated SBOM for your image before you push your image to a registry. To validate, you can build the image using the `local` exporter. Building with the `local` exporter saves the build result to your local filesystem instead of creating an image. Attestations are written to a JSON file in the root directory of your export. ```console $ docker buildx build \ --sbom=true \ --output type=local,dest=out . ``` The SBOM file appears in the root directory of the output, named `sbom.spdx.json`: ```console $ ls -1 ./out | grep sbom sbom.spdx.json ``` ## Arguments By default, BuildKit only scans the final stage of an image. The resulting SBOM doesn't include build-time dependencies installed in earlier stages, or that exist in the build context. This may cause you to overlook vulnerabilities in those dependencies, which could impact the security of your final build artifacts. For instance, you might use [multi-stage builds](../building/multi-stage.md), with a `FROM scratch` stanza for your final stage to achieve a smaller image size. ```dockerfile FROM alpine AS build # build the software ... FROM scratch COPY --from=build /path/to/bin /bin ENTRYPOINT [ "/bin" ] ``` Scanning the resulting image built using this Dockerfile example would not reveal build-time dependencies used in the `build` stage. To include build-time dependencies from your Dockerfile, you can set the build arguments `BUILDKIT_SBOM_SCAN_CONTEXT` and `BUILDKIT_SBOM_SCAN_STAGE`. This expands the scanning scope to include the build context and additional stages. You can set the arguments as global arguments (after declaring the Dockerfile syntax directive, before the first `FROM` command) or individually in each stage. If set globally, the value propagates to each stage in the Dockerfile. The `BUILDKIT_SBOM_SCAN_CONTEXT` and `BUILDKIT_SBOM_SCAN_STAGE` build arguments are special values. You can't perform variable substitution using these arguments, and you can't set them using environment variables from within the Dockerfile. The only way to set these values is using explicit `ARG` command in the Dockerfile. ### Scan build context To scan the build context, set the `BUILDKIT_SBOM_SCAN_CONTEXT` to `true`. ```dockerfile # syntax=docker/dockerfile:1 ARG BUILDKIT_SBOM_SCAN_CONTEXT=true FROM alpine AS build # ... ``` You can use the `--build-arg` CLI option to override the value specified in the Dockerfile. ```console $ docker buildx build --tag : \ --attest type=sbom \ --build-arg BUILDKIT_SBOM_SCAN_CONTEXT=false . ``` Note that passing the option as a CLI argument only, without having declared it using `ARG` in the Dockerfile, will have no effect. You must specify the `ARG` in the Dockerfile, whereby you can override the context scanning behavior using `--build-arg`. ### Scan stages To scan more than just the final stage, set the `BUILDKIT_SBOM_SCAN_STAGE` argument to true, either globally or in the specific stages that you want to scan. The following table demonstrates the different possible settings for this argument. | Value | Description | | ----------------------------------- | ------------------------------------------------------ | | `BUILDKIT_SBOM_SCAN_STAGE=true` | Enables scanning for the current stage | | `BUILDKIT_SBOM_SCAN_STAGE=false` | Disables scanning for the current stage | | `BUILDKIT_SBOM_SCAN_STAGE=base,bin` | Enables scanning for the stages named `base` and `bin` | Only stages that are built will be scanned. Stages that aren't dependencies of the target stage won't be built, or scanned. The following Dockerfile example uses multi-stage builds to build a static website with [Hugo](https://gohugo.io/){: target="blank" rel="noopener" class="_"}. ```dockerfile # syntax=docker/dockerfile:1 FROM alpine as hugo ARG BUILDKIT_SBOM_SCAN_STAGE=true WORKDIR /src COPY </: \ --format "{{ json .SBOM.SPDX }}" { "SPDXID": "SPDXRef-DOCUMENT", ... } ``` {% endraw %} You can also construct more complex expressions using the full functionality of Go templates. For example, you can list all the installed packages and their version identifiers: {% raw %} ```console $ docker buildx imagetools inspect /: \ --format "{{ range .SBOM.SPDX.packages }}{{ .name }}@{{ .versionInfo }}{{ println }}{{ end }}" adduser@3.118ubuntu2 apt@2.0.9 base-files@11ubuntu5.6 base-passwd@3.5.47 ... ``` {% endraw %} ## SBOM generator BuildKit generates the SBOM using a scanner plugin. By default, it uses is the [BuildKit Syft scanner](https://github.com/docker/buildkit-syft-scanner){: target="blank" rel="noopener" } plugin. This plugin is built on top of [Anchore's Syft](https://github.com/anchore/syft){: target="blank" rel="noopener" }, an open source tool for generating an SBOM. You can select a different plugin to use with the `generator` option, specifying an image that implements the [BuildKit SBOM scanner protocol](https://github.com/moby/buildkit/blob/master/docs/attestations/sbom-protocol.md){: target="blank" rel="noopener" }. ```console $ docker buildx build --attest type=sbom,generator= . ``` ## SBOM attestation example The following JSON example shows what an SBOM attestation might look like. ```json { "_type": "https://in-toto.io/Statement/v0.1", "predicateType": "https://spdx.dev/Document", "subject": [ { "name": "pkg:docker//@?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/v5@v5.0.0", "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" } } ```