コンテナイメージの成分分析:ソースコードのスキャンでは見えない層
よくある戸惑い
チームが SCA を CI に組み込み、ソーススキャンは問題なし。ところがセキュリティチームがイメージスキャナを走らせると、深刻度の高い脆弱性が数十件報告される。開発側の最初の反応はたいてい「スキャナがおかしい」です。
スキャナはおかしくありません。両者が見ているものが根本的に違うのです。
イメージの中に何が入っているのか
典型的なアプリケーションイメージには、性質の異なる 3 つの層の部品が含まれます。
第 1 層:ベースイメージ(OS 層)——Dockerfile の 1 行目、FROM に書いたものです。オペレーティングシステムのユーザー空間一式を持ち込みます。glibc、openssl、bash、coreutils、パッケージマネージャそのもの。この層の部品数はアプリ依存より遥かに多いのが通常で、しかもアプリケーションの宣言ファイルには一切現れません。
第 2 層:システムパッケージ——ビルド中に apt-get install や apk add で入れたもの。curl、git、コンパイラツールチェーン、各種ランタイムライブラリ。ビルドのために入れ、削除を忘れ、本番イメージにそのまま残るという経路をたどりがちです。
第 3 層:言語依存——package.json、pom.xml、requirements.txt に宣言されているもの。この層、そしてこの層だけが、ソースレベルの SCA が見ている範囲です。
つまり「ソースはきれいなのにイメージには脆弱性がある」は矛盾ではありません。問題は、自分では書いていないが確実に動いている 2 つの層にあるのです。
ベースイメージにリスクが集中する理由
ベースイメージの問題は品質が低いことではなく、3 つの構造的要因にあります。
容量は攻撃面です。 完全な ubuntu:22.04 は数百のパッケージを伴い、その大半はアプリケーションが一度も触れないものです。それでも CVE はスキャンに現れ、説明か修正を求められます。
更新の遅れ。 FROM node:18 という書き方はバージョン固定に見えますが、タグは動きます。そしてチームがイメージを再ビルドするのは数か月に一度ということも珍しくありません。ベースイメージのセキュリティ更新は、自動的には本番環境に届きません。
継承による不可視性。 自分のイメージが他チームの中間イメージを FROM し、そのイメージがさらに別のものを FROM している。最終的な本番イメージの部品は、3 層も 4 層も上流の判断に由来することがあり、その連鎖全体を見た人は誰もいません。
統制の 3 原則
1. 精簡で保守が約束されたベースイメージを選ぶ。
distroless、公式の slim 版、alpine——選定基準は「どれが最小か」ではなく「実行要件を満たしたうえで部品が最も少なく、セキュリティ更新の頻度が明示されているのはどれか」です。パッケージが 1 つ減れば、潜在的な CVE が 1 つ減り、不要な説明が 1 回減ります。
2. イメージスキャンを CI へ、ソーススキャンと並行して置く。
両者は代替ではなく補完です。ソース SCA は依存導入の時点で止め(早く、修正コストが低い)、イメージスキャンは成果物の層で受け止めます(広く、宣言していない部分まで覆う)。理想的なゲートの位置はイメージのビルド後、レジストリへのプッシュ前です。この時点ならまだ再ビルドできますが、プッシュ後に見つければロールバックになります。
3. ベースイメージのバージョンを全社で一元管理する。
各チームが個別に FROM を選ぶのではなく、会社としてセキュリティ審査を経た基準イメージ群を維持し、各チームはそこから派生させます。効果が最も明確に出るのは脆弱性発生時です。基準を一度直せば下流は再ビルドするだけで済み、20 チームがそれぞれ調査する事態を避けられます。
SBOM はどの層まで覆うべきか
コンテナ化された製品の SBOM を顧客や規制当局に提出する場合、言語依存だけの出力では不十分です。受け取る側が期待しているのは「このイメージに何が入っているか」であって、「このアプリが何を宣言したか」ではありません。
完全なコンテナ SBOM には、ベースイメージの識別子とダイジェスト、システムパッケージの一覧(バージョン付き)、言語依存ツリー、そして各層の出所情報が含まれるべきです。幸いこれは自動化できます。CI でビルド済みイメージに対して成分分析を行い、SPDX または CycloneDX を出力し、イメージとともに公開すればよいのです。
注意すべきは層の追跡可能性です。同じ部品が複数の層に現れることがあり、出所も修正経路も異なります。ベースイメージの openssl はベースイメージの差し替えで直し、アプリ依存のものは宣言の変更で直します。SBOM が出所を区別していなければ、受け取った側は誰に修正を求めればよいか判断できません。
「スキャン通過」から「成分が分かっている」へ
コンテナ化は成果物を「1 つの jar」から「実行環境まるごと」へと変え、ソフトウェアサプライチェーンの境界を 2 層分下へ広げました。成分透明性の要求も、それに合わせて下へ降りる必要があります。
強調しておきたいのは、これがセキュリティだけの問題ではなくライセンスの問題でもあるという点です。ベースイメージに含まれる GPL 部品や、システムパッケージのライセンス義務も、イメージの配布とともに伝播します。アプリ依存だけを見るコンプライアンス監査は、コンテナ化された配布の前では不完全です。
---
関連記事:SBOM フィールド実務ガイド · CI パイプラインでの SCA ゲート設定 · CleanSource SCA のコンテナイメージ分析
