From db5489f7a107a86fd8183beafea6d63b17b9956f Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Wed, 9 Nov 2022 11:41:53 +0000 Subject: [PATCH] docs: add user-facing attestation docs Signed-off-by: Justin Chadwell --- docs/sbom.md | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 docs/sbom.md diff --git a/docs/sbom.md b/docs/sbom.md new file mode 100644 index 000000000..9cb008775 --- /dev/null +++ b/docs/sbom.md @@ -0,0 +1,198 @@ +# SBOMs + +BuildKit supports automatic creation of [SBOMs](https://en.wikipedia.org/wiki/Software_supply_chain) +to record the software components that make up the final image. These consist +of a list of software packages and the files that they own. + +They also usually contain metadata about each component, such as software +licenses, authors, and unique package identifiers which can be used for +vulnerability scanning. + +All SBOMs generated by BuildKit are wrapped inside [in-toto attestations](https://github.com/in-toto/attestation) +in the [SPDX](https://spdx.dev) JSON format. They can be generated using +generator images that follow the [SBOM generator protocol](./sbom-protocol.md). + +When the final output format is a container image, these SBOMs are attached +using the [attestation storage](./attestation-storage.md). + +To build an image with an attached SBOM (derived using the builtin default scanner, +[docker/buildkit-syft-scanner](https://github.com/docker/buildkit-syft-scanner)), +use the `attest:sbom` option: + +```bash +buildctl build \ + --frontend=dockerfile.v0 \ + --local context=. \ + --local dockerfile=. \ + --opt attest:sbom= +``` + +You can also specify a custom SBOM generator image: + +```bash +buildctl build \ + --frontend=dockerfile.v0 \ + --local context=. \ + --local dockerfile=. \ + --opt attest:sbom=generator=/ +``` + +## Dockerfile configuration + +By default, only the final build result is scanned - because of this, the +resulting SBOM will not include build-time dependencies that may be installed +in separate stages or the build context. This could cause you to miss +vulnerabilities in those dependencies, which could impact the security of your +final build artifacts. + +To include these build-time dependencies from your Dockerfile, you can set the +build arguments `BUILDKIT_SBOM_SCAN_CONTEXT` and `BUILDKIT_SBOM_SCAN_STAGE` to +additionally scan the build context and other build stages respectively. These +build arguments are special values, and cannot be used for variable +substitutions or as environment variables from within the Dockerfile, as they +exist solely to change the behavior of the scanner. + +Both arguments can be set as global meta arguments (before a `FROM`) or can be +individually set in each stage. If set globally, the value is propagated for +each stage in the Dockerfile. They can take the following values: + +- `true`: enables context/stage scanning (e.g. `BUILDKIT_SBOM_SCAN_STAGE=true`) +- `false`: disables context/stage scanning (e.g. `BUILDKIT_SBOM_SCAN_STAGE=false`) +- `[,]`: enables context/stage scanning for all stages + listed in the comma-separated list of provided stages (e.g. + `BUILDKIT_SBOM_SCAN_STAGE=x,y` will scan stages called `x` and `y`). + +Scanning will *never* be enabled for a stage that is not built, even if it is +enabled via the build arguments. + +For example: + +```dockerfile +FROM alpine:latest as build +# enable scanning for the intermediate build stage +ARG BUILDKIT_SBOM_SCAN_STAGE=true +WORKDIR /src +COPY . . +RUN ... # build some software + +FROM scratch as final +# scan the build context only if the build is run to completion +ARG BUILDKIT_SBOM_SCAN_CONTEXT=true +COPY --from=build /path/to/software /path/to/software +``` + +You can also directly override these `ARG`s on the command line, by passing +them as build arguments: + +```bash +buildctl build \ + --frontend=dockerfile.v0 \ + --local context=. \ + --local dockerfile=. \ + --opt build-arg:BUILDKIT_SBOM_SCAN_STAGE= \ + --opt build-arg:BUILDKIT_SBOM_SCAN_CONTEXT= \ + --opt attest:sbom= +``` + +Scanning will only override existing `ARG` definitions in the Dockerfile, and +so does not allow including other stages in the Dockerfile that do not declare +`BUILDKIT_SBOM_SCAN` arguments. + +## Output + +To inspect the SBOMs that were generated, and attached to a container image, +you can use the `docker buildx imagetools` command to explore the resulting +image in your registry, following the format described in the [attestation storage](./attestation-storage.md). + +For example, for a simple Docker image based on `alpine:latest`, we might get +the following SBOM: + +```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", + "name": "/run/src/core", + "spdxVersion": "SPDX-2.2", + "creationInfo": { + "created": "2022-11-09T10:12:01.338817553Z", + "creators": [ + "Organization: Anchore, Inc", + "Tool: syft-[not provided]" + ], + "licenseListVersion": "3.18" + }, + "dataLicense": "CC0-1.0", + "documentNamespace": "https://anchore.com/syft/dir/run/src/core-4006bb64-24b1-4a22-a18f-94efc6b90edb", + "files": [ + { + "SPDXID": "SPDXRef-1ac501c94e2f9f81", + "comment": "layerID: sha256:9b18e9b68314027565b90ff6189d65942c0f7986da80df008b8431276885218e", + "fileName": "/bin/busybox", + "licenseConcluded": "NOASSERTION" + }, + ... + ], + "packages": [ + { + "SPDXID": "SPDXRef-980737451f148c56", + "description": "Size optimized toolbox of many common UNIX utilities", + "downloadLocation": "https://busybox.net/", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:busybox:busybox:1.35.0-r17:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + }, + { + "referenceCategory": "PACKAGE_MANAGER", + "referenceLocator": "pkg:alpine/busybox@1.35.0-r17?arch=aarch64&upstream=busybox&distro=alpine-3.16.2", + "referenceType": "purl" + } + ], + "filesAnalyzed": false, + "hasFiles": [ + "SPDXRef-1ac501c94e2f9f81", + ... + ], + "licenseConcluded": "GPL-2.0-only", + "licenseDeclared": "GPL-2.0-only", + "name": "busybox", + "originator": "Person: Sören Tempel ", + "sourceInfo": "acquired package info from APK DB: lib/apk/db/installed", + "versionInfo": "1.35.0-r17" + }, + ... + ], + "relationships": [ + { + "relatedSpdxElement": "SPDXRef-1ac501c94e2f9f81", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-980737451f148c56" + }, + ... + ] + } +} +``` + +The exact output will depend on the generator you use, however, generally: + +- The `files` key will contain a list of all files in the image. +- The `packages` key will contain a list of all packages discovered from the + image. +- The `relationships` key links together various files and packages, together + with metadata about how they relate to each other. + +Entries in the `files` and `packages` will contain a `comment` field that +contains the `sha256` digest of the layer which introduced it if that layer is +present in the final image.