システムイメージ(System images)
ここでは、再現性のあるシステムイメージのビルドについて理解できていることを説明します。 仮想マシンやクラウドイメージ、動的システムやOSのインストーラーのISOイメージなどです。
再現性のあるシステムイメージの作成に関する一般的な問題
一般的には次のような問題があります。
- ファイルシステムは 1回 で作成しなければなりません
- ファイルシステムは作成日時や変更日時を含みます
- ファイルシステムは UUID や明示的に指定できないラベルを含みます
- ファイルシステムに配置するファイルにはタイムスタンプが付いています
- ファイルシステムに配置するファイルをビルド時に(再現性を損なう方法で)生成および更新する場合があります
- 統合されるブートローダーにはタイムスタンプが付いています
- 統合された initramfs イメージは、システムイメージをビルドするとき、再現性を損なう方法でビルドされます
- 環境変数
SOURCE_DATE_EPOCH
に依存しないタイムスタンプは再現性を損なう場合があります
mkfs.ext4
コマンドでファイルシステムを作成し、マウントし、変更し、保存したイメージは再現性がありません。
割り当てられたiノード番号が分からないからです。
幸運なことに、ほとんどの問題に解決策が存在します。
ext2, ext3, ext4
mkfs.ext
ではなく make_ext4fs
を使用します。
make_ext4fs
はファイルシステム全体を1回で作成します。
make_ext4fs -T <unix_timestamp>
という形式で SOURCE_DATE_EPOCH
を変更日時に指定できます。
make_ext4fs
は次のコミットを含んでいるバージョンを使用してください。
- https://git.lede-project.org/?p=project/make_ext4fs.git;a=commit;h=bd53eaafbc2a89a57b8adda38f53098a431fa8f4
ISO ファイルシステム
xorriso
で ISO ファイルシステムをビルドするときの注意点は次のとおりです。
- 最新バージョンならさまざまな ISO イメージのメタデータに
$SOURCE_DATE_EPOCH
を使用できます --modification-date
に$SOURCE_DATE_EPOCH
を指定すると全ての変更日時が同じ値になります
次のような考慮も必要です。
isohybrid --id
には固定値を渡します- initrd イメージも再現性を考慮してビルドします(https://bugs.debian.org/845034)
SquashFS のメタデータとデータ圧縮
SquashFS でシステムイメージを圧縮すると、メタデータや圧縮の仕方により再現性が損なわれてしまいます。
次の修正パッチを適用したバージョンの mksquashfs
なら、再現性のあるシステムイメージを作成できるでしょう。
$SOURCE_DATE_EPOCH
に指定したさまざまな形式のタイムスタンプに対応する: https://github.com/squashfskit/squashfskit/commit/0ab12a8585373be2de5129e14d979c62e7a90d82- コンテンツのタイムスタンプを
$SOURCE_DATE_EPOCH
で指定できる: https://github.com/squashfskit/squashfskit/commit/32a07d4156a281084c90a4b78affc8b0b32a26fc frag_deflator_thread
を削除する: https://github.com/squashfskit/squashfskit/commit/afc0c76a170bd17cbd29bbec6ae6d2227e398570
ルートファイルシステム
ビルド中に作成し、SquashFS などの形式で圧縮したルートファイルシステムをシステムイメージに含める場合がよくあります。
不要ファイルを除外する
ルートファイルシステムのイメージを作成するとき、いくつかのファイルを空にしたり除外するのは簡単です(サイズを最適化したい場合もあるし、不要な場合もあるでしょう)。
例えば Tails プロジェクトでは次のようなツールを使用しています。
- https://gitlab.tails.boum.org/tails/tails/-/blob/stable/config/chroot_local-includes/usr/share/tails/build/mksquashfs-excludes
- https://gitlab.tails.boum.org/tails/tails/-/blob/stable/config/chroot_local-hooks/99-zzzzzz_reproducible-builds-post-processing
注意:結果を予測するのが難しくなる可能性があります。 例えば Tails プロジェクトではもっとたくさんのファイル(fontconfig のキャッシュなど)を削除しようとしたのですが、予期せぬ結果をもたらしたり、(ビルド時間が?)遅くなってしまうため、最終的に妥協したところもあるのです。
ファイルのメタデータ
システムイメージのビルドプロセスでは、ファイルを作ったり更新したりする場合がよくあります。 そうすると、ビルドを実行したときの状態に依存するメタデータを生成してしまいます。
この問題を解決する上手い方法の1つが、ルートファイルシステム中の全てのファイルの最終変更日時(mtime
)を $SOURCE_DATE_EPOCH
に揃える方法です。
ビルド時に作成・更新するファイル
dpkg や RPM のようなパッケージマネージャーは、postinst
スクリプト(後処理スクリプト)や、パッケージを展開した後に実行するトリガースクリプトに対応しています。
具体的には、キャッシュや索引を生成、更新するようなものです。
これらは潜在的に再現性を損なう可能性があります。
この問題を解決する方法の1つとして考えられるのは、これらのスクリプトが行う全ての処理を後回しに(例えば初回起動時に)することです。
これらのスクリプトが再現性のある方法でファイルを生成、更新できるようにする方法も考えられます。 根本原因を解消できるし、全てのプロジェクトに共通する方法でもあります。
/etc/kernel/postinst.d/apt-auto-removal
: https://salsa.debian.org/apt-team/apt/commit/a9b56a0/etc/shadow
: https://github.com/shadow-maint/shadow/pull/71- fontconfig cache: https://bugs.debian.org/864082, https://bugs.debian.org/863427
- gdk-pixbuf’s
loaders.cache
: https://bugzilla.gnome.org/show_bug.cgi?id=783592, https://bugs.debian.org/875704 giomodule.cache
: https://bugzilla.gnome.org/show_bug.cgi?id=786983- GTK+
immodules.cache
: https://bugzilla.gnome.org/show_bug.cgi?id=786528 /usr/share/applications/mimeinfo.cache
: https://bugs.freedesktop.org/show_bug.cgi?id=102320/var/cache/cracklib/src-dicts
: https://bugs.debian.org/865623/var/lib/gconf/defaults/%gconf-tree-*.xml
: https://bugzilla.gnome.org/show_bug.cgi?id=784738, https://bugs.debian.org/867848.
最終的にこれらのファイルのタイムスタンプを strip-nondeterminism
で正規化する方法も考えられます。
gettext
GNU gettext の使用する POT/PO/MO ファイルの扱いは悩ましい問題です。 例えば次のような方法が考えられます。
- POT ファイルを本当に必要なときだけ更新するようにします。例えば、POT-Creation-Date フィールドだけの変更なら、ファイル自体を変更する必要はありません。
- コメントだけ(あるいは行番号)の変更なら PO ファイルを(MO ファイルも)更新しません。 https://gitlab.tails.boum.org/tails/tails/-/blob/stable/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh
Introduction
Achieve deterministic builds
- SOURCE_DATE_EPOCH
- 確実なビルドシステム(Deterministic build systems)
- 揮発性のある入力データは消える場合がある(Volatile inputs can disappear)
- 入力データの順序を固定する(Stable order for inputs)
- 値を初期化する(Value initialization)
- バージョン情報(Version information)
- タイムスタンプ(Timestamps)
- タイムゾーン(Timezones)
- ロケール(Locales)
- アーカイブのメタデータ(Archive metadata)
- 出力データの順序を固定する(Stable order for outputs)
- 無作為性(Randomness)
- ビルド時のファイルシステムパス(Build path)
- システムイメージ(System images)
- JVM
Define a build environment
- ビルド環境に含む要素(What's in a build environment?)
- ビルド環境を記録する(Recording the build environment)
- ビルド環境の定義における戦略(Definition strategies)
- Proprietary operating systems
Distribute the environment
Verification
Specifications
Follow us on Twitter @ReproBuilds, Mastodon @reproducible_builds@fosstodon.org & Reddit and please consider making a donation. • Content licensed under CC BY-SA 4.0, style licensed under MIT. Templates and styles based on the Tor Styleguide. Logos and trademarks belong to their respective owners. • Patches welcome via our Git repository (instructions) or via our mailing list. • Full contact info