Nix のビルド入力の導出
各イメージのビルド入力は、Nix のビルドグラフから機械的に導出できます。 この導出は、SBOM の生成、上流のマルウェア検知、上流のゼロデイ修正検知という、性質の異なる複数の機能に共通する基盤です。
導出とは
Nix でのビルドは、すべて導出(derivation)という単位で宣言します。 導出は、依存する導出、ソース、ビルドスクリプトといった入力を持ち、それぞれの入力はハッシュで固定されています。 同じ入力からは必ず同じ出力ができるという性質は、この宣言のしかたから直接来ています。 イメージそのものもひとつの導出で、その入力をたどると、依存するライブラリの導出、そのソースの導出というふうに、ビルドグラフ全体が木構造で広がっています。 あるイメージが実際に何を取り込んでビルドされたかは、人が書いたドキュメントではなく、このグラフそのものが正本です。
導出の中身は、nix derivation show で誰でも直接確認できます。
たとえば nixpkgs の hello パッケージを確認すると、ビルドスクリプトを実行する builder、その引数、そして依存する導出(inputDrvs)が、次のように JSON で得られます(実際の出力 から一部を抜粋)。
$ nix --extra-experimental-features 'nix-command flakes' \
derivation show 'nixpkgs#legacyPackages.x86_64-linux.hello'
{
"name": "hello-2.12.3",
"system": "x86_64-linux",
"builder": "/nix/store/zh1ijdhb6gng1509b1zrilb6xlzx60j6-bash-5.3p9/bin/bash",
"args": [
"-e",
"/nix/store/l622p70vy8k5sh7y5wizi5f2mic6ynpg-source-stdenv.sh",
"/nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh"
],
"inputDrvs": [
"9w4h6mwgy4vivksdb54jhz6i2dihqv1l-hello-2.12.3.tar.gz.drv",
"g7p7rs03xah2w00a142hzas9h4fkwpck-bash-5.3p9.drv",
"i1fmvnw4pqbjhcygp8rggs6n88jg1bny-version-check-hook.drv",
"l0x59a9gpwqh6rxxx2sxbl5nd72r4bc8-stdenv-linux.drv"
]
}
inputDrvs に並ぶのは、この導出が依存する他の導出です。
それぞれをさらに nix derivation show でたどれば、ソース取得の導出に行き着くまで、ビルドグラフを手作業でも下れます。
このソース取得の導出こそが、次に述べる固定出力導出(FOD)です。
固定出力導出(FOD)とネットワークアクセス
このグラフのなかで、外部ネットワークへのアクセスが許される導出は、固定出力導出(fixed-output derivation、FOD)だけです。 通常の導出はサンドボック スの中でビルドし、宣言した入力以外(ネットワークや宣言外のファイル)へのアクセスを遮断します。 FOD だけは例外的にネットワーク取得を許されますが、そのかわり、取得する結果のコンテンツハッシュを事前に宣言しなければなりません。 取得した結果が宣言したハッシュと一致しなければ、ビルドはその場で失敗します。
| 観点 | 通常の導出 | 固定出力導出(FOD) |
|---|---|---|
| ネットワークアクセス | 許されない | 許される |
| 出力のハッシュ | ビルドした結果から決まる | 事前に宣言し、一致しなければビルド失敗 |
| 使われる場面 | 依存関係のコンパイルや組み立て | 上流ソースの取得(tarball、Git リポジトリなど) |
nixpkgs のソース取得関数は、tarball を取ってくるものも Git リポジトリを取ってくるものも、最終的にすべてこの FOD に行き着きます。 FOD は、宣言したハッシュを信頼する形でネットワーク取得を安全に切り出した、ビルドグラフ上で唯一の外部への窓口です。
上流ソースの機械的な導出
ビルドグラフをたどって FOD だけを取り出せば、イメージに寄与した外部ソースの全量を機械的に導出できます。 各 FOD には、取得元の URL やリビジョン、宣言したハッシュが、そのまま属性として残っています。 人がイメージの定義やパッチを読んで「どこから来たか」を推測する必要はなく、ビルドグラフを評価するだけで、この一覧が得 られます。 一覧には、イメージ本体のパッケージだけでなく、ビルドに使うツール自体のソースも含まれます。
得られる一覧は、たとえば次のような形です(実際の一覧から 1 ソース分を抜粋)。
{
"https://github.com/chainguard-dev/apko.git": {
"fetcher": "git:github.com",
"rev": "refs/tags/v1.2.19",
"hash": "sha256-Iia0U/oibPuUYC3adeXvL5m4nhEPHqBvHw7J7Uxn88s=",
"images": ["apko"]
}
}
どの上流ソースが、どのリビジョンで、どのイメージに影響するか(images