GitHub Actions OIDCで実現する鍵レス本番デプロイ:漏えい事故を減らす実装プレイブック
CI/CD の事故は、ビルドが失敗することより「漏えいしても気づけない鍵」が残り続けることのほうが深刻です。特に AWS_ACCESS_KEY_ID のような長期シークレットを GitHub Secrets に保存し続ける運用は、便利ですがリスクが高いです。
本記事では、GitHub Actions の OIDC(OpenID Connect)連携を使って、長期鍵を使わずに AWS へデプロイする実践手順をまとめます。単なる設定紹介ではなく、最小権限・ブランチ制限・監査ログ設計まで含めて、明日から本番投入できる形で説明します。
1. まず何が危険なのか:長期シークレット運用の限界
従来構成では、次のような問題が起きます。
- Secret が漏れても検知が遅い(CIログ、誤コミット、権限の広いメンバー)
- ローテーションが後回しになる
- 1つの鍵で複数環境へアクセスできてしまう
- 「誰のどの workflow 実行が何をしたか」が追いにくい
OIDC 連携では、GitHub が発行する短命トークンを信頼し、AWS 側で一時認証情報を払い出します。つまり、保管する鍵そのものを減らすのが最大の価値です。
2. 全体アーキテクチャ
基本フローは以下です。
- GitHub Actions ジョブが OIDC トークンを取得
- AWS IAM の OIDC プロバイダとロール信頼ポリシーで検証
- 条件に一致したジョブだけ
AssumeRoleWithWebIdentity - 一時クレデンシャルで S3/CloudFront/ECR/ECS へデプロイ
ポイントは「GitHub 側の workflow 制御」だけでなく、AWS 側で repo・branch・workflow を強制することです。
3. AWS 側の初期設定(OIDC Provider + IAM Role)
3.1 OIDC Provider を作成
CLI 例(すでに存在する場合はスキップ):
|
|
3.2 信頼ポリシーを厳密化する
以下のように sub と aud を必ず絞ります。
|
|
sub を repo:org/repo:* のように広く取りすぎると、意図しない workflow からも引き受ける可能性があり危険です。
3.3 デプロイ権限ポリシーを分離する
「ロール1個に全部盛り」は避けます。
deploy-web-prod-role: S3同期 + CloudFront invalidationdeploy-api-prod-role: ECR push + ECS updateread-only-audit-role: CloudWatch Logs / Describe 系のみ
環境別(dev/stg/prod)にロールを分離すると、誤デプロイ時の被害半径が大きく減ります。
4. GitHub Actions workflow 実装
最小サンプル:
|
|
重要なのは permissions.id-token: write を明示する点です。これがないと OIDC トークンを取得できません。
5. 事故を防ぐための実務ルール
5.1 branch protection と environment protection を組み合わせる
main直push禁止- 必ず PR + 1 approval
- production environment には Required reviewers を設定
- 夜間デプロイを禁止したい場合は手動承認ステップを入れる
5.2 workflow ファイル改変の監査
.github/workflows/*.yml の変更は CODEOWNERS で必ずレビュアー固定にします。
|
|
5.3 self-hosted runner の扱い
OIDC を導入しても、runner 自体が侵害されると意味が薄れます。
- runner をプロジェクト共有にしない(専用化)
- ジョブ後にワークディレクトリをクリーン
- egress 制限をかける
- runner グループを環境ごとに分離
6. トラブルシューティング
症状1: Not authorized to perform sts:AssumeRoleWithWebIdentity
確認ポイント:
audがsts.amazonaws.comになっているかsubが実際の実行 ref と一致しているか(タグ実行でハマりやすい)permissions.id-token: writeが設定されているか- Role ARN の typo がないか
症状2: main 以外で偶発的にデプロイされた
- workflow の
on.push.branches見直し - IAM 信頼ポリシー
subを main 固定へ - 環境保護ルール(Required reviewers)追加
症状3: デプロイは通るが操作が一部失敗
これは IAM 権限不足の可能性が高いです。CloudTrail の eventName と errorCode を見て、必要最小限のアクションだけ追加します。闇雲に * を付けないこと。
7. 段階的な移行計画(既存運用からの切替)
実務では一気に切り替えず、以下の順が安全です。
- OIDC ロールを作成(既存シークレットは残す)
- staging workflow だけ OIDC に切替
- 1週間監視(失敗率・デプロイ時間・CloudTrail)
- production を OIDC 化
- 最後に長期シークレットを削除
削除前に「どの workflow がどの secret を参照しているか」を grep で確認しておくと事故が減ります。
|
|
8. 監査ログ設計:何を見れば安全性が上がるか
最低限、次をダッシュボード化すると運用しやすいです。
AssumeRoleWithWebIdentity実行回数(日次)- 失敗イベント数(権限エラー/条件不一致)
- production deploy 実行者(workflow + sha + actor)
- 1回のデプロイで変更された主要リソース数
CloudTrail + CloudWatch Logs Insights での簡易クエリ例:
|
|
まとめ
OIDC は「設定が新しいから導入する」ものではなく、長期鍵を削減して事故確率を下げるための運用設計です。導入時にやるべきことはシンプルで、次の3つに集約できます。
- IAM 信頼ポリシーを repo/branch 単位で厳密化する
- workflow 側で id-token 権限と環境保護を設定する
- CloudTrail で AssumeRole の監査を継続する
ここまで実施すれば、CI/CD のセキュリティは「頑張って守る」状態から、「漏えいしにくい仕組みで守る」状態へ進化します。まずは staging 1本から置き換えるのがおすすめです。