poisoned pipeline executionとは何か? secretを持って信頼できないコードを実行する
poisoned pipeline execution (PPE) とは、誰かがCIパイプラインに自分の制御するコードを、パイプラインが持つすべてのsecretと権限で実行させる攻撃です。
PPEは最も鋭いCI攻撃の1つです。パイプライン自身の信頼を悪用するからです。攻撃者はあなたのサーバーに侵入するのではなく、あなたのパイプラインに彼らのコードを代わりに実行させます。それはあなたのsecret、deploy key、署名IDを伴います。最も一般的な入口は、信頼できないコントリビューターからのpull requestです。
PPEの仕組み
攻撃者は、パイプラインファイル、build script、あるいはパイプラインが読み込むconfigを編集することでパイプラインが実行する内容に影響を与え、その変更がsecretを付けて実行されるように仕向けます。パイプラインは自身の設定を信頼し、敵対的なコードを従順に実行します。
直接的、間接的、パブリックなPPE
- 直接的: 攻撃者がパイプライン定義そのものを編集する。
- 間接的: パイプラインが実行するもの (script、Makefile) を編集する。
- パブリック: fork pull requestが特権的なworkflowをトリガーする。
fork pull requestの罠
古典的なパブリックPPE: あるworkflowがsecretへのアクセスを持ってpull requestで実行されます。外部のコントリビューターが、buildを変更してsecretを自分のサーバーにダンプするPRを開きます。パイプラインは、誰かがレビューする前にPRのコードを実行します。pull_request_targetのようなトリガーはここで悪名高いです。
PPEの防止
信頼できないコードをsecretと共に実行しないでください。fork PRのworkflowからsecretを差し控え、外部からの貢献に対する特権的な実行の前に承認を要求し、パイプラインとbuildのファイルをレビューが必要な保護されたコードとして扱い、actionを信頼できるバージョンにpinしてください。
着地したPPEの封じ込め
多層防御は、防止が失敗しうると想定します。least privilegeのtoken、エフェメラルな認証情報、egressフィルタリング、分離されたランナーによって、成功したPPEでさえ見つけられるsecretはわずかで、それをどこにも送れず、存続もできません。爆発半径は1つの使い捨てjobの中に留まります。
重要なポイント
- poisoned pipeline executionは、攻撃者のコードをパイプラインの権限で実行します。
- secretを取得するfork pull requestが、古典的なパブリックPPEのベクターです。
- 信頼できない実行からsecretを差し控え、least privilegeと分離で封じ込めます。