SJ blog
security
S

信頼度ランク

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の評価順序

まず結論

AssumeRoleのAccessDeniedは、次のどこかで起きます。

失敗場所典型原因
呼び出し側sts:AssumeRole が対象ロールARNに許可されていない
呼び出し側permissions boundaryやSCPがDenyしている
trust policyPrincipalが違う
trust policyExternal 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 を付ける方が監査しやすいです。

クロスアカウントでは、基本的に両方が必要です。

  1. 呼び出し元アカウントのprincipalに sts:AssumeRole を許可
  2. 引き受け先アカウントのrole trust policyで呼び出し元を信頼

クロスアカウントAssumeRole設計

クロスアカウントの最小構成

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:PassRoleAWSサービスにロールを渡す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種類のイベントを見ます。

  1. STSのAssumeRoleイベント
  2. assumed-roleセッションが実行した後続APIイベント

AssumeRoleイベントでは、次を見ます。

  • userIdentity: 誰がAssumeRoleを呼んだか
  • requestParameters.roleArn: どのロールを引き受けたか
  • requestParameters.roleSessionName: セッション名
  • requestParameters.externalId: 外部IDの有無
  • requestParameters.sourceIdentity: SourceIdentity
  • responseElements.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にAccessDeniedrole 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とは別物

参考