堅牢・安全・信頼の「Chainguard」を試してみた #chainguard #docker #python

はじめに
Chainguardは、ソフトウェアサプライチェーンの安全性を高めるために開発された、セキュリティ重視のコンテナベースイメージおよびソフトウェアライブラリです。
Docker Hubの通常のalpineイメージやdebianイメージを見ると、脆弱性を持ったままです。これらの影響が低いとしてもTrivyのようなセキュリティスキャナは通知をします。その都度人力で、通知されたCVEを見て影響度を確認し、修正を行う・無視設定するなどは大変です。
Chainguardのコンテナイメージは既知の脆弱性(CVE)がゼロであることをうたっています(Chainguard delivers the industry’s largest zero-CVE)。
一方、ベースイメージをそのまま使うことはほとんどの場合ないでしょう。PythonであればPyPI、JavaScript (Node)であればnpm、JavaであればMavenといったパブリックレジストリから追加ライブラリやパッケージをインストールしてイメージを構築しているはずです。いくらベースイメージが安全であっても、ライブラリが危険であれば意味がありません。開発者になりすました攻撃者がライブラリを改竄して公開するという手口が最近頻繁に発生しています。
Chainguardはそれらのパブリックレジストリに代わり、安全なライブラリやパッケージの配布も行っています(Chainguard Libraries is a malware-free catalog of language dependencies that replaces your team’s reliance on public registries.)。
本稿ではPythonを利用したプロジェクトを対象に、Chainguardをお試しした感想を紹介します。
ベースイメージ
ChainguardではベースイメージとしてWolfiを開発・利用しています。Wolfiとはオオカミ…ではなく、世界最小のタコが由来だそうです。
一般的に、Dockerのベースイメージとしては先に上げたようにalpineイメージやdebianイメージが利用されることが多いでしょう。先に述べた通り、これらは脆弱性が含まれたままであることが多いです。
そうであってもイメージサイズが小さく、それにより相対的に脆弱性も少ないalpineが選択されることが多いかと思います。しかし、alpineが採用している標準Cライブラリであるmusl libcには、特定のライブラリがビルドできない・うまく実行できない、特定の状況でパフォーマンスが落ちる、といったトレードオフがあります。筆者もdebianベースイメージで実行していたアプリケーションをalpineベースイメージでビルドし直したところ、正常に動作しないことがありました。
では広く使われている標準CライブラリであるGNU libc (glibc)を使おうとすると、ベースイメージがdebianでサイズが大きく残っている脆弱性も数多い…というジレンマがあります。
Wolfiはイメージサイズを小さくしつつ、glibcを採用するという、両者の良いとこ取りをしています。
実際のサイズを比較してみましょう。
なお、Chainguardのイメージは 有料版のみタグ付き で利用可能です。無料版あるいは試用版の一部はChainguardのイメージは latest しかありません。
% docker image inspect --format '{{.Size}}' docker.io/chainguard/wolfi-base:latest@sha256:e161445c05b19e668cb5cc44df2f0403329fd4f0ac892794255e328e760612a1 | numfmt --to=si
17M
% docker image inspect --format '{{.Size}}' debian:trixie-slim@sha256:4e401d95de7083948053197a9c3913343cd06b706bf15eb6a0c3ccd26f436a0e | numfmt --to=si
79M
% docker image inspect --format '{{.Size}}' alpine:3.24.1@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b | numfmt --to=si
8.5M
Alpine (8.5M) < Wolfi (17M) < Debian (slim) (79M) となりました。
標準Cライブラリも確認してみましょう。libc.so* ファイルはライブラリですが直接実行も可能で、バージョン等が表示される仕組みになっています。
% docker container run --rm --entrypoint /lib/libc.so.6 docker.io/chainguard/wolfi-base:latest@sha256:e161445c05b19e668cb5cc44df2f0403329fd4f0ac892794255e328e760612a1 GNU C Library (glibc-2.43-r8) stable release version 2.43. Copyright (C) 2026 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 16.1.0. libc ABIs: UNIQUE IFUNC ABSOLUTE Minimum supported kernel: 4.9.0 For bug reporting instructions, please see: <https://www.gnu.org/software/libc/bugs.html>.
% docker container run --rm --entrypoint /lib/x86_64-linux-gnu/libc.so.6 debian:trixie-slim@sha256:4e401d95de7083948053197a9c3913343cd06b706bf15eb6a0c3ccd26f436a0e GNU C Library (Debian GLIBC 2.41-12+deb13u3) stable release version 2.41. Copyright (C) 2025 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 14.2.0. libc ABIs: UNIQUE IFUNC ABSOLUTE Minimum supported kernel: 3.2.0 For bug reporting instructions, please see: <http://www.debian.org/Bugs/>.
% docker container run --rm --entrypoint /lib/libc.musl-x86_64.so.1 alpine:3.24.1@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b musl libc (x86_64) Version 1.2.6 Dynamic Program Loader Usage: /lib/libc.musl-x86_64.so.1 [options] [--] pathname [args]
WolfiはDebianと同じくglibc、Alpineはmuslとなっています。
さらにtrivyでスキャンしてみましょう。
% docker container run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$HOME/.cache/trivy:/root/.cache/trivy" aquasec/trivy:0.71.0@sha256:016eae51fdcf989332a5404af7e8f625cd5d95d7c0907a221d080a996f556500 image --scanners vuln docker.io/chainguard/wolfi-base:latest@sha256:e161445c05b19e668cb5cc44df2f0403329fd4f0ac892794255e328e760612a1 2> /dev/null | grep Total %
% docker container run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$HOME/.cache/trivy:/root/.cache/trivy" aquasec/trivy:0.71.0@sha256:016eae51fdcf989332a5404af7e8f625cd5d95d7c0907a221d080a996f556500 image --scanners vuln debian:trixie-slim@sha256:4e401d95de7083948053197a9c3913343cd06b706bf15eb6a0c3ccd26f436a0e 2> /dev/null | grep Total Total: 147 (UNKNOWN: 36, LOW: 62, MEDIUM: 39, HIGH: 8, CRITICAL: 2)
% docker container run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$HOME/.cache/trivy:/root/.cache/trivy" aquasec/trivy:0.71.0@sha256:016eae51fdcf989332a5404af7e8f625cd5d95d7c0907a221d080a996f556500 image --scanners vuln alpine:3.24.1@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b 2> /dev/null | grep Total %
WolfiとAlpineはゼロ、Debian (slim)は147という結果になりました。
このように、Wolfiはイメージサイズを小さくしつつ、glibcを利用し、脆弱性もゼロ、というように使い勝手と安全性を両立していると言えます。
Pythonライブラリ
前述の通り、ベースイメージが安全であっても、アプリケーションを構築する際に利用するライブラリが安全でないというのは問題です。今回対象としたPythonのプロジェクトは、 pyproject.toml で明示的に依存指定しているPythonライブラリが25個、 uv.lock で実際に依存しているPythonライブラリは111個ありました。この数の安全性維持を人力で対応しようとすると途方もないことになります。
Chainguardでは、通常のPythonライブラリの配布に用いられているPyPIのパッケージを再構築・脆弱性の修正を行ったChainguard Libraries for Pythonを提供しています。
本稿執筆時点、PyPIには83万以上のプロジェクトが存在しており、さすがにそのすべてを対応するのは難しいのではないか、今回対象としたPythonプロジェクトで用いているライブラリ111個もそれなりに外れているものがあるのではないか、と思いました。しかし実際にPyPIからChainguard Libraries for Pythonに切り替えてみると、最近リリースされた1件のみが対象外でした。それでも、リクエストがあったものは自動的にライブラリに追加されるという記述があり、そのうち追加されると思われます。
なお、Chainguard Libraries for Pythonに切り替え後にtrivyをかけてみましたが、もちろんCVEはゼロでした。
まとめ
本稿ではDockerベースイメージとPythonライブラリの観点から簡単に、Chainguardの紹介を行いました。
昨今、ソフトウェアの脆弱性や侵害は、エンドユーザを狙うのではなく、開発者を狙って行われるようになってきています。たくさんのAPIキーやパスワードは開発者は手元のみならず、CI/CDといったソフトウェア開発・インフラ運用の基盤にも保存されています。開発用のソフトウェアがいつの間にか改竄され、それをダウンロードやインストールするその裏で機密情報が流出していた、ということも耳にします(参考:2026年3月Trivyサプライチェーン攻撃とDockerイメージのバージョンピニング)。これまでのように「毎晩自動的に、依存するライブラリの最新バージョンでビルド・テスト」ということも考えなく行うことができなくなっているように思います。
Chainguardを導入すれば、脆弱性はないか、改竄されていないか、といったソフトウェアサプライチェーンにおける心配事を減らしていけます。是非導入を検討してみてください。
クリエーションラインではChainguardの導入・運用の支援を行っております。お気軽にお問い合わせください。
