サプライチェーン
ソフトウェアサプライチェーンセキュリティのベストプラクティス
最初のコミットからリリース後の対応までを網羅した実践的なチェックリストです。各セクションは、最小の手間で最大の保護が得られる手順から始まるため、どこで止めても以前より良い状態になります。
更新日
ソース
- 強力な認証を必須にする。すべてのコードホスティングアカウントで多要素認証を使います。
- メインブランチを保護する。マージ前のレビューを必須とし、誰もリリースブランチに直接プッシュできないようにします。
- シークレットをコードに含めない。プッシュのたびにスキャンし、露出したものはすべてローテーションします。
- ワークフローファイルをコードとして扱う。パイプラインの変更はシークレットに届きうるため、オーナーによるレビューを必須にします。
依存関係
-
ロックファイルをコミットし、そこからインストールする。
npm ciやそれに相当するコマンドを使い、ビルドが誤って新しいバージョンを取り込まないようにします。ロックファイルには限界がありますが、出発点となります。 - 新しいバージョンに待機期間を設ける。悪意あるリリースは公開後まもなく発見されることが多いため、公開当日にバージョンを採用しないことで、発見される時間を確保できます。
- インストールスクリプトを制限する。可能な限り無効にします。インストール時に実行されるスクリプトは、npmワームが拡散する経路です。
- 新しい依存関係を精査する。名前にタイポスクワッティングがないかを確認し、メンテナンス状況と普及度を確認します。OpenSSF Scorecardでその一部を自動化できます。
- 社内パッケージ名を保護する。スコープとレジストリ設定を使い、依存関係の混乱(dependency confusion)によって公開パッケージが社内パッケージに取って代わることのないようにします。
- 不要なものを削る。依存関係はどれも、監視すべきものが1つ増えることを意味します。
ビルドとCI/CD
- GitHub Actionsを完全なコミットハッシュで固定する。tj-actionsの侵害が示したように、タグは付け替えられる可能性があります。
- 各ジョブができることを制限する。ワークフローのトークンには必要最小限の権限を与え、長期間有効なシークレットの代わりに短期間の認証情報を使います。
- 外向きの通信を制限する。ビルドは既知のソースからパッケージを取得し、既知の場所に公開します。それ以外をすべてブロックすれば、盗まれたシークレットには行き場がなくなります。GitHub Actionsのエグレスポリシーをご覧ください。
- 各ジョブを新しい隔離環境で実行する。あるジョブから次のジョブに何も引き継がれてはならず、外部コントリビューターのプルリクエストからはなおさらです。
- キャッシュを入力として扱う。汚染されたキャッシュはビルド間で残り続け、そこから復元されるものは見落とされがちです。GitHub Actionsのキャッシュをご覧ください。
完全なリストは、CI/CDパイプラインセキュリティチェックリストとランナーセキュリティの比較をご覧ください。
リリース
- すべてのリリースについて、ビルドからSBOMを生成する。成果物と一緒に保管します。SBOMのベストプラクティスをご覧ください。
- 成果物に署名し、来歴を公開する。利用者はリリースの出どころを確認できるようになります。レベルはSLSAで定められています。
- リリースはCIでのみビルドする。ノートPCから作られたリリースには、信頼できる記録の裏付けがありません。
- テストから本番まで1つの成果物を使う。再ビルドするのではなく、テストしたものを昇格させることで、記録が正確なまま保たれます。
リリース後
- 出荷したものを監視する。サポート中のリリースのSBOMを、新たな脆弱性に照らしてチェックし続けます。
- CVSS以外の指標も使って優先順位を付ける。CISA KEV、EPSS、そして文脈を活用します。脆弱性の優先順位付けの方法をご覧ください。
- どれだけの期間さらされていたかを把握する。ビルド履歴から、どのリリースにいつからそのパッケージが含まれていたかがわかります。
- 必要になる前に計画を立てる。誰がトリアージし、誰が修正し、誰が顧客と連絡を取るかを決めておきます。脆弱性管理のライフサイクルをご覧ください。
- 現実的なシナリオで訓練する。特定のパッケージを含むすべてのリリースを見つけるのにどれだけかかるかを確認してください。答えが「数日」なら、そこから始めましょう。
まず何から始めるか
| 時期 | 実施すること |
|---|---|
| 今週 | 多要素認証、CIでのロックファイル利用、GitHub Actionsの固定、最小権限のワークフロートークン |
| 今月 | すべてのリリースビルドからのSBOM、担当者付きの依存関係アラート、シークレットスキャン |
| 今四半期 | ビルドの外向き通信ルール、出荷したリリースの監視、テスト済みの対応計画 |
| その次 | 署名付きの来歴、SLSAまたはNIST SSDFの対応範囲の正式なレビュー、サプライヤーのSBOM |
CRACIが担う項目
CRACIは、ビルドとそれ以降のすべてをカバーします。GitHub Actionsのランナーとして、各ジョブをそれぞれ隔離された仮想マシンで実行し、ジョブが取得したすべてのパッケージをSBOMに記録し、CIキャッシュから復元されたパッケージを明示し、ビルドに不要な接続をブロックするエグレスポリシーを適用します。さらに出荷したものをチェックし続け、どのビルドに脆弱なパッケージが含まれていたかを示し、ポリシーゲートでビルドをブロックできます。
それ以外は他のツールの役割です。CRACIはソースコードやシークレットのスキャンを行わず、挙動から新たな悪意あるパッケージを検出することもなく、SBOMや来歴への署名も行いません。それぞれの隙間を埋めるものについては、ソフトウェアサプライチェーンセキュリティツールの比較をご覧ください。
ソフトウェアサプライチェーンセキュリティのベストプラクティス:よくあるご質問
ソフトウェアサプライチェーンはどのように保護すればよいですか?
すべてのリリースビルドのSBOMで出荷するものを把握し、ロックファイルと精査で取り込むものを管理し、シークレットと外向きの通信を制限してビルドを保護し、リリースしたものを監視し続けます。
小規模なチームはまず何をすべきですか?
多要素認証を有効にし、CIではロックファイルからインストールし、GitHub Actionsをコミットハッシュで固定し、ワークフローのトークンに必要最小限の権限を与えます。これらは数日で実施でき、よくある攻撃経路を塞げます。
悪意あるパッケージはどのように防げますか?
1つの手順だけでは防げません。新しいバージョンの採用を遅らせ、インストールスクリプトを制限し、新しい依存関係を精査します。ビルドからの外向きの通信を制限すれば、悪意あるパッケージがすり抜けた場合の被害を抑えられます。
なぜGitHub Actionsをコミットハッシュで固定するのですか?
バージョンタグは別のコードに付け替えられる可能性があるためです。完全なコミットハッシュは常に同じコードを指すため、乗っ取られたタグがパイプラインに届くことはありません。
サプライチェーンはどのくらいの頻度で見直すべきですか?
監視は継続的に行うべきです。依存関係のポリシー、ワークフローの権限、対応計画は少なくとも年に1回、そして自社のスタックでインシデントが起きた後に見直してください。