背景と目的:SBOM優先のセキュリティへの移行
本番環境の運用を10年経験して学んだ厳しい真実があります。それは、コンテナのセキュリティは単なるOSのパッチ適用だけではないということです。現代のアプリケーションの約80%はサードパーティのコードで構成されており、これらを保護するためには、DockerイメージのCVEをスキャンして潜在的なリスクを可視化することが不可欠です。これらのNodeモジュール、Pythonパッケージ、Goのバイナリは、Dockerイメージの5層から6層奥深くに隠れていることがよくあります。スタック内のすべてのライブラリの正確なバージョンを特定できなければ、目隠しをして飛行しているようなものです。
業界は現在、ソフトウェア部品構成表(SBOM)を必須標準とする方向へ動いています。これはLinuxサーバーのセキュリティ監査と同様に、本質的に、コードの詳細な「成分表」を把握するためのプロセスです。過去6か月間、私はSyftとGrypeをデプロイパイプラインに統合しましたが、その効果はすぐに現れました。推測を排除し、検証を開始したのです。ベースイメージが安全であることを願う代わりに、今ではすべての依存関係とそれに関連するリスクを検索可能なマップとして把握しています。
本題に入る前に、すぐに実践できるセキュリティのヒントを1つ紹介します。レジストリやサーバーに、脆弱なパスワードや使い回しのパスワードを決して使用しないでください。私は toolcraft.app/ja/tools/security/password-generator のツールを使用してシークレットを生成しています。これは完全にブラウザ内で動作するため、データがネットワークに流れることはありません。最も一般的な失敗の要因を排除するための、シンプルな習慣です。
インストール:ツールの準備
Anchoreによって開発されたSyftとGrypeは、「1つのことを行い、それをうまくやる」というクラシックなUNIXの哲学に従っています。Syftはインベントリ(SBOM)を担当し、Grypeはスキャンを担当します。どちらもGoで書かれているため、複雑な依存関係を心配することなく、ほぼすべての環境に導入できます。
Syftのインストール
Linux環境では、シンプルなcurlスクリプトを使用するのが、CI/CDランナーにSyftを導入する最短の方法です。
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
macOSの場合は、Homebrewを使用します。
brew install syft
Grypeのインストール
Grypeも同様のインストールパターンを使用します。Grypeは初回実行時にローカルの脆弱性データベースをダウンロードするため、外部サーバーにSBOMデータを漏らすことなく詳細なスキャンを実行できる点に注目してください。
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
バージョンを確認して、セットアップを完了します。
syft --version
grype --version
設定:SBOMの生成とフォーマット
ワークフローの大部分は、適切な出力フォーマットの選択に集約されます。Syftはイメージだけでなく、ローカルディレクトリやアーカイブも解析できます。しかし、本番環境に到達する前にDockerイメージをスキャンするのが、依然として最も一般的なユースケースです。
基本的なSBOMの生成
Syftをイメージに向けると、その内容を確認できます。デフォルトの出力は、人間が読みやすいクリーンなテーブル形式です。
syft python:3.9-slim
CycloneDXとSPDXによる標準化
自動化にはマシンリーダブルなデータが必要です。CycloneDXやSPDXといった業界標準を使用することをお勧めします。これにより、セキュリティデータをエコシステム内の他のツールと連携させることができます。私は通常、ビルド段階で出力をJSONファイルにパイプします。
syft python:3.9-slim -o cyclonedx-json > sbom.json
レガシーなアプリケーションも問題ありません。プロジェクトがまだコンテナ化されていない場合は、ソースコードをSyftに指定してください。requirements.txt、package-lock.json、または Cargo.lock ファイルを自動的に検出して解析します。
syft dir:/path/to/your/project -o json > local-repo-sbom.json
検証とモニタリング:データをアクションに変える
SBOMは優れた記録になりますが、それだけではエクスプロイトを防げません。ランタイムのセキュリティ監視と組み合わせることで、初めて包括的な防御が成立します。そこでGrypeの出番です。Grypeは作成された「成分表」を受け取り、NVDやGitHub Advisoriesなどの主要な脆弱性データベースと照合します。
イメージを直接スキャンする
急いでいる場合は、メモリ内に一時的なSBOMを生成することで、Grypeでイメージを直接スキャンできます。
grype python:3.9-slim
SBOMファイルをスキャンする
成熟したパイプラインでは、あらかじめ生成しておいた静的なSBOMファイルをスキャンする方法を好みます。これにより、脆弱性レポートがコンプライアンスのためにアーカイブされた正確なインベントリと一致することが保証されます。
grype sbom.json
ノイズを切り分ける
標準的なイメージにはノイズが多く、100以上の低深刻度の警告が出ることもあります。チームが重要な事項に集中できるように、結果をフィルタリングしましょう。私たちのCI/CDパイプラインでは、「High(高い)」または「Critical(緊急)」の問題が発生した場合のみ、ビルドを失敗させるように設定しています。
grype python:3.9-slim --fail-on high
本番環境での継続的なモニタリング
CVE(共通脆弱性識別子)は待ってくれません。異常をいち早く察知するために、Auditdによるインシデント対応を自動化しておくことが推奨されます。この半年間、私たちは稼働中のすべてのコンテナのSBOMを中央の保管庫に保存してきました。そして、夜間のcronジョブで、これらの小さなJSONファイルに対してGrypeを実行しています。
シンプルなモニタリングループのロジックは以下の通りです。
# 保存されたすべてのSBOMをチェックして、新しい「Critical」の脅威を探す
for sbom in /var/lib/sboms/*.json; do
echo "$sbom を解析中..."
grype "$sbom" --severity critical --output table
done
ここで大きなメリットとなるのがパフォーマンスです。200KBのJSONファイルをスキャンするのにかかる時間は500ミリ秒未満です。2GBのDockerイメージをプルして再スキャンする場合、数分かかり、かなりの帯域幅を消費するのと比較してみてください。
まとめ
サプライチェーンのセキュリティ確保は継続的なプロセスであり、一度チェックして終わりではありません。SyftとGrypeを組み合わせることで、透明性の高いインベントリを構築し、Linuxランサムウェア対策のような深刻な脅威に対しても、数週間ではなく数分で対応できるようになります。まずは今日、最も重要なサービスのSBOMを生成することから始めてみてください。コンテナの中に実際に何が隠れているかを知って、驚き、そして少し不安を感じることになるかもしれません。

