- 公開日
- 最終更新日
【クロスアカウントでの混乱した代理】図解で理解するAssumeRoleのリスクと対策
この記事を共有する
目次
はじめに
先日、「混乱した代理」問題¹ の項目「サービス間の混乱した代理の防止」を読み解く記事を作成しました。
「混乱した代理」問題には他にも、項目「クロスアカウントでの混乱した代理」があります。
初めて読んだときは理解できませんでしたが、改めて読むことで、以下の内容を理解しました。
- IAM ロールでクロスアカウントの AssumeRole を許可すると、許可したアカウントを経由して、意図しないユーザーから不正なアクセスが発生する可能性があります。
- この不正なアクセスを防止するため、IAM ロールの信頼ポリシーに外部 ID (ExternalId)を含めることで、信頼したアカウントのみアクセスを許可します。
「不正なアクセス」がなぜ発生するのかは、図解しながら順序立てて読み解くことが重要です。
本記事では AWS ドキュメントの例示¹を参考に、「クロスアカウントでの混乱した代理」を図解で説明します。
以下、固有情報は筆者が {} で囲って匿名化しています。
0.説明の前提
0-1.コスト最適化サービスの提供
AWS アカウント(以下、「アカウント」)のリソースについて、コスト最適化を提案する SaaS サービス(以下、「サービス」)があるとします。
このサービスは、顧客が管理するアカウントにアクセスし、モニタリングをする必要があります。
顧客はブラウザ経由でサービスのコンソール画面にアクセスし、保有するリソース情報を参照できます。
本記事では、例として Amazon EC2 インスタンス(以下、「インスタンス」)を参照します。

0-2.サービスによるアカウントへのアクセス
サービスは顧客のアカウント上の IAM ロールへ AssumeRole をして、顧客の「代理」としてリソース情報を取得します。
ここでの「代理」とは、信頼ポリシーに基づいて IAM ロールを引き受け(AssumeRole)、付与された権限でリソースを操作できる関係を指します。
取得したリソース情報は、サービス内で処理したうえで Web サーバーへ連携し、コンソール画面を通じて顧客に提供します。

1.「混乱した代理」の発生
1-1.A社 サービス利用開始
A社はコスト最適化サービスの導入を決め、そのためにサービス会社と契約を結びました。
契約開始に伴い、サービス会社から以下 2 つの情報が提供されます。
- サービスが稼働している アカウント ID
- サービスのコンソール画面 ログイン ID

1-2.A社 IAM ロールの作成
A社 アカウントに、サービスが必要とするポリシー(describe-instances など)をアタッチした IAM ロールを作成します。
IAM ロールの信頼ポリシーでは、サービス会社 アカウントを信頼する対象に設定します。
A社 IAM ロールの信頼ポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{サービス会社 アカウントID}:root"
},
"Action": "sts:AssumeRole"
}
]
}

1-3.A社 IAM ロールの ARN 提供
A社が作成した IAM ロールの ARN をサービス会社に提供します。・・・①
サービス会社はその ARN をサービスに組み込み、A社向けのテナント設定を行います。・・・②

1-4.サービスがA社へアクセス
サービス会社 アカウントに存在する IAM ユーザーが、A社 IAM ロールに対して AssumeRole を実行します。・・・①
IAM ロールはサービス会社 アカウントを信頼しているため、AssumeRole が成功し、一時的なセキュリティ認証情報が払い出されます。・・・②

参考までに、サービス会社 アカウントで実施される処理例を提示します。
クリックして展開
$ # ① AssumeRole の実行と、② 一時的なセキュリティ認証情報の払い出し²
$ aws sts assume-role \
> --role-arn {A社 IAM ロールの ARN} \
> --role-session-name access-to-user-account
{
"Credentials": {
"AccessKeyId": "{AccessKeyId}",
"SecretAccessKey": "{SecretAccessKey}",
"SessionToken": "{SessionToken}",
"Expiration": "2025-12-26T12:00:00+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "{ID}:access-to-user-account",
"Arn": "arn:aws:sts::{A社 アカウント ID}:assumed-role/{A社 IAM ロール名}/access-to-user-account"
}
}
1-5.A社のインスタンス情報を取得
払い出されたセキュリティ認証情報を使用して、サービスが A社 アカウントのインスタンス情報を describe-instances で要求します。・・・①
Amazon EC2 API からレスポンスが返されて、インスタンス情報を取得します。・・・②
取得したインスタンス情報は、A社 テナントのコンソール画面に表示されます。
サービス会社はA社に代わって操作ができる「代理」として信頼されているため、リソース情報を取得できました。

参考までに、サービス会社 アカウントで実施される処理例を提示します。
クリックして展開
$ # セキュリティ認証情報を環境変数に設定³
$ export AWS_ACCESS_KEY_ID="{AccessKeyId}"
$ export AWS_SECRET_ACCESS_KEY="{SecretAccessKey}"
$ export AWS_SESSION_TOKEN="{SessionToken}"
$
$ # ① describe-instances の実行と、② インスタンス情報の取得⁴
$ aws ec2 describe-instances \
> --query 'Reservations[*].Instances[*].{Name:Tags[?Key==`Name`]|[0].Value,InstanceID:InstanceId,InstanceType:InstanceType}' \
> --output json
[
[
{
"Name": "Instance A",
"InstanceID": "{InstanceID}",
"InstanceType": "t3.nano"
}
],
[
{
"Name": "Instance B",
"InstanceID": "{InstanceID}",
"InstanceType": "t2.nano"
}
],
[
{
"Name": "Instance C",
"InstanceID": "{InstanceID}",
"InstanceType": "t3.nano"
}
]
]
1-6.X社 サービス利用開始
A社のサービス利用を知ったX社も、サービス会社と契約しました。

1-7.X社がA社 IAM ロールの ARN を提供
X社は、漏えいや推測によりA社 IAM ロールの ARN を特定しました。
そして、自身のアカウントで作成した IAM ロールであると偽って、サービス会社に提供します。・・・①
サービス会社はその ARN をサービスに組み込み、X社向けのテナント設定を行います。・・・②

1-8.サービスがX社と誤認して、A社へアクセス
サービス会社 アカウントに存在する IAM ユーザーが、X社の IAM ロールに AssumeRole を試みます。
しかし IAM ロールはA社 アカウントに存在するため、実態としてはA社 IAM ロールに対して AssumeRole を実行します。・・・①
IAM ロールはサービス会社 アカウントを信頼しているため、AssumeRole が成功し、一時的なセキュリティ認証情報が払い出されます。・・・②

サービス会社 アカウントで実施される処理例は、「1-4.サービスがA社へアクセス」と同様です。
1-9.X社がA社のリソースに不正アクセス
払い出されたA社のセキュリティ認証情報を使用して、A社 アカウントへインスタンス情報を describe-instances で要求します。・・・①
Amazon EC2 API からレスポンスが返されて、インスタンス情報を取得します。・・・②
取得したインスタンス情報は、X社 テナントのコンソール画面に表示されます。

サービス会社 アカウントで実施される処理例は、「1-5.A社のインスタンス情報を取得」と同様です。
「混乱した代理」問題のポイント
このようにして、X社はA社のリソースへ不正にアクセスできました。
サービス会社はX社に騙されてA社のリソースへアクセスしたため、サービス会社は「混乱した代理」状態といえます。
サービス会社は「混乱した代理」を防止するため、顧客ごとに一意な外部 ID (ExternalId) を作成・管理します。
外部 ID は、顧客のアカウントで作成する IAM ロールの信頼ポリシーの条件(Condition)に含めます。
サービス会社は顧客の IAM ロールへ AssumeRole をするとき、外部 ID を含めてリクエストします。
これにより、想定と異なるアカウントへの AssumeRole を防止できます。
続いて、外部 ID を使用した「混乱した代理」の防止を図解で説明します。
※説明では簡略化した外部 ID を例示しますが、顧客間で GUID が一意の場合、GUID を外部 ID として使用するのが適切¹です。
2.「混乱した代理」の防止
2-1.A社 サービス利用開始
A社はコスト最適化サービスの導入を決め、そのためにサービス会社と契約を結びました。
このとき、サービス会社から 外部 ID「12345」が提供されます。

2-2.A社 IAM ロールの作成
A社 アカウントに、サービスが必要とするポリシー(describe-instances など)をアタッチした IAM ロールを作成します。
「1-2.A社 IAM ロールの作成」と異なり、信頼ポリシーの条件に外部 ID「12345」を指定しています。
A社 IAM ロールの信頼ポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{サービス会社 アカウントID}:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "12345"
}
}
}
]
}

2-3.A社 IAM ロールの ARN 提供
A社が作成した IAM ロールの ARN をサービス会社に提供します。・・・①
サービス会社はその ARN をサービスに組み込み、A社向けのテナント設定を行います。・・・②

2-4.サービスがA社へアクセス
サービス会社 アカウントに存在する IAM ユーザーが、A社 IAM ロールに対して外部 ID「12345」を含めて AssumeRole を実行します。・・・①
外部 ID「12345」は IAM ロールの信頼ポリシーの条件と一致するため、AssumeRole が成功し、一時的なセキュリティ認証情報が払い出されます。・・・②

参考までに、サービス会社 アカウントで実施される処理例を提示します。
クリックして展開
$ # ① AssumeRole の実行と、② 一時的なセキュリティ認証情報の払い出し²
$ aws sts assume-role \
> --role-arn {A社 IAM ロールの ARN} \
> --role-session-name access-to-A \
> --external-id "12345"
{
"Credentials": {
"AccessKeyId": "{AccessKeyId}",
"SecretAccessKey": "{SecretAccessKey}",
"SessionToken": "{SessionToken}",
"Expiration": "2025-12-26T12:00:00+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "{ID}:access-to-A",
"Arn": "arn:aws:sts::{A社 アカウント ID}:assumed-role/{A社 IAM ロール名}/access-to-A"
}
}
2-5.A社のインスタンス情報を取得
払い出されたセキュリティ認証情報を使用して、サービスが A社 アカウントのインスタンス情報を describe-instances で要求します。・・・①
Amazon EC2 API からレスポンスが返されて、インスタンス情報を取得します。・・・②

サービス会社 アカウントで実施される処理例は、「1-4.サービスがA社へアクセス」と同様です。
2-6.X社 サービス利用開始
A社のサービス利用を知ったX社も、サービス会社と契約しました。
このとき、サービス会社から 外部 ID「67890」が提供されます。

2-7.X社がA社 IAM ロールの ARN を提供
X社は、漏えいや推測によりA社 IAM ロールの ARN を特定しました。
そして、自身のアカウントで作成した IAM ロールであると偽って、サービス会社に提供します。・・・①
サービス会社はその ARN をサービスに組み込み、X社向けのテナント設定を行います。・・・②

2-8.X社と誤認したA社へのアクセスを拒否
サービス会社 アカウントに存在する IAM ユーザーが、X社の IAM ロールに AssumeRole を試みます。
X社の外部 ID は「67890」のため、A社 IAM ロールに対して外部 ID「67890」を含めて AssumeRole を実行します。・・・①
外部 ID「67890」は IAM ロールの信頼ポリシーの条件と一致しないため、AssumeRole が拒否されます。・・・②
外部 ID はサービス会社が管理するため、X社は外部 ID を変更することはできません。

参考までに、サービス会社 アカウントで実施される処理例を提示します。
クリックして展開
$ # ① AssumeRole の実行と、② AssumeRole の拒否
$ aws sts assume-role \
> --role-arn {A社 IAM ロールの ARN} \
> --role-session-name access-to-X \
> --external-id "67890"
An error occurred (AccessDenied) when calling the AssumeRole operation: User: {サービス会社 IAM ユーザー ARN} is not authorized to perform: sts:AssumeRole on resource: {A社 IAM ロールの ARN}
2-9.A社のリソース情報が保護される
A社のセキュリティ認証情報が払い出されないため、サービスはA社 アカウントへアクセスできません。
X社はサービスのコンソール画面を見ても、A社 アカウントのリソース情報を取得できません。
このように外部 ID を使用することで、「混乱した代理」を防止できることが分かりました。

まとめ
本記事では AWS ドキュメントの例示¹を参考に、「混乱した代理」問題の項目 「クロスアカウントでの混乱した代理」を図解で説明しました。
内容のポイントは、以下 2 点です。
- IAM ロールでクロスアカウントの AssumeRole を許可すると、許可したアカウントを経由して、意図しないユーザーから不正なアクセスが発生する可能性があります。
- この不正なアクセスを防止するため、IAM ロールの信頼ポリシーに外部 ID (ExternalId)を含めることで、信頼したアカウントのみアクセスを許可します。
本記事が少しでもお役に立てば幸いです。
おまけ
AWS マネジメントコンソールの IAM ロール作成画面において、「信頼されたエンティティタイプ」で「AWS アカウント」を選択すると、以下画像⁵のとおりオプションとして外部 ID の要求を設定できます。

画像に記載⁵の以下 2 点は、外部 ID に関して重要な情報と考えます。
- ベストプラクティス
外部 ID を要求する (サードパーティがこのロールを引き受ける場合のベストプラクティス)
- 外部 ID のサポート
コンソールでは、[ロールの切り替え] 機能での外部 ID の使用はサポートされていません。
参考文献
¹ "「混乱した代理」問題 - AWS Identity and Access Management". AWS Documentation. https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/confused-deputy.html, (参照 2025-12-26)
² "AWS SDK または CLI で AssumeRole を使用する - AWS Identity and Access Management". AWS Documentation. https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/sts_example_sts_AssumeRole_section.html, (参照 2025-12-27)
³ "AWS アクセスキー - AWS SDKsとツール". AWS Documentation. https://docs.aws.amazon.com/ja_jp/sdkref/latest/guide/feature-static-credentials.html, (参照 2025-12-27)
⁴ "describe-instances -- AWS CLI 2.32.24 Command Reference". AWS Documentation. https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html, (参照 2025-12-27)
⁵ "ロールを作成 | IAM | Global". Amazon Web Services. https://us-east-1.console.aws.amazon.com/iam/home?region=ap-northeast-1#/roles/create, (参照 2025-12-29)
この記事は私が書きました
Hirano
記事一覧AWSの知見を身につけるため、一大決心でP&Sに入社しました。 目標はシステム改善に大きく貢献できるエンジニアになることです。 簡単な内容であっても自身が戸惑った点を投稿することで、同じ苦労をしている方の助けになれば嬉しいです!