SBOM 证明

软件物料清单 (SBOM) 证明描述了哪些软件工件 镜像包含用于创建镜像的工件。元数据包含在 用于描述软件工件的 SBOM 可能包括:

  • 项目的名称
  • 版本
  • 许可证类型
  • 作者
  • 唯一包标识符

相反,在构建过程中为镜像的内容编制索引有好处 扫描最终镜像。当扫描作为构建的一部分进行时,您将 能够检测到您用于构建镜像的软件,这些软件可能不会显示在 最终镜像。

BuildKit 生成的 SBOM 遵循 SPDX 标准。SBOM 附加到 最终镜像作为 JSON 编码的 SPDX 文档,使用 in-toto SPDX 谓词定义的格式。

创建 SBOM 证明

要创建 SBOM 认证,请将--attest type=sbom选项添加到docker buildx build命令:

$ docker buildx build --tag <namespace>/<image>:<version> \
    --attest type=sbom --push .

或者,您也可以使用简写--sbom=true选项而不是--attest type=sbom.

有关如何使用 GitHub Actions 添加 SBOM 证明的示例,请参阅使用 GitHub Actions 添加证明

验证 SBOM 证明

在将镜像推送到注册表之前,请始终验证为镜像生成的 SBOM。

要进行验证,您可以使用local出口商。 使用localexporter 将构建结果保存到本地文件系统,而不是创建镜像。 证明将写入导出根目录中的 JSON 文件。

$ docker buildx build \
  --sbom=true \
  --output type=local,dest=out .

SBOM 文件将显示在输出的根目录中,名为sbom.spdx.json:

$ ls -1 ./out | grep sbom
sbom.spdx.json

参数

默认情况下,BuildKit 仅扫描镜像的最后阶段。生成的 SBOM 不包括早期阶段安装的构建时依赖项,或者 存在于构建上下文中。这可能会导致您忽略 这些依赖项可能会影响最终构建的安全性 工件。

例如,您可以使用多阶段构建、 替换为FROM scratch节以实现较小的镜像大小。

FROM alpine AS build
# build the software ...

FROM scratch
COPY --from=build /path/to/bin /bin
ENTRYPOINT [ "/bin" ]

扫描使用此 Dockerfile 示例生成的生成的镜像不会 显示build阶段。

要包含 Dockerfile 中的构建时依赖项,您可以设置 build 参数BUILDKIT_SBOM_SCAN_CONTEXTBUILDKIT_SBOM_SCAN_STAGE.这 扩展扫描范围以包括 Build Context 和其他阶段。

您可以将参数设置为全局参数(在声明 Dockerfile syntax 指令,在第一个FROM命令)或单独在每个 阶段。如果全局设置,则该值将传播到 Dockerfile 中的每个阶段。

BUILDKIT_SBOM_SCAN_CONTEXTBUILDKIT_SBOM_SCAN_STAGE构建参数 是特殊值。您不能使用这些 参数,并且不能使用 Dockerfile 文件。设置这些值的唯一方法是使用 explicitARG命令 Dockerfile 中。

扫描构建上下文

要扫描构建上下文,请将BUILDKIT_SBOM_SCAN_CONTEXTtrue.

# syntax=docker/dockerfile:1
ARG BUILDKIT_SBOM_SCAN_CONTEXT=true
FROM alpine AS build
# ...

您可以使用--build-argCLI 选项覆盖 Dockerfile 文件。

$ docker buildx build --tag <image>:<version> \
    --attest type=sbom \
    --build-arg BUILDKIT_SBOM_SCAN_CONTEXT=false .

请注意,仅将选项作为 CLI 参数传递,而无需声明它 用ARG将不起作用。您必须指定ARG在 Dockerfile 中,这样你可以使用--build-arg.

扫描阶段

要扫描的不仅仅是最终阶段,请将BUILDKIT_SBOM_SCAN_STAGE参数设置为 true,无论是在全局还是在你想要的特定阶段 扫描。下表演示了此项的不同可能设置 论点。

价值描述
BUILDKIT_SBOM_SCAN_STAGE=true启用当前阶段的扫描
BUILDKIT_SBOM_SCAN_STAGE=false禁用当前阶段的扫描
BUILDKIT_SBOM_SCAN_STAGE=base,bin启用对名为basebin

将仅扫描构建的阶段。不依赖 的阶段 不会构建或扫描目标阶段。

以下 Dockerfile 示例使用多阶段构建来使用 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 /

设置ARG BUILDKIT_SBOM_SCAN_STAGE=truehugo阶段确保最终的 SBOM 包括使用 Alpine Linux 和 Hugo 创建网站的信息。

使用localexporter 创建两个 JSON 文件:

$ docker buildx build \
  --sbom=true \
  --output type=local,dest=out .
$ ls -1 out | grep sbom
sbom-hugo.spdx.json
sbom.spdx.json

检查 SBOM

要浏览通过imageexporter 中,您可以使用imagetools inspect.

使用--format选项中,您可以为输出指定模板。都 SBOM 相关数据可在.SBOM属性。例如,要获取 SPDX 格式的 SBOM 的原始内容:

$ docker buildx imagetools inspect <namespace>/<image>:<version> \
    --format "{{ json .SBOM.SPDX }}"
{
  "SPDXID": "SPDXRef-DOCUMENT",
  ...
}

提示

如果镜像是多平台镜像,则可以使用--format '{{ json (index .SBOM "linux/amd64").SPDX }}'.

您还可以使用完整功能构造更复杂的表达式 的 Go 模板。例如,您可以列出所有已安装的软件包及其 版本标识符:

$ docker buildx imagetools inspect <namespace>/<image>:<version> \
    --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
...

SBOM 生成器

BuildKit 使用 scanner 插件生成 SBOM。默认情况下,它使用 BuildKit Syft scanner 插件。这个插件构建在 Anchore 的 Syft 之上, 用于生成 SBOM 的开源工具。

您可以选择不同的插件来与generator选项, 指定 实现 BuildKit SBOM 扫描程序协议的镜像。

$ docker buildx build --attest type=sbom,generator=<image> .

提示

Docker Scout SBOM 生成器可用。请参阅 Docker Scout SBOMs

SBOM 认证示例

以下 JSON 示例显示了 SBOM 证明可能是什么样子。

{
  "_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/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"
  }
}

APP信息