テックブログ

GitHub Actionsのシークレット漏えい対策:禁止パターンと代替手段

GitHub Actionsのシークレット漏えい対策:禁止パターンと代替手段

CIのシークレット漏えいは、GitHub Actionsそのものが危険というより、PRやフォーク経由で実行されるワークフロー、ログ出力、artifact保存、広すぎる権限設定が重なることで起きやすくなります。漏えいすると、クラウドやレジストリ、デプロイ先、外部APIが第三者に使われ、改ざん・不正課金・データ流出・サプライチェーン汚染につながることがあります。大切なのは「Secretsを置くか置かないか」だけでなく、どのイベントで、どの権限で、どこまで使わせるかを構造で絞ることです。

関連: Trivy入門:コンテナ脆弱性スキャンをCIでゲートする最小構成

1. なぜ漏えるのか(典型パターン)

1-1. PR/フォーク起点の危険

GitHub Actionsで一番注意したいのは、外部から持ち込まれたコードがSecretsに触れる構造です。特にPRやfork起点の実行は、便利な一方で漏えい事故の入口になりやすいです。

CIは「リポジトリにあるコードを自動で実行する」仕組みなので、攻撃者に近い立場の人がワークフロー実行対象へコードを混ぜられると、そのコード経由でSecretsやトークンが使われる可能性があります。forkからのPR、外部コントリビューション、レビュー前の変更をそのまま危険なジョブへ流す構成は特に注意が必要です。つまり、問題はSecretsそのものより、「誰のコードを、どの権限で実行しているか」です。

実務では、「PRだから安全」「テストだけだから安全」と思い込みやすいですが、デプロイやレジストリログインを含むジョブへつながっていると危険です。チェック観点としては、「このイベントは信頼できるコードだけで動くか」「fork由来でも同じジョブが走るか」「Secretsが必要なジョブと不要なジョブが分かれているか」を見ると、危険パターンを見つけやすくなります。

1-2. ログ出力・artifact・環境変数の落とし穴

Secretsは、コード中で直接表示しなくても、ログ・artifact・環境変数の扱いで漏れることがあります。ここは初心者が特に見落としやすいポイントです。

たとえば、デバッグ目的で echo した値がログへ残る、ビルド時の設定ファイルへ展開された値がartifactに含まれる、環境変数をそのまま子プロセスへ渡して別ツールがログへ出す、といった形です。GitHub Actionsにはマスク機能がありますが、すべての漏えいパターンを自動で防げるわけではありません。つまり、「Secretsに入れているから出ない」ではなく、「使った先でどう扱われるか」まで見る必要があります。

よくある落とし穴は、失敗時の詳細ログや、便利な一時ファイルの保存です。チェックリストとしては、「シークレット値をechoしていないか」「生成ファイルに資格情報が含まれていないか」「artifactへ設定ファイルや.env系を入れていないか」を確認すると効果があります。マスクは最後の保険であって、出力しない設計の代わりにはなりません。

2. まず禁止するルール

2-1. workflow権限(permissions)最小化

最初に徹底したいのは、workflowやjobの権限を必要最小限にすることです。権限が広いままだと、漏れたときの被害も、悪用できる範囲も大きくなります。

GitHub Actionsでは、GITHUB_TOKEN や各種Secretsが、ジョブの実行内容によってさまざまな操作に使われます。ここでリポジトリ書き込み、パッケージ公開、デプロイ実行などの権限を広く持たせると、1つの漏えいが複数の被害へつながります。最小権限の考え方は、「このジョブは何をするのか」から逆算して、不要な権限を全部落とすことです。

permissions:
  contents: read

jobs:
  test:
    permissions:
      contents: read
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test

この設定では、テストジョブに読み取り権限だけを与えています。注意点は、workflow全体で広く許可してしまうと、実際には不要なジョブまで強い権限を持つことです。まずは全体を狭くし、どうしても必要なジョブだけ追加で権限を広げる順番のほうが安全です。

2-2. 危険イベントの扱い(pull_request 等)

Secrets漏えい対策では、どのイベントでSecretsを使うかを分けることがとても重要です。特に pull_request まわりは便利さと危険が近いため、明確なルールが必要です。

PR起点のジョブでは、レビュー前の変更や外部から来たコードが実行対象になることがあります。そのため、ビルド・テストのようにSecrets不要で回るジョブと、デプロイ・公開・本番確認のようにSecretsが必要なジョブを分離するべきです。危険なのは、「PRでも同じworkflowが全部動く」「Secretsが必要な処理が条件分岐なしで混ざっている」構成です。

  • fork由来PRでSecrets必須ジョブを実行しない
  • PRではテスト専用ジョブだけ動かす
  • 公開・デプロイはmainマージ後や手動承認後に限定する
  • 外部入力をそのままシェルへ渡さない
  • pull_request_target のような強い文脈は用途を絞って使う

このあたりは「危険イベントを禁止する」というより、「Secretsが必要な処理を危険イベントへ乗せない」と考えると整理しやすいです。PRで必要なのは多くの場合テストと静的解析なので、そこへ本番用の資格情報を混ぜないのが基本です。

3. 代替手段(構造で減らす)

3-1. 短命トークン/権限分離

Secrets漏えいを減らすには、長く使える固定秘密をそのまま置くより、短命トークンや権限分離へ寄せるのが有効です。これは「漏らさない」だけでなく、「漏れても被害を小さくする」考え方です。

固定の長寿命キーは、1回漏れると長期間悪用されやすいです。一方で、短時間だけ使えるトークンや、用途ごとに分けた資格情報なら、漏れたときの被害範囲を狭めやすくなります。たとえば、テスト用と本番デプロイ用の権限を分ける、読み取り専用と書き込み可能を分ける、といった分離だけでも効果があります。

実務では、「1つの強い秘密ですべてをまかなう」構成を避けるのが第一歩です。チェック項目としては、「このSecretsは1つ漏れたら何ができるか」「有効期限は長すぎないか」「テストとデプロイで同じ資格情報を使っていないか」を見ると改善点が見えやすくなります。Secretsの数を減らすことより、1つあたりの危険度を下げることが大切です。

3-2. 環境(Environment)と承認ゲート

GitHub Actionsでは、Environmentと承認ゲートを使って、本当に必要な場面だけSecretsへ触れるようにするのが有効です。これにより、通常のテストジョブと本番系ジョブをきれいに分けやすくなります。

たとえば、production環境にだけ本番用Secretsを置き、その環境を使うジョブには承認者レビューを必須にする、という設計ができます。こうすると、テストやlintの段階では本番資格情報に触れず、実際のデプロイ直前だけ人の確認を挟めます。これは技術的な分離と運用上の確認を同時に入れるやり方です。

jobs:
  deploy:
    environment: production
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

この設定では、deployジョブだけがproduction環境に属します。注意点は、Environmentを使っても、ジョブ全体の設計が広すぎると安全にはならないことです。承認ゲートは最後の関門なので、その前に「PR段階ではそもそも本番Secretsへ触れない」構造も合わせて必要です。

4. 漏えい時の初動

4-1. 失効・ローテ・影響範囲の特定

もしシークレット漏えいの疑いが出たら、最初にやるべきことは削除ではなく失効とローテーションです。見えなくすることより、使えなくすることが先です。

一度ログやartifact、外部公開されたPR、スクリーンショットなどへ出た可能性があるなら、もう第三者が取得した前提で動くべきです。そのため、対象トークンやキーを無効化し、新しいものへ切り替え、どのワークフロー・どの環境・どの期間に影響があったかを調べます。ここで「今は非公開だから大丈夫」と判断すると、被害が長引くことがあります。

初動の順番としては、「1. 対象Secretsの失効」「2. 新しい値へローテーション」「3. 影響したジョブ・artifact・デプロイ先の確認」「4. 必要なら外部サービス側ログの確認」が基本です。特にクラウドやレジストリの資格情報は、CI以外でも使われていることがあるため、影響範囲を横に広く見る意識が必要です。

4-2. 再発防止(監査とルール)

漏えい対応で大切なのは、その場しのぎで終わらせず、なぜ起きたかを運用ルールへ戻すことです。単にキーを入れ替えるだけでは、同じ種類の事故がまた起きます。

たとえば、PRイベント設計が危なかったのか、ログ出力が雑だったのか、権限が広すぎたのか、artifact管理が甘かったのかを振り返る必要があります。そして、その原因に応じてpermissionsの見直し、危険イベントの分離、Secrets利用ジョブの承認必須化、監査ログの確認手順、レビュー観点の追加などへ落とし込みます。再発防止はツール追加より、まず既存フローの穴を塞ぐことが中心です。

実務では、「Secretsを使うworkflowはレビューで何を見るか」を明文化すると効果があります。最低限の観点として、「不要な権限がないか」「SecretsをPR系ジョブで使っていないか」「ログやartifactへ出る可能性がないか」をチェック項目化すると、個人の経験差に左右されにくくなります。

5. まとめ:チェックリスト

GitHub Actionsのシークレット漏えい対策で重要なのは、Secretsを“安全な箱”として信じることではなく、どのイベントで、どのコードに、どの権限で触れさせるかを絞ることです。特にPRやfork起点、ログ出力、artifact保存、広すぎるpermissionsは、初心者が踏みやすい危険ポイントです。

  • workflowとjobの permissions を最小化しているか
  • PRやfork由来ジョブでSecrets必須処理を走らせていないか
  • ログへSecretsや展開後の値が出ないか確認しているか
  • artifactへ設定ファイルや資格情報を含めていないか
  • 長寿命の強いトークンを1つで使い回していないか
  • Environmentと承認ゲートで本番系を分離しているか
  • 漏えい時の失効・ローテーション手順があるか
  • レビューでSecrets利用workflowの観点が共有されているか

最初から完璧なSecrets運用を作る必要はありませんが、少なくとも「危険なイベントで使わない」「権限を狭くする」「漏れたらすぐ無効化できる」の3点は早めに固める価値があります。CIのSecretsは便利ですが、便利さのぶんだけ設計を雑にすると被害も大きくなりやすいので、構造で減らす発想を持つことが大切です。

6. 参考リンク