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
匯出器構建映象。使用 local
匯出器構建會將構建結果儲存到本地檔案系統,而不是建立映象。證明將寫入匯出根目錄中的 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 的構建時依賴項,您可以設定構建引數 BUILDKIT_SBOM_SCAN_CONTEXT
和 BUILDKIT_SBOM_SCAN_STAGE
。這將擴充套件掃描範圍以包括構建上下文和附加階段。
您可以將引數設定為全域性引數(在宣告 Dockerfile 語法指令之後,在第一個 FROM
命令之前)或在每個階段中分別設定。如果設定為全域性,則該值會傳播到 Dockerfile 中的每個階段。
BUILDKIT_SBOM_SCAN_CONTEXT
和 BUILDKIT_SBOM_SCAN_STAGE
構建引數是特殊值。您無法使用這些引數執行變數替換,也無法使用 Dockerfile 中的環境變數設定它們。設定這些值的唯一方法是在 Dockerfile 中使用顯式的 ARG
命令。
掃描構建上下文
要掃描構建上下文,請將 BUILDKIT_SBOM_SCAN_CONTEXT
設定為 true
。
# syntax=docker/dockerfile:1
ARG BUILDKIT_SBOM_SCAN_CONTEXT=true
FROM alpine AS build
# ...
您可以使用 --build-arg
CLI 選項覆蓋 Dockerfile 中指定的值。
$ docker buildx build --tag <image>:<version> \
--attest type=sbom \
--build-arg BUILDKIT_SBOM_SCAN_CONTEXT=false .
請注意,僅作為 CLI 引數傳遞選項,而沒有使用 Dockerfile 中的 ARG
宣告它,將不會有任何效果。您必須在 Dockerfile 中指定 ARG
,您可以使用 --build-arg
覆蓋上下文掃描行為。
掃描階段
要掃描除最後階段以外的其他階段,請將 BUILDKIT_SBOM_SCAN_STAGE
引數設定為 true,全域性設定或在要掃描的特定階段中設定。下表演示了此引數的不同可能設定。
值 | 描述 |
---|---|
BUILDKIT_SBOM_SCAN_STAGE=true | 啟用當前階段的掃描 |
BUILDKIT_SBOM_SCAN_STAGE=false | 停用當前階段的掃描 |
BUILDKIT_SBOM_SCAN_STAGE=base,bin | 啟用名為 base 和 bin 的階段的掃描 |
只有構建的階段才會被掃描。不是目標階段依賴項的階段不會被構建或掃描。
以下 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 /
在 hugo
階段設定 ARG BUILDKIT_SBOM_SCAN_STAGE=true
可確保最終 SBOM 包含用於建立網站的 Alpine Linux 和 Hugo 資訊。
使用 local
匯出器構建此映象會建立兩個 JSON 檔案
$ docker buildx build \
--sbom=true \
--output type=local,dest=out .
$ ls -1 out | grep sbom
sbom-hugo.spdx.json
sbom.spdx.json
檢查 SBOM
要探索透過 image
匯出器匯出的 SBOM,您可以使用 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 }}'
檢查特定於平臺的索引的 SBOM。
您還可以使用 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 使用掃描程式外掛生成 SBOM。預設情況下,它使用的是 BuildKit Syft 掃描程式 外掛。此外掛建立在 Anchore 的 Syft 的基礎上,這是一個用於生成 SBOM 的開源工具。
您可以使用 generator
選項選擇其他外掛,指定一個實現 BuildKit SBOM 掃描程式協議 的映象。
$ docker buildx build --attest type=sbom,generator=<image> .
提示
Docker Scout SBOM 生成器可用。請參閱 Docker Scout SBOM。
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"
}
}