CIパイプラインからクラウドへのアクセスをOIDCで動かすか静的キーで回すか――federation設計判断

CIパイプラインからクラウドへのアクセス認証において、静的キー(IAMアクセスキーやサービスアカウントキーなど)を廃止してOIDCベースのフェデレーションに移行すべきかどうかは、セキュリティ要件と運用コストのトレードオフを正確に把握したうえで判断する必要があります。結論から言えば、CI/CDプラットフォームがOIDCをサポートしている環境では、静的キーを残す技術的理由はほぼ存在しません。ただし、移行設計を誤るとフェデレーション設定自体が攻撃面になるため、trust policyの絞り込みと段階的な廃止計画が不可欠です。

静的キーが残存する理由とOIDC移行の判断基準

静的キーが消えない3つの構造的要因

「なぜ静的キーが残るのか」を正直に分析するところから始める必要があります。第一の要因は設定の手軽さです。アクセスキーを環境変数に1行書けばすぐに動くため、「いったん動いたもの」はそのまま放置されがちです。第二は既存パイプラインとの依存関係です。数年前に構築したCI設定が複数のジョブ・ステージに静的キーを組み込んでいる場合、一括置換のリスクを恐れて先送りされます。第三はOIDCを正確に理解しているエンジニアの不足です。フェデレーション設計にはIAMのtrust policy、JWTのclaims検証、プロバイダ固有の実装差異を理解する必要があり、学習コストが壁になります。一般的には、組織内に静的キーが10個以上存在する場合、その半数以上は「最後にローテーションした時期が不明」な状態になっていることが多く、定期的なキーローテーションも形骸化します。

OIDC移行の判断基準

OIDCへの移行を判断する際には、以下の4点を確認します。これらがすべて「はい」であれば、静的キーを維持する技術的根拠はなくなります。

  • CI/CDプラットフォームがOIDCトークン発行をサポートしているか(GitHub Actions・GitLab CI・CircleCI・Bitbucket Pipelines等)
  • クラウドプロバイダがOIDCフェデレーションをサポートしているか(AWS・GCP・Azureはすべて対応済み)
  • セキュリティポリシー上、長期有効な認証情報の保存が禁止または監査対象になっているか
  • 監査ログで「どのパイプライン実行がどのリソースにアクセスしたか」をジョブ単位で追跡する必要があるか

移行コストの目安として、中規模のCI設定(パイプライン数10〜30本程度)であれば、設計・テスト・切り替えを含めて2〜3人日の工数で完了できるケースが多いです。この工数を超えるとすれば、既存のパイプライン設計が密結合になっている場合がほとんどです。

移行を見送るべきケース

一方で、OIDCが適さないケースも存在します。オンプレミス環境にホストされたJenkinsやConcourse CIなど、インターネットから切り離されたCI環境では、クラウドのOIDCエンドポイントとの通信経路を確保できない場合があります。また、マネージドでないSelf-hosted runnerを使用し、そのホストのIDを十分に信頼できない場合は、OIDC設定が逆に攻撃面を広げるリスクがあります。このようなケースでは、静的キーを30日周期での短期ローテーションと最小権限設計で補うことが現実的な選択です。手を動かす手順はドキュメントや公式ガイドを参照しつつ、設計判断の軸をここで定めることが先決です。

静的キー方式とOIDC方式の比較

認証フローの根本的な差異

静的キー方式は、CI環境の環境変数に格納した認証情報をAPIリクエストに直接付与する方式です。トークン取得のステップが不要なため実装はシンプルですが、キーが漏洩した場合の影響範囲が広く、有効期限がないため「気づかない漏洩」が長期化します。OIDC方式は、CIジョブ実行時にプラットフォームが短命のJWTトークンを発行し、それをクラウドの認証エンドポイントに提示してセッション認証情報を取得します。認証情報の有効期間は通常1時間以内に設定でき、長期シークレットの永続保存が不要になります。

比較項目 静的キー方式 OIDC方式
認証情報の有効期間 無期限(手動削除まで有効) 1時間以内(設定可能・最大12時間)
シークレット保存 CI環境変数・Vault等に保存が必要 保存不要(実行時に動的取得)
漏洩時の影響期間 発見・削除まで無制限に悪用可能 有効期間内(最大1時間程度)に限定
設定の複雑さ 低(環境変数1〜2行) 中〜高(trust policy設計が必要)
監査トレーサビリティ キー単位(発行元ジョブ不明) ジョブ・ブランチ・環境単位で追跡可能
環境スケール時の管理コスト 環境数に比例して増加 trust policy条件で柔軟に制御可能

スケーラビリティと運用コストの差

静的キーは環境が増えるたびに「どのキーがどの環境向けか」の管理が複雑になります。想定例として、環境数が10を超えた時点でキー管理台帳の維持コストが顕著に増加し、誰がどのキーを保持しているかの棚卸しが定期的に必要になります。OIDCはtrust policyの条件でブランチ・リポジトリ・環境を区別できるため、同一ロール定義を複数の環境で再利用しながら細かい絞り込みが可能です。環境数が30〜50に増えても、trust policyの管理対象はロールの数(多くても十数個)に抑えられる点が静的キーとの本質的な違いです。

GitHub ActionsとGitLab CIそれぞれのOIDC連携設計

GitHub ActionsのOIDCトークン構造と設計判断

GitHub ActionsがOIDCトークンに含めるclaimsには、リポジトリ名(repository)、ブランチ名(ref)、ジョブのワークフローパス(job_workflow_ref)、環境名(environment)などが含まれます。設計判断として重要なのは、environment claimの活用です。GitHub Actionsのenvironmentを定義してtrust policyの条件に組み込むことで、「mainブランチかつproduction環境から実行されたジョブだけにデプロイ権限を与える」という絞り込みが可能になります。refだけを条件にする設計は「mainブランチの任意のジョブ」が対象になるため、スコープが意図より広くなる点に注意が必要です。

GitLab CIのOIDC設計の特徴

GitLab CIでは、id_tokenブロックを通じてOIDCトークンを取得します。GitLab特有のclaimsとして、namespace_path(グループ・サブグループのパス)、project_path、ref_type(branchとtagの区別)、environmentが利用できます。設計上の判断ポイントとして、GitLab Self-managedとGitLab.comではissuer URLが異なること、およびci configファイルのid_tokenブロックでaudienceを明示的に指定する必要があることが挙げられます。audienceを設定しない場合はGitLabのデフォルト値が入るため、AWSやGCPのtrust policyとの整合性を事前に確認しておく必要があります。

両プラットフォームの設計上の差異

GitHub ActionsとGitLab CIで最も設計判断に影響する違いは「sub claimの形式」です。GitHub Actionsでは「repo:owner/repo:environment:production」のような形式になり、GitLab CIでは「project_path:group/project:ref_type:branch:ref:main」のような形式になります。どちらも柔軟な条件設定が可能ですが、trust policyの条件式はプラットフォームごとに記述形式が大きく異なります。複数のCIプラットフォームを並行運用している場合、trust policyをプラットフォームごとに分離して管理することが保守性の観点から基本的な方針になります。

OIDCトークンのスコープと有効期限の設計

claimsが表すスコープの設計方針

OIDCトークンのclaimsは「このトークンの発行元は何者か」を証明するものであり、クラウド側はその内容を検証したうえでセッション認証情報を発行します。設計上の判断は「どのclaimsを条件に使うか」という点に集約されます。リポジトリ・ブランチ・環境・ワークフローパスを複合条件として設定するほど権限は精密に絞れますが、条件の組み合わせが増えるほどポリシーの保守コストも上がります。最低限の設計として「リポジトリ名+環境名」の組み合わせを条件にすることで、他プロジェクトのパイプラインによる意図しない権限取得を防ぐことができます。条件を増やすかどうかは、そのロールで操作できるリソースの重要度と照らし合わせて判断します。

有効期限設計のトレードオフ

クラウドが発行するセッション認証情報の有効期間は、デフォルトで1時間が一般的です。ビルドやデプロイジョブが1時間を超える場合は、ジョブの途中で認証情報が失効するリスクがあります。この場合、有効期間を延長するか、ジョブを分割して認証情報を再取得する設計が必要です。AWSのSTS AssumeRoleWithWebIdentityは最長12時間まで有効期間を設定できますが、有効期間を長くするほど漏洩リスクが増します。実際のジョブ所要時間を計測し、その1.5倍程度の余裕を持たせた設定が設計の目安です。デプロイジョブが平均40分かかるなら、有効期間を1時間に設定するといった判断になります。

スコープ設計の落とし穴

よくあるつまずきは、「1つのOIDCロールにビルド・テスト・デプロイすべての権限を集約する」設計です。テストジョブが本番環境のリソースにアクセスできる状態になるため、パイプラインの一部が乗っ取られた際の影響範囲が広がります。ジョブの種類ごとに専用ロールを分け、ビルドはアーティファクトストレージへの書き込みのみ、デプロイは対象サービスの更新のみ、という粒度で設計することで爆発半径を限定できます。ステージ別にロールを分割することは設定の手間が増えますが、セキュリティ上の分離設計として外せない考え方です。

ロール引き受け条件の絞り込みと最小権限設計

trust policyの設計思想

trust policyはロールを「誰が」「どういう条件で」引き受けられるかを定義するものです。OIDCの場合、PrincipalはFederated(OIDCプロバイダのARN)を指定し、Conditionブロックでclaimsの値を制限します。設計原則は「条件は必要十分にする」ことです。Conditionを省略すると、そのOIDCプロバイダを経由するすべてのジョブが権限を取得できてしまいます。一方で条件を細かくしすぎると、ブランチのリネームやワークフローファイルの移動で意図せず権限取得が失敗するケースが発生します。変更頻度が低い条件(リポジトリ名・環境名)を中心に据え、変更頻度が高い条件(ブランチ名・ワークフローパス)はワイルドカードで柔軟性を持たせる設計が現実的です。

条件キーの組み合わせと落とし穴

AWSのtrust policyでGitHub Actionsを条件とする場合、subとaudの2つのclaimsを組み合わせることが基本です。audを「sts.amazonaws.com」に固定することで、他クラウド向けに発行されたトークンの流用を防げます。一般的なミスは、StringLikeとStringEqualsの使い分けの誤りです。ワイルドカードを含む条件にはStringLikeが必要で、StringEqualsを使うと完全一致しか検証されないため、「refs/heads/*」のようなワイルドカード指定が意図通りに動作しません。また、audクレームが配列値になる場合にはForAnyValue修飾子を組み合わせる設計が必要になります。これらの細かい仕様はクラウドドキュメントと突き合わせて確認することが重要です。

最小権限の実装方針

OIDCを導入したからといって最小権限が自動的に実現されるわけではありません。ロールに紐づくIAMポリシーを適切に絞らなければ、OIDC経由でも広い権限が取得できてしまいます。設計上の判断として、ジョブの種類ごとに専用ロールを作り、それぞれに必要最小限のポリシーだけを付与する方針が基本です。実装の目安として、本番・ステージング・開発の3環境×ビルド・デプロイ・監査の3用途で、少なくとも6〜9のロールに分割することで爆発半径を限定できます。初期設定でResource: * などのワイルドカード許可を付与したまま放置するケースが、よくあるつまずきの一つです。

複数クラウド環境での連携設計の違い

AWS・GCP・Azureの実装差異

AWS、GCP、AzureはOIDCフェデレーションをそれぞれサポートしていますが、設定の粒度と仕組みが異なります。AWSはIAM Identity Providerを登録してtrust policyで条件を制御する形式です。GCPはWorkload Identity Federationの仕組みでattribute mappingを使い、OIDCのclaimsからGCPの属性へのマッピングをCEL(Common Expression Language)で定義します。条件がattribute conditionとして別立てで定義される点がAWSのtrust policyとは設計の考え方が異なります。AzureはFederated Identity Credentialをサービスプリンシパルに紐づける形式で、subject・audience・issuerを個別に設定します。設計ドキュメントには各クラウドで「条件がどのレイヤーに定義されているか」を明示しておくことが、保守性の観点から重要です。

マルチクラウド環境での設計統一

複数クラウドを同一のCIパイプラインから操作する場合、各クラウド向けのフェデレーション設定を一元管理するリポジトリを設けることが有効です。Terraformなどのインフラ定義ツールで各クラウドのフェデレーション設定を宣言的に管理し、条件(リポジトリ名・ブランチ・環境)を変数として統一することで設定の差異を最小化できます。複数クラウドに対して1回のジョブ実行でそれぞれの認証を行う場合、各クラウドへの認証ステップを並列実行できる設計にしておくとジョブ全体のレイテンシを抑えられます。マルチクラウド環境では特に「どのクラウドのどのロールがどのCIジョブから取得可能か」の一覧を設計ドキュメントとして維持することが運用の基本になります。

クラウドとCIの組み合わせによる制約

GCPのWorkload Identity Federationでは、GitLab CIのnamespace_pathなどプロバイダ独自のclaimsを条件に使う場合、そのclaimがGCP側のattribute mappingで明示的に定義されていなければ利用できません。事前に「使いたいclaimがマッピング可能か」を確認する設計工程が必要です。AWSは比較的柔軟にclaimsを条件として利用できますが、claim名の大文字小文字が完全一致で検証されるため、プロバイダのclaim仕様を正確に把握しておく必要があります。いずれのクラウドも、CIプラットフォーム側のclaim仕様変更がクラウド側の設定に影響するため、プラットフォームのリリースノートを追跡する仕組みを設けておくことが設計維持の観点から重要です。

移行時の並行運用期間と静的キー廃止手順

並行運用期間の設計

静的キーからOIDCへの移行において、いきなり静的キーを削除する方法は高リスクです。並行運用期間を設けることが基本的な移行設計になります。まずOIDC認証を使う新しいジョブを既存のパイプラインとは別ステージに追加し、新旧両方が動作することを確認します。次に新しい認証方式が2週間程度安定して動作していることを確認したうえで、パイプラインのメイン処理をOIDCに切り替えます。最後に静的キーを使う旧ジョブを削除します。この3ステップを環境ごとに順番に(開発→ステージング→本番の順)実施することで、本番への影響を最小化できます。

静的キー廃止の手順設計

静的キーの廃止は「無効化」と「削除」を別ステップで行うことが安全な設計です。まずキーを無効化(AWSであればInactive状態に変更)して、パイプラインが正常に動作することを24〜48時間確認します。その後、問題がなければ削除します。削除前にCloudTrailやCloud Audit Logsで「そのキーを最後に使ったのはいつか」を確認し、想定外の利用がないかを確認することが欠かせません。よくある落とし穴として、廃止予定のキーが自動化スクリプトや外部サービスのWebhookからまだ参照されているケースが挙げられます。移行作業の開始前に、対象キーのAPIコール履歴を少なくとも30日分遡って確認しておくことで、予期せぬ依存関係を事前に洗い出せます。

移行後の監査と設計維持のチェックリスト

OIDC移行完了後も、設計の劣化を防ぐための継続的な確認が必要です。以下のチェックリストを定期的に実施することで、フェデレーション設計の品質を維持できます。

  • trust policyの条件が想定通りに機能しているか、CloudTrailやIAM Access Analyzerで定期確認しているか
  • 想定外のclaimsによる権限取得が発生していないか、監査ログを定期的に確認しているか
  • CIプラットフォームのOIDCトークン仕様(claimの追加・変更)に追従できているか
  • ロールの有効期間設定が実際のジョブ所要時間と乖離していないか
  • 環境が追加された際にtrust policyが手順通りに更新されているか
  • 廃止した静的キーがすべて削除済みであることをIAMコンソールで確認しているか

これらの確認を四半期ごとに実施することで、移行後のフェデレーション設計の品質を長期的に維持できます。OIDCへの移行はゴールではなく、設計を継続的に見直す仕組みの起点として位置づけることが重要です。

▶ 手を動かして本番まで到達する

脱属人化の第一歩は「読める・書けるスクリプト」から始まります

ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。

自動化の設計を、手を動かして身につける2日間です。手順書に閉じ込めた構築を、他人が読めて再現できる形へ変えていきます。

CIからクラウドへのOIDCアクセス設計をスクリプトで実践するシェルスクリプト実践コースへ →

シェルスクリプトマスターセミナー|自動化の設計を手で身につける2日間