信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
AssumeRoleをSCS視点で完全理解する
AssumeRoleの信頼ポリシー、呼び出し側権限、クロスアカウント、External ID、MFA、セッションポリシー、CloudTrail監査を詳しく解説する。
一言結論
AssumeRoleは『ロールを使うAPI』ではなく、呼び出し側のAllow、引き受け先のtrust policy、セッション後の権限評価をすべて通過して初めて成立する。SCSではクロスアカウント、External ID、MFA、ロールチェーン、CloudTrail上の追跡をセットで読む。
Knowledge Graph 3D
ドラッグ: 回転 / ホイール: ズーム3D記事アーキテクチャ
AssumeRoleを呼び出し前評価、信頼評価、セッション後評価、監査の4段階に分けて設計する。
Caller Permission Layer
責務: 呼び出し元が対象ロールに対してsts:AssumeRoleを実行できるか確認する
障害影響範囲: trust policyが正しくてもAssumeRole呼び出しがAccessDeniedになる
- Identity policy
- Permissions boundary
- SCP
- MFA context
Trust Policy Layer
責務: 引き受け先ロールがどのPrincipalをどの条件で信頼するか定義する
障害影響範囲: 想定外Principalの引き受け、または正当Principalの拒否が起きる
- Principal
- ExternalId
- aws:MultiFactorAuthPresent
- sts:SourceIdentity
- OIDC conditions
Session Authorization Layer
責務: 引き受け後のセッション権限をrole policy、session policy、resource policyで決める
障害影響範囲: AssumeRoleは成功するが、後続APIがAccessDeniedになる
- Role permissions
- Session policy
- Session tags
- Resource policy
境界契約(切り分けポイント)
-
Caller -> sts:AssumeRole
契約: 呼び出し元に対象ロールARNへのsts:AssumeRole Allowがある
検証: aws sts assume-role実行前にiam simulate-principal-policyで確認する
-
STS -> Role Trust Policy
契約: trust policyのPrincipalとConditionが呼び出しリクエストに一致する
検証: ExternalId、MFA、SourceIdentity、session tagsの条件不一致をCloudTrailで確認する
-
Role Session -> Target Resource
契約: 後続APIはロール権限とsession policyの交差、さらにresource policyで評価される
検証: GetCallerIdentityとAccessDeniedのencoded authorization messageを確認する
ビルド検証
- AssumeRole成功後にGetCallerIdentityでassumed-role ARNを確認する
- CloudTrailでAssumeRoleイベントと後続APIを相関する
- 外部ベンダーロールにはExternal ID条件が入っている
この記事はAWS公式ドキュメントを前提に、AssumeRoleをSCS-C03で解ける粒度まで分解します。STS全体の話は別記事で扱い、ここではAssumeRoleに集中します。
AssumeRoleはAWSセキュリティで最も重要な操作のひとつです。クロスアカウント、運用者アクセス、CI/CD、監査、Break Glass、外部ベンダー連携、EKS/GitHub OIDCなど、多くの設計が「ロールを安全に引き受ける」ことで成り立ちます。
SCSで落ちやすいポイントは、AssumeRoleを単純に「ロールを使う」と理解してしまうことです。実際には3段階あります。
1. 呼び出し元は sts:AssumeRole を許可されているか
2. 引き受け先ロールは呼び出し元を信頼しているか
3. 引き受け後のセッションは対象リソースを操作できるか
まず結論
AssumeRoleのAccessDeniedは、次のどこかで起きます。
| 失敗場所 | 典型原因 |
|---|---|
| 呼び出し側 | sts:AssumeRole が対象ロールARNに許可されていない |
| 呼び出し側 | permissions boundaryやSCPがDenyしている |
| trust policy | Principalが違う |
| trust policy | External ID、MFA、SourceIdentity、tag条件が不一致 |
| セッション後 | role policyに対象Actionがない |
| セッション後 | session policyで絞りすぎている |
| リソース側 | S3/KMSなどのresource policyが拒否している |
この表を頭に入れると、SCSの「Allowしているのに失敗する」問題を落としにくくなります。
AssumeRoleで発行される主体
AssumeRoleが成功すると、元のIAM userやroleの権限で動くのではなく、assumed-role principalとして動きます。
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/SecurityAuditRole \
--role-session-name alice-ticket-4832 \
--duration-seconds 3600
その後 get-caller-identity を実行すると、次のようなARNになります。
arn:aws:sts::222222222222:assumed-role/SecurityAuditRole/alice-ticket-4832
CloudTrailでもこのassumed-role ARNが後続操作の主体になります。だからRoleSessionNameに alice やチケットIDなど追跡可能な値を入れる設計が重要です。
同一アカウントとクロスアカウントの違い
AssumeRoleには同一アカウントとクロスアカウントがあります。
同一アカウントでは、trust policyにユーザーやロールを直接Principalとして書くと、resource-based policyとして扱われるため、追加のidentity policyなしでも成立するケースがあります。ただし実務上は、呼び出し側に明示的に sts:AssumeRole を付ける方が監査しやすいです。
クロスアカウントでは、基本的に両方が必要です。
- 呼び出し元アカウントのprincipalに
sts:AssumeRoleを許可 - 引き受け先アカウントのrole trust policyで呼び出し元を信頼
クロスアカウントの最小構成
Account Bにリソースがあり、Account Aから操作したいとします。
Account Bのロールtrust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:role/AuditOperatorRole"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
Account Aの呼び出し元ロールに付けるpolicy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::222222222222:role/SecurityAuditRole"
}
]
}
Account BのSecurityAuditRoleに付けるpermissions policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudtrail:LookupEvents",
"config:SelectResourceConfig",
"securityhub:GetFindings",
"guardduty:ListFindings",
"guardduty:GetFindings"
],
"Resource": "*"
}
]
}
ここで、trust policyは「誰がこのロールを引き受けられるか」を定義します。permissions policyは「引き受けた後に何ができるか」を定義します。この2つを混ぜてはいけません。
External ID: 外部ベンダー連携の必須論点
External IDは、外部ベンダーに自分のAWSアカウントへのアクセスを委任するときに重要です。目的はConfused Deputy問題の防止です。
たとえば監視SaaSが多数の顧客AWSアカウントへアクセスする場合、悪意ある顧客が他社のrole ARNをSaaSに渡し、SaaS経由で他社リソースへアクセスさせようとする可能性があります。External IDは、この取り違えを防ぎます。
trust policyでは次のように書きます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::999999999999:role/VendorServiceRole"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "vendor-generated-customer-7f3a"
}
}
}
]
}
External IDは秘密鍵ではありません。AWS公式も、External IDはロールを閲覧できる権限がある人には見えるものとして扱っています。重要なのは、顧客が勝手に決める値ではなく、ベンダーが顧客ごとに一意な値を発行し、その値をAssumeRole時に必ず送ることです。
SCSでは「第三者ベンダー」「複数顧客」「Confused Deputy」「外部ID」が出たら、External ID条件を含むtrust policyが正解候補です。
MFA条件
人間の運用者が強い権限を引き受ける場合、trust policyでMFAを要求できます。
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:user/alice"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
CLIではMFAデバイスのserial numberとtoken codeを渡します。
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/BreakGlassAdmin \
--role-session-name alice-emergency-20260501 \
--serial-number arn:aws:iam::111111111111:mfa/alice \
--token-code 123456
ただし、サービスロールや自動化ロールにMFAを要求すると実行不能になります。MFA条件は人間の対話的アクセスに向いています。
SourceIdentityで誰がやったかを残す
SourceIdentity は、ロールを引き受ける元の識別子をセッションに持たせるための値です。ロールチェーンしても引き継がれるため、運用者やIdPユーザーを追跡しやすくなります。
trust policy側で要求する例です。
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:role/OperatorRole"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringLike": {
"sts:SourceIdentity": "*@example.com"
}
}
}
AssumeRole時:
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/SecurityAuditRole \
--role-session-name audit-ticket-4832 \
--source-identity alice@example.com
SCSでは「CloudTrailで元のユーザーを追いたい」「ロールチェーン後も識別したい」という要件で出ます。
Session policyで権限を縮小する
AssumeRole時にsession policyを渡すと、そのセッションの権限をさらに絞れます。
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/S3Operator \
--role-session-name upload-ticket-123 \
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::example-bucket/ticket-123/*"
}
]
}'
このセッションは、ロールが持つ権限のうち、session policyと重なる部分だけを使えます。session policyにS3許可を書いても、ロール側にS3許可がなければ使えません。
SCSで「一時的に範囲を絞った権限を与えたい」「ロール自体は広いが今回のセッションでは限定したい」と出たら、session policyが候補です。
Session tagsとABAC
AssumeRole時にsession tagsを渡すと、そのセッションのprincipal tagとして評価に使えます。
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/ProjectOperator \
--role-session-name alice-project-alpha \
--tags Key=Project,Value=alpha Key=Department,Value=security \
--transitive-tag-keys Project
これにより、リソース側で aws:PrincipalTag/Project を参照できます。プロジェクト単位、部署単位、テナント単位のABACに向いています。
注意点は、session tagsを許可するには sts:TagSession が必要なことです。AssumeRoleだけ許可しても、タグ付きAssumeRoleは失敗します。
Role chaining
ロールチェーンは、AssumeRoleで得た一時認証情報を使ってさらにAssumeRoleすることです。
IAM user
-> RoleA session
-> RoleB session
ロールチェーン時は最大セッション期間が1時間に制限されます。RoleBの最大セッション期間を12時間にしても、RoleA sessionからRoleBを引き受けるなら1時間です。
実務では、長時間処理でロールチェーンを使うと途中で期限切れになります。SCSでは「最大セッション期間を12時間にしたのに1時間で切れる」という形で出ます。正解は、ロールチェーン制限を理解して、最終ロールを直接引き受ける、サービス実行ロールを使う、認証経路を見直すことです。
PassRoleとの違い
AssumeRoleとPassRoleは頻出の混同ポイントです。
| 権限 | 意味 | 例 |
|---|---|---|
sts:AssumeRole | 自分がロールを引き受けて一時認証情報を得る | 監査ロールで別アカウントを読む |
iam:PassRole | AWSサービスにロールを渡す | Lambda関数に実行ロールを設定する |
EC2やLambdaに実行ロールを設定する権限はAssumeRoleではなくPassRoleです。ただし、渡されたロールをサービスが引き受けるため、ロールのtrust policyではサービスプリンシパルを信頼します。
Lambda実行ロールのtrust policy例:
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
ユーザーがLambdaにこのロールを設定できるかは iam:PassRole で決まります。Lambdaサービスが実行時にロールを引き受けられるかはtrust policyで決まります。
CloudTrailでの調査
AssumeRole調査では、少なくとも2種類のイベントを見ます。
- STSのAssumeRoleイベント
- assumed-roleセッションが実行した後続APIイベント
AssumeRoleイベントでは、次を見ます。
userIdentity: 誰がAssumeRoleを呼んだかrequestParameters.roleArn: どのロールを引き受けたかrequestParameters.roleSessionName: セッション名requestParameters.externalId: 外部IDの有無requestParameters.sourceIdentity: SourceIdentityresponseElements.assumedRoleUser.arn: 生成されたassumed-role ARN
後続APIイベントでは、userIdentity.sessionContext を見ます。ここにassumed roleの情報、MFAの有無、SourceIdentityなどが現れます。
AccessDeniedの切り分け
AssumeRoleで詰まったら、順番に切ります。
Step 1: 呼び出し元のidentity policy
対象role ARNに sts:AssumeRole があるか
Step 2: permissions boundary / SCP
明示Denyや許可上限で落ちていないか
Step 3: trust policy
Principal、ExternalId、MFA、SourceIdentity、tag条件が一致するか
Step 4: session policy
AssumeRole後のAPIを絞りすぎていないか
Step 5: resource policy
S3 bucket policyやKMS key policyがassumed-role principalを許すか
後続APIのAccessDeniedでは、AssumeRole自体は成功していることが多いです。この場合、trust policyではなく、role permissions、session policy、resource policy、SCP、KMS key policyを見ます。
実務ユースケース
セキュリティ監査ロール
管理アカウントの監査ロールから各メンバーアカウントのSecurityAuditRoleをAssumeRoleします。権限は読み取り中心にし、CloudTrail、Config、Security Hub、GuardDuty、IAM Access Analyzerを参照できる範囲にします。
Break Glass
通常運用では使わない強権限ロールを作り、MFA、SourceIdentity、短いDurationSeconds、CloudTrailアラート、承認チケットを必須にします。SCSでは「緊急時アクセスを監査可能にする」文脈で出ます。
外部ベンダー監視
ベンダーのAWSアカウントをPrincipalにし、External IDを必須にします。権限は読み取り専用から始め、必要なActionだけ追加します。ベンダーにAdministratorAccessを渡す設計は避けます。
CI/CDデプロイ
CI/CD基盤のOIDCまたは管理ロールから、デプロイ先アカウントのDeployRoleをAssumeRoleします。RoleSessionNameにworkflow run IDを入れ、session policyでデプロイ対象stackやprefixに絞ります。
SCSの引っかけ
| 問題文 | 判断 |
|---|---|
| trust policyにAllowしたのに失敗 | 呼び出し元のidentity policy、boundary、SCPを見る |
| AssumeRoleは成功したがS3にAccessDenied | role policy、session policy、S3 bucket policyを見る |
| 外部SaaSへアクセス委任 | External ID必須 |
| 人間の強権限ロール | MFA、SourceIdentity、短いDuration、CloudTrail |
| ロールチェーンで12時間使いたい | 最大1時間制限で不可 |
| Lambdaにロールを設定できない | iam:PassRole を見る |
| GitHub OIDCで想定外repoが使える | trust policyのaud/sub条件を絞る |
| 誰が操作したか不明 | RoleSessionNameとSourceIdentity設計を見直す |
試験直前チェック
- AssumeRoleには呼び出し側Allowと引き受け先trust policyの両方が重要
- trust policyは「誰が引き受けられるか」、permissions policyは「引き受け後に何ができるか」
- External IDは外部ベンダー連携でConfused Deputyを防ぐ
- MFA条件は人間の強権限アクセスに向く
- session policyは権限追加ではなく権限縮小
- session tagsには
sts:TagSessionが必要 - SourceIdentityはロールチェーン後も元の識別子を追う助けになる
- role chainingは最大1時間
- PassRoleはサービスにロールを渡す権限で、AssumeRoleとは別物