GitHub Actions Secrets 管理:漏洩リスクから OIDC による秘密鍵レスデプロイまで
2025年3月のある週末、GitHub セキュリティチームは 23,000 以上のリポジトリの所有者に緊急メールを送信しました。
彼らの secrets が漏洩した可能性があるという内容です。
犯人は tj-actions/changed-files という action でした。広く使われていたこのツールが攻撃者に侵害され、ワークフロー内のすべての環境変数と secrets を密かに窃取していました。「自分のプロジェクトでもこの action を使っているけど、大丈夫だろうか?」と思われた方もいるかもしれません。
正直なところ、この事件は多くの人が見過ごしていた問題を浮き彫りにしました。GitHub Actions 内の secrets は、一体どう管理すべきなのか?
この記事では、3つのことをお話しします。secrets の3層アーキテクチャの選び方、8つの安全鉄則の守り方、そして OIDC を使って静的クレデンシャル漏洩の悪夢から完全に解放される方法です。
一、GitHub Actions Secrets の3層アーキテクチャ
GitHub は secrets を保存するために3つのレベルを提供しています:Repository、Environment、Organization。どれを選ぶべきか?答えは「あなたのユースケース次第」です。
Repository Secrets:個人プロジェクトの首选
最もシンプルなレベルです。secrets はリポジトリレベルで保存され、すべてのワークフローがアクセスできます。個人プロジェクト、モノリポジトリ、複数環境デプロイの要件がない場合は、これだけで十分です。
唯一の欠点は、staging と production の同名 secret を区別できないことです。例えば DATABASE_URL という secret がある場合、staging と production で値が異なります。どうすればよいのでしょうか?ここで Environment Secrets が必要になります。
Environment Secrets:複数環境デプロイの必需品
Environment secrets は環境ごとに分離でき、承認フローもサポートしています。GitHub リポジトリの設定で staging と production の2つの環境を作成し、それぞれ異なる secrets を設定できます。
重要な特徴は、その環境を参照するジョブだけが対応する secrets にアクセスできることです。これにより、セキュリティ境界がより明確になります。
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # staging 環境を参照
steps:
- run: echo "Deploying to staging..."
- env:
API_KEY: ${{ secrets.API_KEY }} # staging 環境の secret
deploy-production:
runs-on: ubuntu-latest
environment: production # production 環境を参照(承認設定可能)
steps:
- run: echo "Deploying to production..."
- env:
API_KEY: ${{ secrets.API_KEY }} # production 環境の secret
上記の設定では、deploy-staging は staging 環境の secrets にしかアクセスできず、deploy-production は production 環境の secrets にしかアクセスできません。両者は互いに干渉しません。
また、Environment は「保護ルール」もサポートしています。例えば production 環境では、人的承認を経ないと実行できないように設定できます。これはチームでのコラボレーション時に特に有用です。
Organization Secrets:チーム共有、統一管理
もしチームに数十のリポジトリがあり、各リポジトリに同じ AWS_ACCESS_KEY を設定する必要があるとします。何十回もコピペして、更新時はまた何十回も修正する——考えるだけで頭が痛くなります。
Organization secrets はこの問題を解決するために存在します。組織レベルで一度設定すれば、すべてのリポジトリで使用できます。また、どのリポジトリがアクセスできるかを制御できます:すべてのリポジトリ、または指定したリポジトリリスト。
# リポジトリのワークフローでは、repository secrets と全く同じように使用
steps:
- env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
どう選ぶ?
シンプルに言うと:
| シナリオ | 推奨レベル |
|---|---|
| 個人プロジェクト、単一環境 | Repository Secrets |
| 複数環境デプロイ(staging/production) | Environment Secrets |
| チーム複数リポジトリ、共有クレデンシャル | Organization Secrets |
私の経験では、多くのプロジェクトは最初 Repository Secrets を使用し、複数環境の要件が出てから Environment Secrets に移行します。移行コストは高くありませんが、事前に計画することをお勧めします。
二、Secrets セキュリティベストプラクティス — 8つの鉄則
ここまで secrets の保存方法を説明しました。ここからは使い方についてお話しします。実践から学んだ8つの鉄則をまとめました。それぞれに教訓があります。
1. 命名規則を守る
すべて大文字 + アンダースコア区切り。例:AWS_ACCESS_KEY_ID。小文字やキャメルケースは使わないでください。理由はシンプルです。一目で secret とわかり、普通の変数と混同しません。
2. JSON を1つの secret に保存しない
これは典型的な落とし穴です。設定ファイル全体を1つの secret に詰め込む人がいます:
{"api_key": "xxx", "db_url": "yyy", "token": "zzz"}
そしてワークフロー内で fromJson で解析します。問題は、この secret が漏洩すると、すべての機密情報が一緒に漏洩することです。正しい方法は、各値を独立した secret として保存することです。
3. 明示的に受け渡す、インラインにしない
# 悪い例 ❌
- run: my-cli --token ${{ secrets.MY_TOKEN }}
# 良い例 ✅
- env:
MY_TOKEN: ${{ secrets.MY_TOKEN }}
run: my-cli --token $MY_TOKEN
なぜでしょうか?GitGuardian の研究によると、コマンドライン引数は同じマシン上の他のプロセスから ps x -w で見ることができます。環境変数の方がはるかに安全です。
4. 定期的にローテーションする
30〜90日ごとに変更します。ローテーションは面倒だとわかっています。しかし、漏洩後の対応と比べれば、この手間は本当に大したことありません。Blacksmith チームの提案では、クラウドサービス(AWS/GCP)を使用している場合、OIDC と組み合わせることでこの手順を完全にスキップできます。
5. Actions を SHA に Pin する
サプライチェーン攻撃の最初の防衛ラインです。
# 悪い例 ❌
- uses: tj-actions/changed-files@v45
# 良い例 ✅
- uses: tj-actions/changed-files@b827595e0a7e97537d7c7a2f458b5a8e6d5c8e39
バージョン番号タグではなく、commit SHA を使用してください。タグは攻撃者によって改ざんされる可能性がありますが、SHA は不変です。
6. GITHUB_TOKEN には最小権限のみを付与する
GitHub は各ワークフローに自動的に GITHUB_TOKEN を提供します。デフォルトの権限は高すぎます——コードを書ける、issue を変更できる。ワークフローまたはリポジトリ設定で read-only に変更することをお勧めします:
permissions:
contents: read
7. ログで secrets が正しくマスキングされているか確認する
GitHub は自動的に ${{ secrets.XXX }} をログ内で *** に置換します。しかし、このように書くと:
- run: echo "Token is $MY_TOKEN"
ログに実際の token 値が表示されます。ワークフローをテストして、予期しない露出がないことを確認してください。
8. 派生した機密値を登録する
ワークフローが1つの secret から新しい機密値を生成した場合(例:API key で JWT を生成)、その新しい値も secret として登録してください。メモリ内でのみ受け渡さないでください。
この8つの鉄則は単なる理論ではありません。tj-actions 事件後、StepSecurity チームが数千の公開リポジトリを監査したところ、これらのルールに違反しているリポジトリが相当な割合を占めていました。修正は難しくありませんが、時間をかけて1つずつ確認する必要があります。
三、OIDC — 秘密鍵レス時代のクラウドデプロイ認証
前の2つの鉄則で「secrets の定期的なローテーション」に触れました。正直なところ、ローテーションは本当に面倒です——毎回 AWS コンソールで手動変更、GitHub secrets の更新、チームメンバーへの通知が必要です。
OIDC(OpenID Connect)は1つの解決策を提供します:そもそも secrets を保存しない。
OIDC はどう動作するのか?
従来の方法:AWS で IAM ユーザーを作成し、access key を生成し、その key を GitHub secrets に保存します。ワークフローが実行されるたびに、この静的 key を使って AWS リソースにアクセスします。
OIDC の方法:GitHub がアイデンティティプロバイダーとして、AWS に「このワークフローは eastondev/my-repo リポジトリから来ている」ことを証明します。AWS は検証後、短期 JWT トークン(有効期限は数分から数時間)を発行します。ワークフローはこの一時トークンを使ってタスクを完了し、トークンは期限切れ後に自動的に無効化されます。
長期クレデンシャルを保存する必要がなく、ローテーションも不要で、漏洩リスクもありません。
AWS OIDC 設定例
手順は2つの部分に分かれます:AWS 側で信頼関係を設定し、GitHub 側でトークンをリクエストします。
AWS 側(コンソール操作):
- IAM Identity Provider を作成、URL を
https://token.actions.githubusercontent.comに設定 - IAM Role を作成、信頼ポリシーをリポジトリに制限:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:eastondev/my-repo:ref:refs/heads/main"
}
}
}]
}
この設定の意味は、eastondev/my-repo リポジトリの main ブランチだけがこの role を assume できるということです。
GitHub 側(ワークフロー設定):
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # 必須:OIDC トークンをリクエスト
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
ここには secrets.AWS_ACCESS_KEY が一切ないことに注目してください。直接 role で認証しています。
GCP と Azure
3大クラウドはすべて OIDC をサポートしており、設定は似ています:
| クラウドプラットフォーム | GitHub Action | 公式ドキュメントのキーワード |
|---|---|---|
| AWS | aws-actions/configure-aws-credentials | OIDC federation |
| GCP | google-github-actions/auth | Workload Identity Federation |
| Azure | azure/login | Federated Identity Credentials |
OIDC の意外なメリット
johal.in のテストによると、OIDC 認証のレイテンシーは従来の secrets 方式より約 87% 低減されました。理由はシンプルです。GitHub secrets API からクレデンシャルを読み取る必要がなく、ローカル JWT から直接一時トークンを取得できます。
私個人の使用経験から言うと、OIDC はクラウドデプロイの首选ソリューションです。唯一のハードルは設定が少し複雑なことですが、一度設定すれば後は完全に放置できます。
四、サプライチェーン攻撃対策 — tj-actions 事件の振り返り
冒頭で触れた tj-actions/changed-files 事件に戻りましょう。どのように発生したのか?何を学べるのか?
事件の経緯
2025年3月、攻撃者が tj-actions リポジトリの maintainer 権限を取得しました(具体的な経路は調査中ですが、クレデンシャル漏洩またはアカウント侵害の可能性があります)。彼らは v45 バージョンのコードに悪意のあるスクリプトを挿入し、このスクリプトはワークフロー実行時に密かにすべての環境変数と secrets を読み取り、攻撃者が管理するサーバーに送信しました。
Semgrep の分析によると、tj-actions/changed-files@v45 を使用しているすべてのワークフローが影響を受けました——GitHub secrets でも OIDC でも、この action が環境変数にアクセスできれば窃取されます。
Unit42 Palo Alto のレポートでは、23,000 以上のリポジトリがこの action を使用していたことが指摘されています。有名なプロジェクトの fork も含まれていました。
教訓
この事件はいくつかの問題を露呈しました:
- Action のバージョン番号タグは信頼できない——攻撃者はタグを改ざんして悪意のある commit を指すことができる
- サードパーティ action はあなたの secrets にアクセスできる——侵害されると、すべての secrets が露出する
- 過去の実行ログは機密情報を漏洩している可能性がある——現在修正しても、過去の実行記録には痕跡が残っている可能性がある
チェックリスト
tj-actions/changed-files を使用したことがある場合、以下の項目を1つずつ確認することをお勧めします:
□ ワークフローログを確認し、secrets が出力に漏洩していないことを確認
□ 漏洩した可能性のある secrets をすべてローテーション(API keys、tokens など)
□ action を commit SHA に pin し、バージョン番号ではなく
□ 他のサードパーティ action の maintainer の出所を監査
□ Dependabot または Renovate で action バージョンの自動チェックを検討
まだ侵害されていないプロジェクトにとって、Pin SHA が最も重要な防御策です。SHA はバージョン番号より読みにくいですが、タグ改ざんを防ぐ唯一の方法です。
また、GitHub は2026年のセキュリティロードマップで重要な方向性を言及しています:コード貢献権限とクレデンシャル管理権限の分離。将来的には、より詳細なアクセス制御が導入され、サードパーティ action が必要な secrets にしかアクセスできないようになる可能性があります。これは良いニュースですが、現時点では自分で防衛線を守る必要があります。
結論
GitHub Actions Secrets 管理は複雑な技術問題ではなく、継続的な注意が必要なセキュリティプラクティスです。まとめると:
3層アーキテクチャの選び方:個人プロジェクトは Repository Secrets、複数環境デプロイは Environment Secrets、チーム共有は Organization Secrets。
安全鉄則の守り方:Pin SHA、明示的な受け渡し、定期的なローテーション——この3つが最も重要です。
クラウドデプロイの認証方法:OIDC が首选、secrets 保存なし、ローテーションの悩みなし。
サプライチェーン攻撃の防ぎ方:サードパーティ action の secrets アクセスを制限、maintainer の出所を監査。
tj-actions 事件から教訓を得た後、私の実践はこうです:すべての action を SHA に pin、クラウドデプロイはすべて OIDC、毎月1回 secrets 監査。このプロセスの構築には約2週間かかりましたが、その後のメンテナンスコストは非常に低いです。
まだこれらのチェックを始めていない方は、今日この記事のチェックリストを実行することをお勧めします。事後対応と比べれば、事前予防のコストははるかに低いです。
GitHub Actions OIDC 秘密鍵レスデプロイの設定
AWS クラウドサービスに OIDC 認証を設定し、静的クレデンシャルを保存せずに安全なデプロイを実現
⏱️ 目安時間: 30 分
- 1
ステップ1: IAM Identity Provider を作成
AWS IAM コンソールでアイデンティティプロバイダーを作成:
• Provider URL: https://token.actions.githubusercontent.com
• Audience: sts.amazonaws.com
• 生成された Provider ARN を記録 - 2
ステップ2: IAM Role を作成し信頼ポリシーを設定
IAM Role を作成し、信頼ポリシーを GitHub リポジトリに制限:
```json
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:OWNER/REPO:ref:refs/heads/main"
}
}
}]
}
```
• ACCOUNT_ID を自分の AWS アカウント ID に置換
• OWNER/REPO を自分の GitHub リポジトリに置換
• :ref:refs/heads/main を削除してすべてのブランチを許可可能 - 3
ステップ3: Workflow で OIDC を使用するように設定
GitHub Actions ワークフローで OIDC トークンをリクエスト:
```yaml
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # 必須:OIDC トークンをリクエスト
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT_ID:role/GitHubActionsRole
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
```
• id-token: write は必須の権限宣言
• secrets.AWS_ACCESS_KEY_ID の設定は不要 - 4
ステップ4: テストと検証
ワークフローを実行して OIDC 設定を検証:
• ワークフローログを確認し、認証成功を確認
• role-to-assume が正しいことを確認
• 静的クレデンシャルなしで AWS リソースにアクセスできることを確認
• ターゲット操作(S3 同期、ECR プッシュなど)をテスト
FAQ
Repository Secrets と Environment Secrets の違いは何ですか?
ワークフローで安全に secrets を使用するにはどうすればよいですか?
• 明示的な受け渡し:env フィールドで注入し、インラインで ${{ secrets.XXX }} を使用しない
• 最小権限:必要なステップにのみ受け渡し、GITHUB_TOKEN 使用時は permissions: contents: read を設定
• 定期的なローテーション:30〜90日ごとのローテーションを推奨、クラウドデプロイでは OIDC を使用してローテーションを完全にスキップ可能
OIDC とは何ですか?従来の secrets より安全な理由は?
サプライチェーン攻撃(tj-actions 事件など)を防ぐにはどうすればよいですか?
• Actions を commit SHA に pin し、バージョン番号タグを使用しない
• secrets を信頼できる actions にのみ受け渡すよう制限
• サードパーティ action の maintainer の出所を監査
• 定期的に Dependabot または Renovate でバージョン更新をチェック
secrets はログに漏洩しますか?
Organization Secrets はどのようなシナリオに適していますか?
6 min read · 公開日: 2026年4月18日 · 更新日: 2026年4月20日
GitHub Actions 完全ガイド
検索からこのページに来た場合は、前後の記事もあわせて読むと同じテーマの理解がかなり早く深まります。
関連記事
GitHub Actions Matrix ビルド:マルチバージョン並列テストの実践
GitHub Actions Matrix ビルド:マルチバージョン並列テストの実践
GitHub Actions 入門:YAML ワークフローの基礎とトリガー設定
GitHub Actions 入門:YAML ワークフローの基礎とトリガー設定
GitHub Actions 入門:YAML ワークフローの基礎とトリガー設定

コメント
GitHubアカウントでログインしてコメントできます