サプライチェーン攻撃は「if」ではなく「when」の問題
- 年のxz utilsバックドア事件(CVE-2024-3094)は、オープンソースのサプライチェーンセキュリティに対する認識を根本的に変えた。2年以上にわたって信頼を築いた貢献者が、xz圧縮ライブラリにバックドアを仕込み、sshd経由のリモートコード実行を可能にした。偶然の発見がなければ、世界中のLinuxサーバーが影響を受けていた。
これは特異な事件ではない。npm、PyPI、GitHub Actionsでの悪意あるパッケージ公開、依存関係のtyposquatting(類似名パッケージによるなりすまし)、CI/CDパイプラインへの侵入—サプライチェーン攻撃は年々増加している。KGAではこれらの脅威に体系的に対処するため、2024年後半からサプライチェーンセキュリティの強化に取り組んだ。
SBOM: ソフトウェアの部品表
SBOM(Software Bill of Materials)は、ソフトウェアに含まれるすべての依存関係のリストだ。食品の原材料表示と同じように、ソフトウェアの構成要素を明示する。
KGAではSyft(Anchore製のOSSツール)でSBOMを自動生成している。CI/CDパイプラインでDockerイメージのビルド後にSyftを実行し、SPDX形式またはCycloneDX形式のSBOMを生成。生成されたSBOMはartifactとして保存し、デプロイ時にGrypeで脆弱性スキャンを実行する。
SBOM生成で重要なのは、直接依存だけでなく推移的依存(依存の依存の依存...)も含めることだ。Node.jsプロジェクトでは、package.jsonに記載された直接依存50個に対して、node_modulesには実際に1,200個以上のパッケージが含まれることが珍しくない。脆弱性の大半はこの推移的依存に潜んでいる。
Sigstore: アーティファクトの署名と検証
Sigstoreは、ソフトウェアアーティファクト(コンテナイメージ、バイナリ、SBOM等)の署名と検証のためのオープンソースプロジェクトだ。従来のPGP署名と異なり、鍵管理が不要なkeyless signingをサポートする。
KGAではCosign(Sigstoreのツール)でDockerイメージに署名している。CI/CDパイプラインでイメージをビルド・プッシュした後、cosign signでイメージに署名。デプロイ時にcosign verifyで署名を検証し、未署名または改ざんされたイメージのデプロイを拒否する。
Kubernetes環境では、admission controller(Kyverno)でイメージ署名の検証を強制している。署名が検証できないイメージのPod作成を拒否するポリシーを設定し、未署名イメージの本番デプロイを物理的に不可能にした。
SLSAフレームワーク: サプライチェーンの信頼性レベル
SLSA(Supply-chain Levels for Software Artifacts、スルサと読む)は、GoogleのBinary Authorizationの経験を基にしたサプライチェーンセキュリティのフレームワークだ。Level 1からLevel 4までの4段階で、ビルドプロセスの信頼性を評価する。
Level 1: ビルドプロセスの文書化。何がどのようにビルドされたかの記録(provenance)がある。Level 2: ホスティングされたビルドサービスの使用。ビルドがCI/CD上で実行され、手元のマシンでのビルドではない。Level 3: ビルドプラットフォームの強化。ビルド環境のセキュリティが保証され、provenance が改ざんされていないことを検証できる。Level 4: 2名以上のレビュー、hermetic build(外部からの入力なし)。
KGAの現状はLevel 3を達成している。GitHub Actionsのattestationsアクションでprovenance情報を自動生成し、SigstoreのRekorに透明性ログとして記録。ビルドの再現性をDockerのマルチステージビルドとピン留めされた依存関係で確保している。
依存関係の管理戦略
KGAの依存関係管理は以下の原則に基づく。ロックファイルの厳格な管理: package-lock.json、poetry.lock、go.sumをgit管理し、CI/CDでロックファイルと実際のインストール結果の一致を検証。
依存関係の定期的な監査: Renovatebot(Dependabot代替)で依存関係の更新PRを自動生成。週次でセキュリティアップデートのみを自動マージし、機能アップデートは手動レビュー。
直接依存の最小化: 標準ライブラリで実現可能な機能にサードパーティパッケージを使わない。left-pad事件の教訓だ。KGAのNode.jsプロジェクトでは、直接依存を30個以下に制限するガイドラインを設けている。
privateレジストリの活用: npm、PyPIのパッケージをGitHub Packages経由でプロキシし、承認済みパッケージのみを使用可能にする。typosquattingや悪意あるパッケージの混入を防止。
実際のインシデント分析
KGAが2024年に検知したサプライチェーン関連のインシデントを2つ共有する。
インシデント1: あるクライアントプロジェクトでDependabotが生成したPRに、正規のパッケージ更新に偽装した悪意あるpostinstallスクリプトが含まれていた。スクリプトは環境変数(APIキー等)を外部サーバーに送信する内容だった。npm auditでは検出されず、コードレビューで発見。以降、npm install時のpostinstallスクリプトの実行を--ignore-scriptsで禁止し、必要なスクリプトのみallowlistで許可する運用に変更した。
インシデント2: GitHub Actionsのサードパーティアクション(600 star以上の人気アクション)のメジャーバージョンタグ(@v3)が、悪意あるコードを含むコミットに付け替えられた。タグではなくコミットSHAで固定するルールを以前から徹底していたため、KGAへの影響はなかった。
ゼロトラストの原則
サプライチェーンセキュリティの根底にあるのは「何も信頼しない」というゼロトラストの原則だ。オープンソースのメンテナ、CI/CDプラットフォーム、パッケージレジストリ、自チームのビルド環境ですら、それぞれが侵害される可能性を前提に防御を設計する。コストと労力はかかるが、一度のサプライチェーン侵害で企業の信頼が崩壊するリスクを考えれば、この投資は正当化される。