世界を動かす技術を、日本語で。

最も単純な方法でGitHub Actionsのポリシーを回避する

概要

  • GitHub Actions のポリシー機能は、アクションや再利用ワークフローの利用制限を目的とした仕組み
  • しかし、この仕組みには 簡単に回避できる脆弱性 が存在
  • GitHub側はこれをセキュリティ問題と認識していない が、筆者は問題視
  • 回避方法やその影響、対応策について詳細に解説
  • セキュリティ境界の誤認リスクがあるため 注意喚起

GitHub Actionsのポリシー機能とその回避

  • GitHub Actions はGitHubが提供する CI/CDサービス
  • ユーザーは ワークフロー内で実行するアクションや再利用ワークフロー の信頼性を十分に確認する必要
  • アクションは Actions Marketplace などから取得
  • 人気や活動状況、所有者の信頼性などで判断するが、 これらはあくまでヒューリスティック
  • 有名なアクションでも サプライチェーン攻撃 のリスク
  • 大規模なCI/CD構成では 管理が困難、未審査のアクション混入リスク

ポリシー機能の内容

  • Actions policies で利用できるアクション/ワークフローを 組織・リポジトリ単位 で制限可能
  • 設定例:OWNER/REPOSITORY@TAG-OR-SHA 形式で限定
    • 例: actions/javascript-action@v1.0.1
  • ワイルドカードカンマ区切り で複数指定も可能
  • 同一組織内のみ許可 などのプリセットも用意

ポリシーの回避方法

  • uses: で指定するアクションは、本来リモートリポジトリを参照

  • しかし、 ローカルパス(例: uses: ./) も指定可能

  • ワークフロー内で git clone 等でアクションリポジトリをローカルに落とし、 uses: ./tmp/checkout のように実行すれば ポリシーを回避 可能

  • 実際の例:

    - run: |
        mkdir -p ./tmp
        git clone https://github.com/actions/checkout.git ./tmp/checkout
    - uses: ./tmp/checkout
    
  • この方法で 制限を簡単に突破 できる現状

対応策とその課題

  • GitHub側の対策案
    • ローカルパス指定(uses: ./)も ポリシー対象 とし、許可されない場合は 拒否
    • これにより バイパス封じ が可能
    • ただし、 既存ユーザーの一部に影響 が出る可能性
  • もしくは、 現仕様の制限事項として公式ドキュメントで明示
    • 利用者が リスクを正しく認識 できるようにする

なぜこの問題が重要か

  • 形だけのポリシー は、セキュリティ境界として 誤認されやすい
  • 実際には 回避可能な仕組み であるにも関わらず、 安全だと誤信 されることでリスク増大
  • 多くの場合、 開発者が業務上仕方なくバイパス するケースが多い
  • GitHub側は修正または明確な注意喚起 を行うべき

まとめ

  • GitHub Actionsのポリシー機能 には 簡単な回避手段 が存在
  • セキュリティ境界の誤認 が組織・プロジェクトにリスクをもたらす
  • GitHub側の対応 (修正またはドキュメント明記)が望まれる
  • 利用者は 現状のリスクを十分認識 し、運用設計を行う必要

Hackerたちの意見

コードの変更でポリシーを「回避」できるっていうのは、そんなに深刻なことじゃない気がする。CI/CDのワークフローの変更を見直してないなら、もう希望はないよ。コードが流出したり、秘密が盗まれたりする可能性もあるからね。

単にレビューの問題じゃなくて、設定によっては、CIがプッシュやPR作成でトリガーされる場合、誰も変更を確認する前にこの回避策が実行されることもあるんだ。

この投稿のポイントは、実際のレビューは様々だってこと。大きな組織なら、コード自体の変更をレビューすべきだけど、多くの組織はCI/CDの変更で行われたすべてのアクション(そのバージョンも)を追跡してないと思う。それがポリシーの役割であり、回避策が危険な理由なんだ。直感的に言うと、ジュニアエンジニアを助けるためのブランチ保護や秘密のプッシュポリシーの価値が理解できるなら、CI/CDポリシーも同じように重要だよ。

「私たちの組織が公開したアクションと再利用可能なワークフローのみを許可します」と「私たちの組織が公開したアクションと再利用可能なワークフロー、または外部ソースから手動でダウンロードしたもののみを許可します」は、全然違うポリシーだよね。

これは「使えない安全なシステムを作ると、ユーザーはそれを使える不安全なものに変えてしまう」という典型的な例だね。誰かがこういうコントロールを積極的に無効化しているなら、そのコントロールはガードレールから線路の上のログに変わってしまったってことだ。AppLockerとかと同じような感じだね。ほとんどの人が使うべきだって言うけど、実際に使ってる人はほとんどいない。なぜなら、「受け入れ可能なソフトウェア」が何かを理解するだけでもものすごい労力がかかるから。

「使えない安全なシステム」の暗黙の解決策は、チェックアウトアクションを自分の組織にフォークして、そこで参照することだね。

ITセキュリティのバブルの外にいる人は、AppLockerを使うのが賢いアイデアだなんて思ってないよ。会社が従業員にどの特定のプログラムを使って仕事をするかを指示するのは、あまりにも過剰なマイクロマネジメントだと思う。

特定のリポジトリを手動でチェックアウトするだけじゃなくて、サブモジュールがあって再帰的にチェックアウトすると、予想もしなかった場所から他のセキュリティの悪夢を引き込むこともできるんだ。とはいえ、それを実行するのはかなり複雑な攻撃になるだろうけど、妥協されたワークフローの連鎖って感じだね、ハハ。

だから、できるだけ非公式なアクションは使わないようにして、アクションのバージョンは必ず設定するようにしてる。以前、契約者がランダムなアクションを使ってファイルをサーバーにSSHで送信して、バージョンとしてmasterを参照してたことがあったんだ。まず、SSHでファイルをアップロードしてコマンドを実行するのはそんなに難しくないし、アクションの所有者が簡単にプライベートキーや情報を別のサーバーに保存するコードを追加できるからね。「回避」についてはちょっと混乱してるけど、敵がワークフローファイルを編集するためにはリポジトリへのプッシュアクセスが必要じゃないの?だから、強化すべき部分は、間違った人がリポジトリにファイルをプッシュできないようにすることなんだよね。公開リポジトリでは、PRが作成されたときに実行されるワークフローのセクションでそれをやられたら問題になるかもしれない。プライベートリポジトリでは、アクセスを与える相手には気をつけるべきだね。

「だから、できるだけ非公式なアクションを使わないようにして、常にアクションのバージョンを設定するようにしてる。これはいいプラクティスだね。バージョン(タグ)を固定するだけでは不十分だと思う。tj-actions/changed-filesイベントで学んだように、コミットSHAを固定すべきだよ。」 [0] GitHubは公式ドキュメントでもこれを述べてるね。[1] > 「アクションを完全なコミットSHAに固定する」 > 「アクションをタグに固定するのは、クリエイターを信頼している場合のみ」 [0] https://www.stepsecurity.io/blog/harden-runner-detection-tj-... [1] https://docs.github.com/en/actions/security-for-github-actio...

「バイパス」についてちょっと混乱してるんだけど、敵がワークフローファイルを編集するにはリポジトリへのプッシュアクセスが必要じゃない?だから、強化が必要なのは、間違った人がリポジトリにファイルをプッシュできないようにすることだよね?私もそう理解してる。でも、会社全体のポリシー(アクションに関して)が、悪意のある開発者や不注意な開発者から会社を守るためのセキュリティ対策として誤解されたり使われたりするかもしれない。だから、その振る舞いを文書化したり強調したりすることで、DevOpsの人たちが誤った安心感を持たないようにするのが大事だと思う。それ以上はないかな。

ワークフローやスクリプトを設定しているときに、全く同じことを考えてた。いつ何が許可されるかの不当で長引く制限に悩まされてるからね。何かをやり方を調べると、10年以上前に開かれた問題がトップに出てくると、ほんとに沈む気持ちになるよね…。ローカルホストのGitLabで仕事してたから、GitHubを使って何か役立つことをしようとすると特に辛い。ドキュメントを何度か試してみたけど、キャッシュの設定がうまくいかなくて諦めちゃった。だって、金払ってるわけじゃないし。CodeQLの推奨設定が、軽い使用で2600分以上もアクションを消費してたのにはびっくりした。数週間の重い利用で得た合計のほぼ倍だよ。これ、誰が払ってるの?

Hacker Newsで議論の続きを見る