AWSマルチアカウント環境からのGoogle Cloudフェデレーション設計 ― AI時代に対応した社内認証基盤の構築
LayerXの技術ブログは、AWSマルチアカウント環境からGoogle Cloudへの安全なフェデレーション認証基盤を、Workload Identity Federationを用いて「入口集約」と「ワークロード単位の最小権限」を両立する2段階制御で設計・実装した実践的アプローチを詳細に解説している。
キーポイント
マルチクラウド環境における認証課題の解決
AWSとGoogle Workspace/GCPを跨ぐ業務自動化・AI活用において、長期鍵管理の運用負荷とセキュリティリスクを解消するため、Workload Identity Federation(WIF)を用いた短命トークンによる安全なアクセス方式を設計した。
2段階アクセス制御による設計思想
「認証入口のSecurityアカウントへの集約」と「ワークロード単位での最小権限付与」を分離した2段階制御を採用し、運用統制性と細かい権限管理を両立している。
監査可能性を確保した実装構成
AWSのAssumeRoleログ、GCPのToken exchangeログ、SA impersonationログなど、認証フローの各段階で監査ログを取得可能な設計により、セキュリティガバナンスを強化している。
実践的な設計・運用ノウハウの共有
AWS Organizationsを使ったマルチアカウント環境での具体的な構成図、attribute_conditionの活用方法、検証時にハマったポイントなど、実際の導入に役立つ詳細な情報を提供している。
GCPプロジェクト構成の設計ポイント
WIF専用プロジェクトを新設することが推奨されており、セキュリティ境界の明確化、管理権限の分離、監視ポイントの集約などの利点がある。
AWS IAM Role構成の分離戦略
ワークロードごとに個別のGCP Federation用ロールを作成することで、GCP側でワークロード単位の分離を実現できる。
attribute_conditionでのパターンマッチ採用
完全一致ではなくprefixパターンマッチ(startsWith)を使用することで、ワークロード追加時の設定変更を最小限に抑え、スケーラビリティを向上させている。
影響分析・編集コメントを表示
影響分析
この記事は、AI時代のデータ連携・業務自動化において増加するマルチクラウド環境での認証課題に対し、実践的で安全なソリューションを提供している。特に大企業や規制業界において、監査可能性を確保しつつ運用負荷を軽減する設計思想は、同様の課題を抱える組織にとって重要な参考事例となる。
編集コメント
理論だけでなく実際の導入経験に基づく実践的な内容で、マルチクラウド環境の認証設計に悩むエンジニアやアーキテクトにとって非常に参考になる。特に監査ログの取得方法まで詳細に記載されている点が評価できる。
LayerX Fintech事業部より、三井物産デジタル・アセットマネジメント(以下、MDM)に出向しているpiroshiです。
AIの活用や業務自動化が当たり前となった今、データや処理はプラットフォームをまたいで動くことが増えています。特に「システム基盤はAWSで動かしつつ、社内業務はGoogle Workspace前提」といった構成では、AWS上のワークロードからGoogle Cloud(以下、GCP)やGoogle WorkspaceのAPIへ安全にアクセスしたい場面が自然に出てきます。
MDMでもそのニーズが顕在化しました。具体的には、共有ドライブの構成情報を定期的に取得して監査(権限・設定の棚卸し)を自動化したいという要件があります。加えて、別のチームではGoogle Drive上のリソースにアクセスする業務ツール開発も並行して進んでいました。ここでチームごとに認証方式が増えていくと、長期鍵の配布・権限の肥大化・監査のしづらさといった問題が起きやすくなります。そこで、個別最適に寄せるのではなく、安全で監査可能な共通のアクセス方式を用意することを目標に設計を検討しました。
サービスアカウントキーを発行してAWS側に置けば動きますが、長期鍵の配布・ローテーション・棚卸しは運用負荷が高く、漏えい時の影響も大きくなります。今回はWorkload Identity Federation(WIF)を使い、静的キーを持たずに短命トークンでアクセスする構成を設計しました。
WIFを使った実装の情報は多く見つかりましたが、AWSがマルチアカウント構成の場合にどう設計すべきかについて触れているものがなかなか見つからず、さらに、GCPのベストプラクティスに沿って「WIFを専用プロジェクトに集約する」構成を採ると、具体的にどう設計・運用が変わるのかイメージが湧きにくかったです。
この記事では、「AWS Organizationsを使ったマルチアカウント環境」で、「GCP側へ出ていく認証経路(入口)を運用・統制の都合でSecurityアカウントに集約」しつつ、「ワークロード単位で識別して最小権限を保つ」ためにどう設計したかをまとめます。検証時にハマったポイントとあわせて共有できればと思います。
なお、記事ではAWS→GCPへのフェデレーションに焦点を当てています。Google Workspace APIを操作する場合のDomain-Wide Delegation(DWD)設定については、ここでは扱いません。
AWS Organizationsを使ったマルチアカウント戦略を採用している
Google側へ出ていく認証経路(入口)を、運用・統制の都合でSecurityアカウントに集約したい
そのうえで、「ワークロード単位で識別して最小権限を付与」を維持する
結論:「入口」と「権限」を分けた2段階のアクセス制御
採用した構成は以下です。まず認証フローの概要を示します。
フローチャート LR サブグラフ AWS_Org[AWS Organizations] サブグラフ Workloads[Workload Accounts] WL_A[Workload Account A] WL_B[Workload Account B] end セキュリティ [セキュリティアカウント] end サブグラフ GCP_Org[GCP Organization] サブグラフ WIF_Proj[WIF 専用プロジェクト] WIF[WIF プール/プロバイダー] end サブグラフ Service_Projs[サービスプロジェクト群] SA_A[SA / リソース A] SA_B[SA / リソース B] end end WL_A -->|1. クロスアカウント AssumeRole| セキュリティ WL_B -->|1. クロスアカウント AssumeRole| セキュリティ セキュリティ -->|2. トークン交換| WIF WIF -->|3. 名乗り出 (Impersonate)| SA_A WIF -->|3. 名乗り出 (Impersonate)| SA_B
Service Account(SA) の権限で GCP リソースにアクセスします。Google Workspace API を使う場合は、SA に Domain-Wide Delegation(DWD) を付与してユーザーとして操作する構成になります。
この構成では、認証フローの各ステップでログが取得できます。
AWS: AssumeRole
どのロールがどのロールを AssumeRole したか
GCP: トークン交換 (Token exchange)
Cloud Audit Logs(WIF プロジェクト)
attribute_condition の成否、どのフェデレーション ID がトークン交換したか
GCP: SA 名乗り出 (SA impersonation)
Cloud Audit Logs(SA のプロジェクト)
どのフェデレーション ID がどの SA を名乗り出したか
OAuth ログ、各サービス監査ログ(Drive など)
Google Workspace へのアクセス状況
WIF 専用プロジェクトと SA のプロジェクトが分かれていても、それぞれのプロジェクトで Cloud Audit Logs が記録されるため、追跡が可能です。
設計思想:2 段階のアクセス制御
attribute_condition
想定外のアカウント/ロールを入口で落とす
第 2 段階:Service Account
ワークロード単位の権限分離 (最小権限)
principalSet とは:WIF のフェデレーション ID(federated identity) を指定するための識別子です。属性に基づいて「どのフェデレーション ID に権限を付与するか」を定義します。
形式:principalSet://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/attribute.{ATTRIBUTE_NAME}/{ATTRIBUTE_VALUE}
例:principalSet://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/aws-workload-id/attribute.aws_role/arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role
arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role
プールに到達できても、サービスアカウント(SA)への IAM バインディングがなければ、フェデレーション ID は impersonate できません。
ワークロードアカウントの実行ロール(IAM Role)から、セキュリティアカウント上の GCP フェデレーション用ロール(IAM Role)へクロスアカウント AssumeRole を実行します。
そのロールの AWS 認証情報を用いて、WIF が要求する署名付き GetCallerIdentity に相当する情報を生成し、Google STS へトークン交換を行います。
プロバイダーの attribute_condition
SA に対する roles/iam.workloadIdentityUser の付与
SA の権限で GCP リソース(必要に応じて DWD で Workspace API)にアクセスします。
補足:WIF が識別する「AWS 側の ID」とは
WIF が AWS 側の ID を識別する際に使用する STS の GetCallerIdentity は、以下の形式です。
arn:aws:sts::{ACCOUNT_ID}:assumed-role/{ROLE_NAME}/{SESSION_NAME}
セッション名は実行ごとに変わるため、WIF のプール側での設定(attribute_mapping)では以下のように記述します。
arn:aws:sts::{ACCOUNT_ID}:assumed-role/{ROLE_NAME}
ARN のうち、ユーザー側でコントロールできるのは IAM Role の名前です。そのため、命名規則を統一することで attribute_condition を適切に設計できます。
設計で検討した 5 つのポイント
- GCP プロジェクト構成:既存プロジェクトの利用 vs 専用プロジェクトの新設
既存プロジェクトに WIF リソースを追加する
WIF 専用プロジェクトを新規作成する
GCP のベストプラクティスでは、「専用のプロジェクトを使用して Workload Identity プールとプロバイダを管理すること」が推奨されています。
セキュリティ境界の明確化(他リソースとの分離)
WIF の管理権限(誰がプール/プロバイダーを操作できるか)を分離・集中管理できます。
一貫した attribute_mapping や attribute_condition を適用可能です。
外部からのフェデレーション経路を一箇所に集約することで、監視・監査すべきポイントが明確になり、セキュリティ上の攻撃対象領域を限定できます。
WIF を専用プロジェクトに集約し、実際のアクセス先となる SA が別のプロジェクトにあってもアクセスできるか懸念がありましたが、SA に対して roles/iam.workloadIdentityUser を付与すれば問題ありません。
- AWS IAM Role 構成:単一共有 vs ワークロード別分離
この設計では、AWS 側に 2 種類の IAM Role が登場します。
Workload Account
Lambda や ECS タスクなど、ワークロードが実行時に使用するロール。ワークロードごとに異なる。
GCP Federation 用ロール
Security Account
GCP への認証 (WIF) に使用するロール。実行ロールから AssumeRole される。
ここで検討するのは、Security Account の GCP Federation 用ロールを、全ワークロードで共有するか、ワークロードごとに分けるかです。
全ワークロードで共有する単一の GCP Federation 用ロール
ワークロードごとに個別の GCP Federation 用ロールを作成
前提として、各ワークロードが必要とする権限 (AWS 側のアクセス先リソースや、GCP 側で取得したい SA の権限) が異なる場合、実行ロールをワークロードごとに分けるのが自然です。
しかし、入口を Security Account に集約する設計では、GCP から見えるのは Security Account 側の「GCP Federation 用ロール」です (厳密には、識別できるのは STS ARN で、そのなかに IAM Role Name が含まれます)。GCP 側で利用できる属性は GetCallerIdentity 由来の情報 (account/arn/userid
よって、ワークロード単位の分離を GCP 側で実現するには、GCP Federation 用ロールもワークロードごとに分ける必要があります。
AWS(Security Account): GCP Federation 用ロール (例: workload-a)
Security Account 側(ID: 111111111111) # - SA へのアクセスを許可するワークロードの実行ロールからの AssumeRole を許可 # - AWS リソースへのアクセス権限は不要なため、信頼ポリシーのみ定義(IAM ポリシーのアタッチなし)
resource "aws_iam_role" "gcp_wif_workload_a" {
name = "gcp-wif-workload-a-role"
assume_role_policy = data.aws_iam_policy_document.trust_from_workload_a_exec.json
}
data "aws_iam_policy_document" "trust_from_workload_a_exec" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "AWS"
identifiers = [
"arn:aws:iam::222222222222:role/workload-a-exec-role"
]
}
}
}
AWS(Workload Account A): 実行ロールに AssumeRole 権限を付与
Workload Account A 側 (ID: 222222222222) # Security Account の GCP Federation 用ロールへの AssumeRole を許可
data "aws_iam_policy_document" "allow_assume_gcp_wif" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
resources = ["arn:aws:iam::111111111111:role/gcp-wif-workload-a-role"]
}
}
resource "aws_iam_role_policy" "workload_a_exec_assume_gcp_wif" {
name = "assume-gcp-wif"
role = aws_iam_role.workload_a_exec.name
policy = data.aws_iam_policy_document.allow_assume_gcp_wif.json
}
- attribute_condition: 完全一致 vs パターンマッチ
まず、attribute_condition(属性条件)について解説します。
これは attribute_mapping(属性マッピング)の結果に対して適用される条件式です。
例えば、AWS から受け取る assertion.arn の値が
arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role/session123
であった場合、attribute_mapping を用いて
attribute.aws_role に
arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role
という値を抽出します。
これにより、実行ごとに変わるセッション名に依存せず、IAM Role 単位での制御が可能になります。
では、attribute_condition をどのように設定するかですが、Role ARN を完全一致で列挙する方式と、プレフィックス(接頭辞)でパターンマッチングする方式があります。
完全一致で列挙する場合:
== "{workload-a の ARN}"
| == "{workload-b の ARN}"
この方法では、新しいワークロードが追加されるたびに Provider の attribute_condition を更新する必要があり、管理コストが高くなります。❌ 却下
一方、プレフィックスでパターンマッチングする方式:
startsWith("...assumed-role/gcp-wif-")
を採用した attribute_condition は、
attribute.aws_role.startsWith('arn:aws:sts::111111111111:assumed-role/gcp-wif-')
のように記述します。
- principalSet: Pool 全体許可 vs 個別 Role 指定
roles/iam.workloadIdentityUser の指定方法には粒度の違いがあり、Pool 全体を許可するか、特定の属性値(assumed-role ARN)で絞り込むかを選べます。
Pool 全体を許可する場合:
principalSet://.../{pool}/*
特定の属性値で絞り込む場合:
principalSet://.../attribute.aws_role/{assumed-role ARN}
プール全体での許可では、Workload A 用の GCP フェデレーションロールが Workload B のサービスアカウントをインパーソネートできてしまい、ワークロード間の分離が壊れてしまいます。個別指定であれば、「この AWS ロールはこのサービスアカウントのみ」という 1:1 の対応を強制できます。
GCP 側の Terraform(プール/プロバイダー/IAM バインディング)
Workload Identity Pool / Provider
WIF 専用プロジェクト
resource "google_iam_workload_identity_pool" "aws_pool" {
project = "my-wif-project"
workload_identity_pool_id = "aws-workload-id"
display_name = "AWS Workload Identity Pool"
description = "Federation from AWS Security Account"
}
resource "google_iam_workload_identity_pool_provider" "aws_provider" {
project = "my-wif-project"
workload_identity_pool_id = google_iam_workload_identity_pool.aws_pool.workload_identity_pool_id
workload_identity_pool_provider_id = "security-account"
display_name = "AWS Security Account Provider"
aws {
account_id = "111111111111" # セキュリティアカウント ID
}
attribute_mapping = {
"google.subject" = "assertion.arn" # セッション名を除去して assumed-role ARN に変換
"attribute.aws_role" = "assertion.arn.contains('assumed-role') ? assertion.arn.extract('{account_arn}assumed-role/') + 'assumed-role/' + assertion.arn.extract('assumed-role/{role_name}/') : assertion.arn"
}
# 命名規則に合致する assumed-role のみ受け入れ
attribute_condition = "attribute.aws_role.startsWith('arn:aws:sts::111111111111:assumed-role/gcp-wif-')"
}
Service Account と IAM Binding(workload-a 例)
サービスプロジェクト側で作る想定
resource "google_service_account" "workload_a" {
project = "my-service-project"
account_id = "workload-a"
display_name = "Service Account for workload-a"
}
重要: principalSet は PROJECT_NUMBER を使う(PROJECT_ID ではない)
resource "google_service_account_iam_binding" "workload_a_wif_user" {
service_account_id = google_service_account.workload_a.name
role = "roles/iam.workloadIdentityUser"
members = [
"principalSet://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/aws-workload-id/attribute.aws_role/arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role"
]
}
新ワークロード追加時の担当タスク
AWS(Security): GCP Federation 用 IAM Role を追加
GCP: ワークロード専用 SA (Service Account) を作成し、必要最小限の権限を付与
GCP: SA に roles/iam.workloadIdentityUser を付与
AWS(Workload): 実行ロールに GCP Federation 用ロールへの AssumeRole 権限を付与
管理者側の GCP 作業 (SA 作成 + IAM Binding) は以下のような Terraform で管理できます:
ワークロード専用 SA
resource "google_service_account" "workload_a" {
project = "my-wif-project"
account_id = "workload-a"
display_name = "Service Account for workload-a"
}
IAM Binding: GCP フェデレーション用ロール → SA
aws_iam_role.gcp_wif_workload_a は Security Account 側で定義した GCP フェデレーション用ロール
resource "google_service_account_iam_binding" "workload_a_wif_user" {
service_account_id = google_service_account.workload_a.name
role = "roles/iam.workloadIdentityUser"
members = [
# IAM Role ARN (arn:aws:iam::...) を STS assumed-role ARN 形式に変換
"principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.aws_pool.name}/attribute.aws_role/arn:aws:sts::${data.aws_caller_identity.security.account_id}:assumed-role/${aws_iam_role.gcp_wif_workload_a.name}"
]
}
命名規則に従う限り、Provider の attribute_condition
補足:管理権限もセットで設計する
WIF(Workload Identity Federation)の設計とあわせて、以下のようなガードレールも検討しておくと安心です。
サービスアカウントキー作成禁止(組織ポリシー)を有効化して、長期鍵が増えないようにする
WIF の Pool/Provider を勝手に作られないように、権限や組織ポリシー(カスタム制約)で縛る
この設計を検証する中で苦労した点を紹介します。
1) コンポーネントが多く、トラブルシューティングが難しい
WIF は AWS と GCP を跨ぎ、IAM Role、STS(Security Token Service)、Provider、Pool、SA など関連するコンポーネントが多いです。問題が発生した場合は、推測ではなくログをもとに原因を切り分けていくのが確実です。
AWS: AssumeRole
どのロールがどのロールを AssumeRole したか
GCP: トークン交換(Token exchange)
Cloud Audit Logs (iam.googleapis.com)
attribute_condition の成否など
GCP: SA インパーソネーション(SA impersonation)
Cloud Audit Logs (iam.googleapis.com)
どのフェデレーション ID がどの SA をインパーソネートしたか
DWD など Workspace 側の監査
2) AssumeRole 時の環境変数の扱いに注意(Lambda など)
例えば Lambda で Google Cloud クライアントライブラリ(Python の google-auth)
google-auth-library
AWS_ACCESS_KEY_ID
Lambda では起動時に実行ロールの認証情報が環境変数にセットされています。AssumeRole 後の認証情報で環境変数を上書きすると、以降の AWS SDK 呼び出しも AssumeRole 後の認証情報で動作してしまいます。つまり、元の実行ロールに付与していた権限が使えなくなります。
今回は try-finally
const prev = { accessKeyId: process.env.AWS_ACCESS_KEY_ID, /* ... */ }; try { process.env.AWS_ACCESS_KEY_ID = assumedCreds.AccessKeyId; // ... WIF 処理 (GCP クライアントライブラリ経由) } finally { process.env.AWS_ACCESS_KEY_ID = prev.accessKeyId; // 必ず元に戻す }
入口 (Security Account) と権限 (GCP 側の SA) を分け、WIF を専用プロジェクトに集約すると、マルチアカウントでも運用しやすい
Provider は「受け入れ条件」、IAM Binding は「実際の権限」と役割分担すると設計が整理できる
attribute_mapping
ログ (CloudTrail / Cloud Audit Logs / Workspace 監査ログ) を前提に、切り分け可能な形にしておく
Workload Identity Federation | Google Cloud
Configure Workload Identity Federation with AWS or Azure | Google Cloud
Download credential configuration and grant access | Google Cloud(principalSet の形式と使用方法)
Domain-Wide Delegation | Google Workspace Admin Help
Restricting service account usage | Google Cloud
Custom organization policies for WIF | Google Cloud
サービス アカウント認証用のロール | Google Cloud(roles/iam.workloadIdentityUser
許可ポリシーについて | Google Cloud(IAM Binding の説明)
今回は、マルチアカウントな AWS 環境から GCP/Google Workspace に安全にアクセスするために、Workload Identity Federation をどう設計したかをまとめました。運用はこ
原文を表示
LayerX Fintech 事業部から、三井物産デジタル・アセットマネジメント(以下、MDM) に出向している piroshi です。
AI 活用や業務自動化が当たり前になってきた今、データや処理はプラットフォームをまたいで動くことが増えています。特に「システム基盤はAWSで動かしつつ、社内業務は Google Workspace 前提」といった構成では、AWS 上のワークロードから Google Cloud(以下、GCP) や Google Workspace の API へ安全にアクセスしたい場面が自然に出てきます。
MDM でもそのニーズが顕在化しました。具体的には、共有ドライブの構成情報を定期的に取得して監査(権限・設定の棚卸し)を自動化したい、という要件があります。加えて、別のチームでは Google Drive 上のリソースにアクセスする業務ツール開発も並行して進んでいました。ここでチームごとに認証方式が増えていくと、長期鍵の配布・権限の肥大化・監査のしづらさといった問題が起きやすくなります。そこで、個別最適に寄せるのではなく、安全で監査可能な共通のアクセス方式を用意することを目標に設計を検討しました。
サービスアカウントキーを発行して AWS 側に置けば動きますが、長期鍵の配布・ローテーション・棚卸しは運用負荷が高く、漏えい時の影響も大きくなります。今回は Workload Identity Federation(WIF) を使い、静的キーを持たずに短命トークンでアクセスする構成を設計しました。
WIF を使った実装の情報は多く見つかりましたが、AWS がマルチアカウント構成の場合にどう設計すべきかについて触れているものがなかなか見つからず、さらに、GCP のベストプラクティスに沿って「WIF を専用プロジェクトに集約する」構成を採ると、具体的にどう設計・運用が変わるのかイメージが湧きにくかったです。
この記事では、「AWS Organizations を使ったマルチアカウント環境」で、「GCP 側へ出ていく認証経路(入口)を運用・統制の都合で Security アカウントに集約」しつつ、「ワークロード単位で識別して最小権限を保つ」ためにどう設計したかをまとめます。検証時にハマったポイントとあわせて共有できればと思います。
なお、記事では AWS→GCP へのフェデレーションに焦点を当てています。Google Workspace API を操作する場合の Domain-Wide Delegation(DWD)設定については、ここでは扱いません。
AWS Organizations を使ったマルチアカウント戦略を採用している
Google 側へ出ていく認証経路(入口)を、運用・統制の都合で Security アカウントに集約したい
そのうえで、「ワークロード単位で識別して最小権限を付与」を維持する
結論: 「入口」と「権限」を分けた 2 段階のアクセス制御
採用した構成は以下です。まず認証フローの概要を示します。
flowchart LR subgraph AWS_Org[AWS Organizations] subgraph Workloads[Workload Accounts] WL_A[Workload Account A] WL_B[Workload Account B] end Security[Security Account] end subgraph GCP_Org[GCP Organization] subgraph WIF_Proj[WIF 専用プロジェクト] WIF[WIF Pool/Provider] end subgraph Service_Projs[サービスプロジェクト群] SA_A[SA / Resources A] SA_B[SA / Resources B] end end WL_A -->|1. Cross-Account AssumeRole| Security WL_B -->|1. Cross-Account AssumeRole| Security Security -->|2. Token Exchange| WIF WIF -->|3. Impersonate| SA_A WIF -->|3. Impersonate| SA_B
Service Account(SA)の権限で GCP リソースにアクセスします。Google Workspace API を使う場合は、SA に Domain-Wide Delegation(DWD)を付与してユーザーとして操作する構成になります。
この構成では、認証フローの各ステップでログが取得できます。
AWS: AssumeRole
どのロールがどのロールを AssumeRole したか
GCP: Token exchange
Cloud Audit Logs(WIF プロジェクト)
attribute_condition の成否、どのフェデレーション ID がトークン交換したか
GCP: SA impersonation
Cloud Audit Logs(SA のプロジェクト)
どのフェデレーション ID がどの SA を impersonate したか
OAuth ログ、各サービス監査ログ(Drive 等)
Google Workspace へのアクセス状況
WIF 専用プロジェクトと SA のプロジェクトが分かれていても、それぞれのプロジェクトで Cloud Audit Logs が記録されるため、追跡が可能です。
設計思想: 2段階のアクセス制御
attribute_condition
想定外のアカウント/ロールを入口で落とす
第2段階: Service Account
ワークロード単位の権限分離(最小権限)
principalSet とは: WIF のフェデレーション ID(federated identity)を指定するための識別子です。属性に基づいて「どのフェデレーション ID に権限を付与するか」を定義します。
形式: principalSet://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/attribute.{ATTRIBUTE_NAME}/{ATTRIBUTE_VALUE}
例: principalSet://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/aws-workload-id/attribute.aws_role/arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role
arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role
Pool に到達できても、SA への IAM Binding がなければフェデレーション ID は impersonate できません。
Workload Account の実行ロール(IAM Role)から、Security Account 上の GCP Federation 用ロール(IAM Role)にクロスアカウント AssumeRole
そのロールの AWS 認証情報で、WIF が必要とする署名付き GetCallerIdentity 相当の情報を作り、Google STS へトークン交換
Provider の attribute_condition
SA に対する roles/iam.workloadIdentityUser
SA の権限で GCP リソース (必要なら DWD で Workspace API) にアクセス
補足: WIF が識別する「AWS 側の ID」とは
WIF が AWS 側の ID を識別する際に使うのは、STS の GetCallerIdentity
arn:aws:sts::{ACCOUNT_ID}:assumed-role/{ROLE_NAME}/{SESSION_NAME}
セッション名は実行ごとに変わるため、WIF の Pool 側の設定(attribute_mapping
arn:aws:sts::{ACCOUNT_ID}:assumed-role/{ROLE_NAME}
ARN のうち、ユーザー側でコントロールできるのは IAM Role の名前です。そのため、命名規則を統一することで attribute_condition
設計で検討した 5 つのポイント
- GCP プロジェクト構成: 既存のプロジェクトを利用 vs 専用プロジェクトを新設
既存プロジェクトに WIF リソースを追加
WIF 専用プロジェクトを新規作成
GCP のベストプラクティスで「専用のプロジェクトを使用して Workload Identity プールとプロバイダを管理する」ことが推奨されている
セキュリティ境界の明確化(他リソースと分離)
WIF の管理権限(誰が Pool/Provider を触れるか)を分離・集中管理できる
一貫した attribute_mapping や attribute_condition を適用できる
外部からのフェデレーション経路を一箇所に集約することで、監視・監査すべきポイントが明確になり、セキュリティ上の攻撃対象領域を限定できる
WIF を専用プロジェクトに集約し、実際のアクセス先となる SA が別のプロジェクトにあってもアクセスできるのかが懸念でしたが、SA に対して roles/iam.workloadIdentityUser
- AWS IAM Role 構成: 単一共有 vs ワークロード別分離
この設計では、AWS 側に 2 種類の IAM Role が登場します。
Workload Account
Lambda や ECS タスクなど、ワークロードが実行時に使用するロール。ワークロードごとに異なる。
GCP Federation 用ロール
Security Account
GCP への認証(WIF)に使用するロール。実行ロールから AssumeRole される。
ここで検討するのは、Security Account の GCP Federation 用ロールを、全ワークロードで共有するか、ワークロードごとに分けるかです。
全ワークロードで共有する単一の GCP Federation 用ロール
ワークロードごとに個別の GCP Federation 用ロールを作成
前提として、各ワークロードが必要とする権限(AWS 側のアクセス先リソースや、GCP 側で取得したい SA の権限)が異なる場合、実行ロールをワークロードごとに分けるのが自然です。
しかし、入口を Security Account に集約する設計では、GCP から見えるのは Security Account 側の「GCP Federation 用ロール」です(厳密には、識別できるのは STS ARN で、そのなかに IAM Role Name が含まれます)。GCP 側で利用できる属性は GetCallerIdentity 由来の情報(account/arn/userid
よって、ワークロード単位の分離を GCP 側で実現するには、GCP Federation 用ロールもワークロードごとに分ける必要があります。
AWS(Security Account): GCP Federation 用ロール(例: workload-a)
Security Account 側(ID: 111111111111) # - SA へのアクセスを許可するワークロードの実行ロールからの AssumeRole を許可 # - AWS リソースへのアクセス権限は不要なため、信頼ポリシーのみ定義(IAM ポリシーのアタッチなし) resource "aws_iam_role" "gcp_wif_workload_a" { name = "gcp-wif-workload-a-role" assume_role_policy = data.aws_iam_policy_document.trust_from_workload_a_exec.json } data "aws_iam_policy_document" "trust_from_workload_a_exec" { statement { effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "AWS" identifiers = [ "arn:aws:iam::222222222222:role/workload-a-exec-role" ] } } }
AWS(Workload Account A): 実行ロールに AssumeRole 権限を付与
Workload Account A 側 (ID: 222222222222) # Security Account の GCP Federation 用ロールへの AssumeRole を許可 data "aws_iam_policy_document" "allow_assume_gcp_wif" { statement { effect = "Allow" actions = ["sts:AssumeRole"] resources = ["arn:aws:iam::111111111111:role/gcp-wif-workload-a-role"] } } resource "aws_iam_role_policy" "workload_a_exec_assume_gcp_wif" { name = "assume-gcp-wif" role = aws_iam_role.workload_a_exec.name policy = data.aws_iam_policy_document.allow_assume_gcp_wif.json }
- attribute_condition: 完全一致 vs パターンマッチ
まず、attribute_condition
attribute_mapping
attribute_condition
条件式の中では attribute_mapping
attribute_mapping
例えば、AWS から受け取る assertion.arn
arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role/session123
attribute_mapping
attribute.aws_role
arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role
これにより、実行ごとに変わるセッション名に依存せず、IAM Role 単位での制御が可能になります。
では、attribute_condition
Role ARN を完全一致で列挙
`== "{workload-a の ARN}"
| == "{workload-b の ARN}"` | ❌ 却下
prefix でパターンマッチ
startsWith("...assumed-role/gcp-wif-")
完全一致で列挙する方法では、ワークロード追加のたびに Provider の attribute_condition
attribute_condition
採用した attribute_condition
attribute.aws_role.startsWith('arn:aws:sts::111111111111:assumed-role/gcp-wif-')
- principalSet: Pool 全体許可 vs 個別 Role 指定
roles/iam.workloadIdentityUser
指定方法には粒度の違いがあり、Pool 全体を許可するか、特定の属性値(assumed-role ARN)で絞り込むかを選べます。
principalSet://.../{pool}/*
principalSet://.../attribute.aws_role/{assumed-role ARN}
Pool 全体許可では、Workload A 用の GCP Federation ロールが Workload B の SA を impersonate できてしまい、ワークロード間の分離が壊れます。個別指定なら「この AWS ロールはこの SA だけ」という 1:1 の対応を強制できます。
GCP 側 Terraform(Pool / Provider / IAM Binding)
Workload Identity Pool / Provider
WIF 専用プロジェクト resource "google_iam_workload_identity_pool" "aws_pool" { project = "my-wif-project" workload_identity_pool_id = "aws-workload-id" display_name = "AWS Workload Identity Pool" description = "Federation from AWS Security Account" } resource "google_iam_workload_identity_pool_provider" "aws_provider" { project = "my-wif-project" workload_identity_pool_id = google_iam_workload_identity_pool.aws_pool.workload_identity_pool_id workload_identity_pool_provider_id = "security-account" display_name = "AWS Security Account Provider" aws { account_id = "111111111111" # Security Account ID } attribute_mapping = { "google.subject" = "assertion.arn" # セッション名を除去して assumed-role ARN に変換 "attribute.aws_role" = "assertion.arn.contains('assumed-role') ? assertion.arn.extract('{account_arn}assumed-role/') + 'assumed-role/' + assertion.arn.extract('assumed-role/{role_name}/') : assertion.arn" } # 命名規則に合致する assumed-role のみ受け入れ attribute_condition = "attribute.aws_role.startsWith('arn:aws:sts::111111111111:assumed-role/gcp-wif-')" }
Service Account と IAM Binding(workload-a 例)
サービスプロジェクト側で作る想定 resource "google_service_account" "workload_a" { project = "my-service-project" account_id = "workload-a" display_name = "Service Account for workload-a" } # 重要: principalSet は PROJECT_NUMBER を使う(PROJECT_ID ではない) resource "google_service_account_iam_binding" "workload_a_wif_user" { service_account_id = google_service_account.workload_a.name role = "roles/iam.workloadIdentityUser" members = [ "principalSet://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/aws-workload-id/attribute.aws_role/arn:aws:sts::111111111111:assumed-role/gcp-wif-workload-a-role" ] }
新ワークロード追加時の担当タスク
AWS(Security): GCP Federation 用 IAM Role を追加
GCP: ワークロード専用 SA を作成し、必要最小限の権限を付与
GCP: SA に roles/iam.workloadIdentityUser
AWS(Workload): 実行ロールに GCP Federation 用ロールへの AssumeRole 権限を付与
管理者側の GCP 作業(SA 作成 + IAM Binding)は以下のような Terraform で管理できます:
ワークロード専用 SA resource "google_service_account" "workload_a" { project = "my-wif-project" account_id = "workload-a" display_name = "Service Account for workload-a" } # IAM Binding: GCP Federation 用ロール → SA # aws_iam_role.gcp_wif_workload_a は Security Account 側で定義した GCP Federation 用ロール resource "google_service_account_iam_binding" "workload_a_wif_user" { service_account_id = google_service_account.workload_a.name role = "roles/iam.workloadIdentityUser" members = [ # IAM Role ARN (arn:aws:iam::...) を STS assumed-role ARN 形式に変換 "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.aws_pool.name}/attribute.aws_role/arn:aws:sts::${data.aws_caller_identity.security.account_id}:assumed-role/${aws_iam_role.gcp_wif_workload_a.name}" ] }
命名規則に従う限り、Provider の attribute_condition
補足: 管理権限もセットで設計する
WIF の設計とあわせて、以下のようなガードレールも検討しておくと安心です。
サービスアカウントキー作成禁止(組織ポリシー)を有効化して、長期鍵が増えないようにする
WIF の Pool/Provider を勝手に作られないように、権限や組織ポリシー(カスタム制約)で縛る
この設計を検証する中で苦労した点を紹介します。
1) コンポーネントが多く、トラブルシューティングが難しい
WIF は AWS と GCP を跨ぎ、IAM Role, STS, Provider, Pool, SA など関連するコンポーネントが多いです。問題が発生した場合は、推測ではなくログをもとに原因を切り分けていくのが確実です。
AWS: AssumeRole
どのロールがどのロールを AssumeRole したか
GCP: Token exchange
Cloud Audit Logs(iam.googleapis.com)
attribute_condition の成否など
GCP: SA impersonation
Cloud Audit Logs(iam.googleapis.com)
どのフェデレーション ID がどの SA を impersonate したか
DWD など Workspace 側の監査
2) AssumeRole 時の環境変数の扱いに注意(Lambda など)
例えば Lambda で Google Cloud クライアントライブラリ(Python の google-auth
google-auth-library
AWS_ACCESS_KEY_ID
Lambda では起動時に実行ロールの認証情報が環境変数にセットされています。AssumeRole 後の認証情報で環境変数を上書きすると、以降の AWS SDK 呼び出しも AssumeRole 後の認証情報で動作してしまいます。つまり、元の実行ロールに付与していた権限が使えなくなります。
今回は try-finally
const prev = { accessKeyId: process.env.AWS_ACCESS_KEY_ID, /* ... */ }; try { process.env.AWS_ACCESS_KEY_ID = assumedCreds.AccessKeyId; // ... WIF 処理(GCP クライアントライブラリ経由) } finally { process.env.AWS_ACCESS_KEY_ID = prev.accessKeyId; // 必ず元に戻す }
入口(Security Account)と権限(GCP 側の SA)を分け、WIF を専用プロジェクトに集約すると、マルチアカウントでも運用しやすい
Provider は「受け入れ条件」、IAM Binding は「実際の権限」と役割分担すると設計が整理できる
attribute_mapping
ログ(CloudTrail / Cloud Audit Logs / Workspace 監査ログ)を前提に、切り分け可能な形にしておく
Workload Identity Federation | Google Cloud
Configure Workload Identity Federation with AWS or Azure | Google Cloud
Download credential configuration and grant access | Google Cloud(principalSet の形式と使用方法)
Domain-Wide Delegation | Google Workspace Admin Help
Restricting service account usage | Google Cloud
Custom organization policies for WIF | Google Cloud
サービス アカウント認証用のロール | Google Cloud(roles/iam.workloadIdentityUser
許可ポリシーについて | Google Cloud(IAM Binding の説明)
今回は、マルチアカウントな AWS 環境から GCP/Google Workspace に安全にアクセスするために、Workload Identity Federation をどう設計したかをまとめました。運用はこ
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み