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

投稿日 Jan 24, 2023
BuildKit を使用して、イメージとパッケージの SBOM を生成する方法を学習します。

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

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

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

証明とは何ですか?

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

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

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

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

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

ユーザーは、カスタムのBuildKitフロントエンドを介して、独自のカスタム認証タイプを定義することもできます。この記事では、SBOM(ソフトウェア構成表)と、それをDockerfileで使用する方法に焦点を当てます。

最新リリースの入手

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

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

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

最新版のBuildKitを使用するには、 buildxを使用してdockerコンテナビルダーを作成します。

$ 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ウェブサーバーを作成するための以下のDockerfileから始めましょう。

# 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
...

BuildKitはスキャナープラグインを使用して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ジェネレーターがこのバイナリを特別にサポートしていない限り、SBOMに表示されない可能性があります(たとえば、 Syftは特定の既知のバイナリを検出する機能をサポートしています)。

Dockerfile のヒアドキュメントを使用して、イメージファイルシステム上の任意の場所に SPDX スニペットを書き込むことで、このソフトウェアの SBOM を手動で生成できます。

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全体を取得して、SBOMを使用してCVEを検索できるツール(AnchoreのGrypeなど)を使用して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 v 0 . 11リリースでリリースされたその他の機能の詳細については、こちらをご覧ください。

関連記事