ビルドキットを使用したイメージの SBOM の生成

buildkit を使用してイメージとパッケージの sbom を生成する方法について説明します。

BuildKit の最新リリース シリーズである v0.11 では、ビルド時の構成証明と SBOM のサポートが導入され、パブリッシャーはイメージのビルド方法の記録を使用してイメージを作成できます。 これにより、イメージ内のパッケージ、イメージのビルド元、同じ結果をローカルで再現できるかどうかなど、一般的な質問に簡単に回答できます。

この新しいデータは、使用する画像のセキュリティについて情報に基づいた意思決定を行うのに役立ち、すべての手作業を手動で行う必要はありません。

このブログ投稿では、構成証明と SBOM とは何か、SBOM を含むイメージを構築する方法、および結果のデータの分析を開始する方法について説明します。

証明とは何ですか?

構成証明は、ステートメントが true であることを宣言することです。 ソフトウェアでは、構成証明は、ソフトウェア成果物に関するステートメントを指定するレコードです。 たとえば、誰がいつ構築したか、どのような入力で構築されたか、どのような出力を生成したかなどを含めることができます。

これらの証明を記述し、成果物自体と一緒に配布することで、他の方法では見つけるのが難しいこれらの詳細を確認できます。 証明なしでこの種の情報を取得するには、ソースコードを見つけようとし、ビルドを自分で再現しようとして、イメージがどのようにビルドされたかをリバースエンジニアリングする必要があります。

この貴重な情報をイメージのエンドユーザーに提供するために、BuildKit v0.11 では、通常のビルドプロセスの一部としてこれらの構成証明をビルドできます。 必要なのは、ビルドステップにいくつかのオプションを追加することだけです。

BuildKit は、(toto フレームワークから) toto 形式での構成証明をサポートしています。 現在、Dockerfile フロントエンドは、次の 2 つの異なる質問に答える 2 種類の構成証明を生成します。

  • SBOM (ソフトウェア部品表) – SBOM には、イメージ内のソフトウェア コンポーネントの一覧が含まれています。 これには、インストールされているさまざまなパッケージの名前、それらのバージョン番号、およびその他の関連するメタデータが含まれます。 これを使用して、イメージに特定のパッケージが含まれているかどうかを一目で確認したり、イメージが特定のCVEに対して脆弱かどうかを判断したりできます。
  • SLSA の来歴 – イメージの来歴は、消費されたマテリアル (画像、URL、ファイルなど)、設定されたビルド パラメーター、結果のイメージをそれを作成した Dockerfile にマッピングできるソース マップなど、ビルド プロセスの詳細を記述します。 これを使用して、イメージがどのように構築されたかを分析し、使用されたソースがすべて正当に見えるかどうかを確認し、自分でイメージを再構築することもできます。

ユーザーは、カスタム BuildKit フロントエンドを介して独自のカスタム構成証明タイプを定義することもできます。 この投稿では、SBOMと、それらをDockerfilesで使用する方法に焦点を当てます。

最新リリースの入手

イメージに構成証明を組み込むには、Buildx と BuildKit の両方の最新リリースが必要です – Docker Desktop を最新バージョンに更新することで最新バージョンを入手できます。

バージョン番号を確認し、buildx v0.10 リリース シリーズと一致していることを確認できます。

$ docker buildx version
github.com/docker/buildx 0.10.0 ...

BuildKit の最新リリースを使用するには、 buildx を使用してドッカーコンテナビルダーを作成します。

$ docker buildx create --use --name=buildkit-container --driver=docker-container

新しいビルダーが正しく構成されていることを確認し、buildkit v0.11リリースシリーズと一致していることを確認できます。

$ docker buildx inspect | grep -i buildkit
Buildkit:  v0.11.1

GitHub Actions で docker/setup-buildx-action を使用している場合は、更新しなくても、これらすべてが自動的に取得されます。

それが邪魔にならないように、SBOMを含むイメージの構築に進むことができます!

イメージへの SBOM の追加

これで、イメージの SBOM を生成する準備ができました。

次のドッカーファイルから始めて、 nginxウェブサーバーを作成しましょう。

# syntax=docker/dockerfile:1.5

FROM nginx:latest
COPY ./static /usr/share/nginx/html

このイメージを SBOM と共に 1 つの手順でビルドしてプッシュできます。

$ docker buildx build --sbom=true -t <myorg>/<myimage> --push .

必要なのはそれだけです! ビルド出力で、SBOM の生成に関するメッセージを見つける必要があります。

...
=> [linux/amd64] generating sbom using docker.io/docker/buildkit-syft-scanner:stable-1                           	0.2s
...

ビルドキットは、スキャナープラグインを使用してSBOMを生成します。 デフォルトでは、 Anchore の Syft オープンソースプロジェクトの上に構築されたスキャナである buildkit-syft-scanner を使用して、手間のかかる作業を行います。 必要に応じて、オプションを指定して generator= 別のスキャナーを使用できます。 

を使用して生成された SBOM buildx imagetoolsを表示する方法を次に示します。

$ docker buildx imagetools inspect <myorg>/<myimage> --format "{{ json .SBOM.SPDX }}"
{
	"spdxVersion": "SPDX-2.3",
	"dataLicense": "CC0-1.0",
	"SPDXID": "SPDXRef-DOCUMENT",
	"name": "/run/src/core/sbom",
	"documentNamespace": "https://anchore.com/syft/dir/run/src/core/sbom-a589a536-b5fb-49e8-9120-6a12ce988b67",
	"creationInfo": {
	"licenseListVersion": "3.18",
	"creators": [
	"Organization: Anchore, Inc",
	"Tool: syft-v0.65.0",
	"Tool: buildkit-v0.11.0"
	],
	"created": "2023-01-05T16:13:17.47415867Z"
	},
	...

SBOMは、ローカルおよびタール輸出業者とも連携します。 これらのエクスポーターを使用してエクスポートする場合、構成証明を出力イメージに直接添付する代わりに、構成証明は個別のファイルとして出力ファイルシステムにエクスポートされます。

$ docker buildx build --sbom=true -o ./image .
$ ls -lh ./image
-rw-------  1 user user 6.5M Jan 17 14:36 sbom.spdx.json
...

この場合の SBOM の表示は、結果を -ing するのと同じくらい cat簡単です。

$ cat ./image/sbom.spdx.json | jq .predicate
{
	"spdxVersion": "SPDX-2.3",
	"dataLicense": "CC0-1.0",
	"SPDXID": "SPDXRef-DOCUMENT",
	…

SBOMの補足

スキャナーを使用してSBOMを生成することは、良い最初のスタートです! ただし、一部のパッケージは、少し型破りな方法でインストールされているため、正しく検出されません。

その場合でも、手動でのやり取りを少し行うことで、この情報をSBOMに取り込むことができます。

curlを使用してダウンロードすることにより、foo v1.2.3をイメージにインストールしたとします。

RUN curl https://example.com/releases/foo-v1.2.3-amd64.tar.gz | tar xzf - && \
    mv foo /usr/local/bin/

この方法でインストールされたソフトウェアは、使用している SBOM ジェネレーターがこのバイナリを特別にサポートしない限り (たとえば、 Syft が特定の既知のバイナリの検出をサポートしている場合)、SBOM に表示されない可能性があります。

このソフトウェアの SBOM を手動で生成するには、 Dockerfile heredoc を使用して、イメージ ファイルシステム上の任意の場所に SPDX スニペットを記述します。

COPY /usr/local/share/sbom/foo.spdx.json <<"EOT"
{
	"spdxVersion": "SPDX-2.3",
	"SPDXID": "SPDXRef-DOCUMENT",
	"name": "foo-v1.2.3",
	...
}
EOT

この SBOM は SBOM ジェネレーターによって取得され、イメージ全体の最終的な SBOM に含まれる必要があります。 この動作は buildkit-syft-scanner に標準で含まれていますが、すべてのジェネレータのツールキットに含まれているわけではありません。

さらに多くのSBOMがあります!

上記のセクションは基本的なイメージをスキャンするのに適していますが、より詳細なパッケージとファイルの情報を提供するのに苦労するかもしれません。 BuildKit は、それぞれ引数と引数 BUILDKIT_SBOM_SCAN_CONTEXT を使用して BUILDKIT_SBOM_SCAN_STAGE 、中間ステージやビルドコンテキストなど、ビルドの追加コンポーネントをスキャンするのに役立ちます。

マルチステージ ビルドの場合、これにより、そのソフトウェアが最終的なイメージに表示されなくても、前のステージの依存関係を追跡できます。

たとえば、デモ C/C++ プログラムの場合、次の Dockerfile があるとします。

# syntax=docker/dockerfile:1.5

FROM ubuntu:22.04 AS build
ARG BUILDKIT_SBOM_SCAN_STAGE=true
RUN apt-get update && apt-get install -y git build-essential
WORKDIR /src
RUN git clone https://example.com/myorg/myrepo.git .
RUN make build

FROM scratch
COPY --from=build /src/build/ /

結果のイメージをスキャンしただけでは、GitやGCC(build-essentialパッケージに含まれています)などのビルドツールがビルドプロセスで使用されたことはわかりません。 build 引数を使用して BUILDKIT_SBOM_SCAN_STAGE SBOM スキャンをビルドに統合することで、他の方法では完全に失われていたであろう、はるかに豊富な情報を取得できます。

これらの追加生成された SBOM ドキュメントには、イメージツールでもアクセスできます。

$ docker buildx imagetools inspect <myorg>/<myimage> --format "{{ range .SBOM.AdditionalSPDXs }}{{ json . }}{{ end }}"
{
	"spdxVersion": "SPDX-2.3",
	"SPDXID": "SPDXRef-DOCUMENT",
	...
}
{
	"spdxVersion": "SPDX-2.3",
	"SPDXID": "SPDXRef-DOCUMENT",
	...
}
...

ローカルエクスポーターとtarエクスポーターの場合、これらは出力ディレクトリに別々のファイルとして表示されます。

$ docker buildx build --sbom=true -o ./image .
$ ls -lh ./image
-rw------- 1 user user 4.3M Jan 17 14:40 sbom-build.spdx.json
-rw------- 1 user user  877 Jan 17 14:40 sbom.spdx.json
...

画像の解析

SBOM を含むイメージを公開しているので、この追加データを利用するためにそれらを分析する方法を見つけることが重要です。

前述のように、サブコマンドを使用して、アタッチされた SBOM 構成証明 imagetools を抽出できます。

$ docker buildx imagetools inspect <myorg>/<myimage> --format "{{json .SBOM.SPDX}}"
{
	"spdxVersion": "SPDX-2.3",
	"dataLicense": "CC0-1.0",
	"SPDXID": "SPDXRef-DOCUMENT",
	...

ターゲット イメージがフラグを使用して --platform 複数のアーキテクチャ用にビルドされている場合は、SBOM 構成証明を抽出するために少し異なる構文が必要になります。

$ docker buildx imagetools inspect <myorg>/<myimage> --format "{{ json (index .SBOM "linux/amd64").SPDX}}"
{
	"spdxVersion": "SPDX-2.3",
	"dataLicense": "CC0-1.0",
	"SPDXID": "SPDXRef-DOCUMENT",
	...

ここで、イメージ内のすべてのパッケージとそのバージョンを一覧表示するとします。 フラグに渡された --format 値を、パッケージを一覧表示する go テンプレート に変更できます。

$ docker buildx imagetools inspect <myorg>/<myimage> --format '{{ range .SBOM.SPDX.packages }}{{ println .name .versionInfo }}{{ end }}' | sort
adduser 3.118
apt 2.2.4
base-files 11.1+deb11u6
base-passwd 3.5.51
bash 5.1-2+deb11u1
bsdutils 1:2.36.1-8+deb11u1
ca-certificates 20210119
coreutils 8.32-4+b1
curl 7.74.0-1.3+deb11u3
...

または、インストールされていることがわかっているソフトウェアのバージョン情報を取得することもできます。

$ docker buildx imagetools inspect <myorg>/<myimage> --format '{{ range .SBOM.SPDX.packages }}{{ if eq .name "nginx" }}{{ println .versionInfo }}{{ end }}{{ end }}'
1.23.3-1~bullseye

SBOMを使用してCVEを検索できるツール(アンコールの Grypeなど)を使用して、SBOM全体を取得し、それを使用してCVEをスキャンすることもできます。

$ docker buildx imagetools inspect <myorg>/<myimage> --format '{{ json .SBOM.SPDX }}' | grype
NAME          	INSTALLED            	FIXED-IN 	TYPE  VULNERABILITY 	SEVERITY   
apt           	2.2.4                             	deb   CVE-2011-3374 	Negligible  
bash          	5.1-2+deb11u1        	(won't fix) deb   CVE-2022-3715 	 
...

これらの操作は超迅速に完了するはずです! SBOM はビルド時に既に生成されているため、毎回最初から生成するのではなく、Docker Hub から既存のデータをクエリするだけです。

さらに先へ

この投稿では、BuildKit と SBOM を使い始めるための絶対的な基本についてのみ説明しました — docs.docker.com で話し合ったことについてもっと知ることができます:

また、最新の BuildKit v0.11 リリースでリリースされたその他の機能の詳細については、 こちらをご覧ください

フィードバック

「ビルドキットを使用してイメージのSBOMを生成する」に関する0の考え