1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWSでAssumeRoleって2回連続でできるの?試してみたら普通にできた話(ロールチェイニング)

1
Posted at

はじめに

AWSでは、実は IAMロール①をAssumeした状態からさらにIAMロール②をAssumeすること(ロールチェイニング) ができます。
この記事ではロールチェイニングについて調べた内容をご紹介します。

今回調べようと思ったのは、構築中の仕組みのテストで利用できると便利だったためです。

image.png

構築中の仕組みでは図1のように、LambdaからのクロスアカウントS3アクセスにおける認証認可でAssumeRoleを使う構成になっています。

ただし、双方のAWSアカウントで認証認可設定を正しく設定できているかを事前検証するタイミングでは、Lambda関数を実際に動かして試すのが難しいという事情がありました。
そこで、アカウントA側のIAMユーザーでLambdaの実行ロールをAssume し、 その状態でさらにS3アクセス用のロールをAssume してS3アクセスが可能かを確認することを計画しました。
そこで出てきたのが、今回のロールチェイニングでした。

image.png


ロールチェイニングとは

image.png

ロールチェイニングとは、IAMロールを引き受けて得た一時セキュリティ認証情報を使い、さらに別のロールを引き受けることです。

ロールチェイニングには以下の特徴・制約があります。

  • セッション期間の制限: ロールチェイニングで引き受けたセッションは、最大1時間(3,600秒)に制限されるという制約があります(元のロールでより長いセッション有効期間が設定されていても、ロールチェイニング経由では1時間を超えることはできません)。
  • チェーン可能な回数: ロールチェーンを繰り返せる回数の上限については、AWS公式ドキュメントに明記されていません。

参考: AWS Identity and Access Management ユーザーガイド:ロールの連鎖


ロールチェイニングの動きのテスト

今回調べる中でロールチェイニングについて初めて知ったので、図2のテストとは別に、個人的にロールチェイニングの挙動をmacOS上のAWS CLIで簡単にテストしてみることにしました。

テスト内容と準備した構成

image.png

テストでは、図4のように アカウントXのIAMユーザー「xxx」がアカウントXのIAMロール「xxx-test-role」をAssumeし、さらにアカウントYのIAMロール「xxx-test-target-role」をAssumeできるかを検証しました。

テストのために、図5のような設定(IAMポリシーおよび信頼ポリシー)を準備しました。

image.png

各AssumeRoleを成立させるためには、 「呼び出し元に対するIAMポリシーでの許可」 と 「引き受け先ロールの信頼ポリシーでの許可」 の双方が必要となります。


個人のテスト手順と検証ログ

以下がロールチェイニングの検証手順と実行ログです。ここに掲載している内容は、あくまで試行錯誤の末に上手くいった最終形です。
実際に手を動かして検証している過程では、「今シェル上でどの認証主体(IAMユーザーなのか、どの一時認証情報なのか)としてコマンドを実行しているのか」が非常に混乱しやすかったため、手順の節目ごとに都度現在の認証主体を明示的に確認するようにするなど手順を修正・整備しながら検証しました。

※ 実行結果のJSONやARNに含まれるアカウントIDなどの固有情報は一部マスキングしています。

ステップ 1: 初期認証と現在アイデンティティの確認

まずはベースとなるIAMユーザー「xxx」として認証し、現在の認証主体を確認します。

1-1. IAMユーザー「xxx」として認証
aws login

コマンドの補足:
「aws login」はWebブラウザ経由でAWSアカウントにログインするためのコマンドです。ブラウザ上で認証を完了すると、ローカル端末のデフォルトプロファイルに対してIAMユーザー「xxx」の認証情報がセットされます。

実行結果:

https://ap-northeast-1.signin.aws.amazon.com/v1/authorize?〜〜

Updated profile default to use arn:aws:iam::<アカウントXのアカウントID>:user/xxx credentials.
1-2. 現在の認証主体を確認(IAMユーザー)
aws sts get-caller-identity

コマンドの補足:
「aws sts get-caller-identity」は現在の認証主体を特定するためのコマンドです。STS(Security Token Service)のAPIを呼び出し、現在シェルやプロファイルで有効になっているAWS認証情報のアカウントID、ユーザーID(UserId)、ARN(Arn)を返します。

実行結果:

{
  "UserId": "AIDAZ...",
  "Account": "<アカウントXのID>",
  "Arn": "arn:aws:iam::<アカウントXのID>:user/xxx"
}

ステップ 2: 1回目のAssumeRole(アカウントXのIAMロールを引き受ける)

IAMユーザー「xxx」の認証情報の状態で、アカウントXの「xxx-test-role」を引き受けます。

2-1. 1回目のAssumeRoleを実行
aws sts assume-role \
  --role-arn arn:aws:iam::<アカウントXのID>:role/xxx-test-role \
  --role-session-name test-session-1

コマンド・オプションの補足:

  • 「aws sts assume-role」: 指定したIAMロールを引き受けて、一時セキュリティ認証情報(AccessKeyId, SecretAccessKey, SessionToken)を取得するコマンドです。
  • 「--role-arn」: 引き受け対象のIAMロールのARNを指定する必須オプションです。ここではアカウントX内の「xxx-test-role」を指定しました。
  • 「--role-session-name」: このAssumeRoleセッションを識別するためのセッション名を指定する必須オプションです。ここでは test-session-1 を指定しました。後でも触れますが、CloudTrailログの principalId や assumed-role ARNの末尾にこのセッション名が記録されるため、誰がいつ起こしたセッションかを追跡する際の重要な手がかりになります。

実行結果:

{
  "Credentials": {
    "AccessKeyId": "<1回目のAccessKeyId>",
    "SecretAccessKey": "<1回目のSecretAccessKey>",
    "SessionToken": "<1回目のSessionToken>",
    "Expiration": "..."
  },
  "AssumedRoleUser": {
    "AssumedRoleId": "AROAZ...:test-session-1",
    "Arn": "arn:aws:sts::<アカウントXのID>:assumed-role/xxx-test-role/test-session-1"
  },
  "PackedPolicySize": ...
}

実行結果の補足:
コマンドが成功すると、Credentials 配下に一時セキュリティ認証情報(AccessKeyId, SecretAccessKey, SessionToken)が発行されます。また AssumedRoleUser.Arn には、引き受けたロール名と指定したセッション名(xxx-test-role/test-session-1)を含んだARNが返されます。

2-2. 取得した一時認証情報を環境変数に設定
export AWS_ACCESS_KEY_ID="<1回目のAccessKeyId>"
export AWS_SECRET_ACCESS_KEY="<1回目のSecretAccessKey>"
export AWS_SESSION_TOKEN="<1回目のSessionToken>"

環境変数の補足:
「export AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN」はシェル環境変数にAWS認証情報を設定するコマンドです。AWS CLIは環境変数の値を最優先で評価するため、これらをエクスポートすることで、以降のAWS CLIコマンドは直前に取得したロール「xxx-test-role」の一時認証情報を用いて実行されるようになります。

2-3. 現在の認証主体を確認(xxx-test-role)
aws sts get-caller-identity

実行結果:

{
  "UserId": "AROAZ...:test-session-1",
  "Account": "<アカウントXのID>",
  "Arn": "arn:aws:sts::<アカウントXのID>:assumed-role/xxx-test-role/test-session-1"
}

実行結果の補足:
実行主体が IAMユーザー「xxx」から、引き受けたロール assumed-role/xxx-test-role/test-session-1 に切り替わっていることが確認できました。


ステップ 3: 2回目のAssumeRole(ロールチェイニングの実施)

ステップ 2 で設定した一時認証情報(xxx-test-role)の状態で、別アカウント(アカウントY)の「xxx-test-target-role」を引き受けます。

3-1. 2回目のAssumeRoleを実行
aws sts assume-role \
  --role-arn arn:aws:iam::<アカウントYのID>:role/xxx-test-target-role \
  --role-session-name test-session-2

コマンド・オプションの補足:
ステップ 2 で設定した「xxx-test-role」の一時認証情報が有効な状態で実行します。

  • 「--role-arn」: 引き受け対象のIAMロールのARNを指定するオプションです。ここでは2段目のロールチェイニング先となる別アカウント(アカウントY)のIAMロール「xxx-test-target-role」のARNを指定しました。
  • 「--role-session-name」: このAssumeRoleセッションを識別するための任意のセッション名を指定するオプションです。ここでは2回目のセッション識別名として test-session-2 を指定しました。

実行結果:

{
  "Credentials": {
    "AccessKeyId": "<2回目のAccessKeyId>",
    "SecretAccessKey": "<2回目のSecretAccessKey>",
    "SessionToken": "<2回目のSessionToken>",
    "Expiration": "..."
  },
  "AssumedRoleUser": {
    "AssumedRoleId": "AROAV...:test-session-2",
    "Arn": "arn:aws:sts::<アカウントYのID>:assumed-role/xxx-test-target-role/test-session-2"
  },
  "PackedPolicySize": ...
}

実行結果の補足:
1回目に取得した「xxx-test-role」の一時認証情報を使って、別アカウント(アカウントY)の「xxx-test-target-role」の一時セキュリティ認証情報が正常に払い出されたことがわかります。AssumedRoleUser.Arn にもアカウントYのロールおよび test-session-2 が記録されています。

3-2. 新たに取得した一時認証情報を環境変数に上書き設定
export AWS_ACCESS_KEY_ID="<2回目のAccessKeyId>"
export AWS_SECRET_ACCESS_KEY="<2回目のSecretAccessKey>"
export AWS_SESSION_TOKEN="<2回目のSessionToken>"

環境変数の補足:
「export AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN」により、既存の環境変数を2回目のAssumeRoleで払い出された一時認証情報で上書きします。これにより、シェルの実行権限がアカウントYの「xxx-test-target-role」へと切り替わります。

3-3. 現在の認証主体を確認(xxx-test-target-role)
aws sts get-caller-identity

実行結果:

{
  "UserId": "AROAV...:test-session-2",
  "Account": "<アカウントYのID>",
  "Arn": "arn:aws:sts::<アカウントYのID>:assumed-role/xxx-test-target-role/test-session-2"
}

実行結果の補足:
アカウントYの assumed-role/xxx-test-target-role/test-session-2 として認証されていることが確認でき、ロールチェイニングによる多段AssumeRoleが正常に動作したことが実証できました。


(参考)検証終了時の環境変数のリセット

検証作業が終わったら、環境変数の一時認証情報をクリアして元の状態に戻します。

unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN

# 元の認証主体に戻ったことを確認
aws sts get-caller-identity

検証で感じた注意点

今回の検証後、実際に両アカウントのCloudTrailイベントログを確認したところ、アカウントを跨いだロールチェイニングでは、「大元の呼び出し元の追跡に手間がかかる点」 や 「引き受け先だけでは防ぎきれないセキュリティリスクがある点」 に注意が必要と感じました。

1. 引き受け先(アカウントY)側のログでは呼び出し元の完全なARNが載らない

アカウントY側で記録された2回目の AssumeRole のイベントログ(抜粋)は以下のようになっていました。

{
  "eventTime": "2026-10-30T11:23:56Z",
  "eventSource": "sts.amazonaws.com",
  "eventName": "AssumeRole",
  "awsRegion": "ap-northeast-1",
  "userIdentity": {
    "type": "AWSAccount",
    "principalId": "AROAZ〜〜:test-session-1",
    "accountId": "<アカウントXのアカウントID>"
  },
  "requestParameters": {
    "roleArn": "arn:aws:iam::<アカウントYのアカウントID>:role/xxx-test-target-role",
    "roleSessionName": "test-session-2"
  },
  "responseElements": {
    "assumedRoleUser": {
      "assumedRoleId": "AROAV〜〜:test-session-2",
      "arn": "arn:aws:sts::<アカウントYのアカウントID>:assumed-role/xxx-test-target-role/test-session-2"
    }
  },
  "resources": [
    {
      "accountId": "<アカウントYのアカウントID>",
      "type": "AWS::IAM::Role",
      "ARN": "arn:aws:iam::<アカウントYのアカウントID>:role/xxx-test-target-role"
    }
  ],
  "sharedEventID": "abc123〜"
}

ログ項目の補足:

  • 「userIdentity」: API呼び出しを行った主体の情報が記録される項目です。ここでは "type": "AWSAccount" となり、呼び出し元のアカウントID(accountId)と一意識別子(principalId)のみが記録されます。
  • 「requestParameters」: API呼び出し時にリクエストパラメータとして渡された情報が記録される項目です。ここでは引き受け対象のロールARN(roleArn)やセッション名(roleSessionName)が記録されています。
  • 「responseElements」: APIのレスポンス結果が記録される項目です。ここでは新しく引き受けたロールのセッションARNやロールID(assumedRoleUser)などが返されています。
  • 「resources」: このAPI操作のイベントに関係したAWSリソースが記録される項目です。ここでは引き受け先ロールのARN(xxx-test-target-role)が記録されています。
  • 注目すべき点:
    userIdentity は "type": "AWSAccount" となり、記録されるのは accountId(アカウントX) と principalId(AROAZ〜〜:test-session-1) のみです。 呼び出し元の完全なARNや、IAMユーザー名やロール名は載りません。 これは、ロールチェイニングに限った話ではなく、クロスアカウントのAssumeRole全般の記録の仕様です。ただしチェイニングでは、呼び出し元がロールセッションになるため、その大元となる1回目のAssumeRoleまで、さらにたどる必要があり、手間が増えます。

2. 大元の呼び出し元(IAMユーザー「xxx」)を特定するにはアカウントX側のログとの突合が必要

引き受け先(アカウントY)の principalId に残っている AROAZ〜〜:test-session-1(ロールIDとセッション名)を手がかりに、アカウントX側のCloudTrailログを検索して初めて大元の呼び出し元が判明します。

アカウントX側で記録されていた1回目の AssumeRole のイベントログ(抜粋)は以下の通りです。

{
  "eventTime": "2026-10-30T11:21:27Z",
  "eventSource": "sts.amazonaws.com",
  "eventName": "AssumeRole",
  "userIdentity": {
    "type": "IAMUser",
    "principalId": "AIDAZ〜〜",
    "arn": "arn:aws:iam::<アカウントXのアカウントID>:user/xxx",
    "accountId": "<アカウントXのアカウントID>",
    "userName": "xxx"
  },
  "requestParameters": {
    "roleArn": "arn:aws:iam::<アカウントXのアカウントID>:role/xxx-test-role",
    "roleSessionName": "test-session-1"
  },
  "responseElements": {
    "assumedRoleUser": {
      "assumedRoleId": "AROAZ〜〜:test-session-1",
      "arn": "arn:aws:sts::<アカウントXのアカウントID>:assumed-role/xxx-test-role/test-session-1"
    }
  },
  "resources": [
    {
      "accountId": "<アカウントXのアカウントID>",
      "type": "AWS::IAM::Role",
      "ARN": "arn:aws:iam::<アカウントXのアカウントID>:role/xxx-test-role"
    }
  ]
}
  • 照合の手がかり:
    アカウントX側の responseElements.assumedRoleUser.assumedRoleId(AROAZ〜〜:test-session-1)が、アカウントY側の userIdentity.principalId と 一致 しています。
    これによって、アカウントYのターゲットロールを引き受けた主体が、元を辿ると アカウントXのIAMユーザー「xxx」 であったと推測できます。ただし、同じロールで同じセッション名が使い回されていると、複数のセッションが一致しえるので、次章で触れる sharedEventID を用いた方が確実です。

3. 照合における sharedEventID の有用性と、CloudTrailイベント履歴検索の限界

今回調べる過程で知ったのですが、クロスアカウントのAPI呼び出しを照合する際、セッション名やロールIDでの一致確認に加えて、 sharedEventID という項目を使う方法があります。 公式ドキュメントでは、異なるアカウントに送信される同一アクションのイベントを識別するGUIDと説明されています。

参考:AWS CloudTrailユーザーガイド:管理、データ、ネットワークアクティビティイベントの CloudTrail レコードコンテンツ

image.png

仕様どおりなら、今回のAssumeRoleのイベントは図6のように 合計3件になります(※アカウントX側の2回目のログは、今回は残念ながら取得しそこねました)。

  1. 1回目のAssumeRole(同アカウント内 / 1件):
    • アカウントX内のIAMユーザー「xxx」が同アカウント内の「xxx-test-role」を引き受けた操作です。同一アカウント内の操作であるため、sharedEventID は発行されません。
  2. 2回目のAssumeRole(クロスアカウント / 2件):
    • アカウントXの「xxx-test-role」がアカウントYの「xxx-test-target-role」を引き受けた操作です。
    • クロスアカウントのAPI呼び出しが発生した場合、CloudTrailは 「呼び出し元(アカウントX)」と「リソース所有者(アカウントY)」の双方のCloudTrailログへ、同一の sharedEventID を付与したペアのイベントレコードをそれぞれ配信 します。

この仕組みを理解しておくと、インシデント調査やアクセス監査の際に大元の実行主体を次の流れできれいに辿ることができます。

  1. アカウントY側で不審なAssumeRoleを検知:
    • まずアカウントY側のログを確認し、該当レコードに刻印されている sharedEventID(今回の例では abc123〜)を控えます。
  2. アカウントX側で sharedEventID を検索:
    • アカウントX側で sharedEventID をキーに検索すると、「誰が(どのロールセッションが)アカウントYへAssumeRoleを仕掛けたのか」という2回目の呼び出し元レコード(xxx-test-role/test-session-1)が一発で特定できます。今回は呼び出し元レコードを手元に残しそこねましたが、sharedEventID を使って2回目の呼び出し元レコードを特定できることは実機確認済みです。
  3. さらに1回目のAssumeRoleを辿る:
    • 1回目のAssumeRoleは、前述の方法(ロールIDとセッション名の一致)でたどります。

ただし、CloudTrailのコンソール(イベント履歴)には次のような難点があります(1つ目と2つ目は今回実際に遭遇しました)。

  • イベント履歴での絞り込み困難:
    検証を行ったアカウントX側で他サービス(バッチや各種AWSリソース)が活発に稼働している時間帯だったため、コンソールの「イベント履歴」でイベント名「AssumeRole」を指定しても大量のログに埋もれてしまい、該当レコードを目視で探し出すのが困難でした。
  • sharedEventID によるコンソール絞り込みの非対応:
    少なくとも調査時点ではCloudTrailのコンソール(イベント履歴)では、フィルタ項目として sharedEventID が提供されておらず、絞り込みができませんでした。
  • 過去90日超のログは検索不可:
    今回は直近の検証ログだったため該当しませんでしたが、CloudTrailのイベント履歴で確認できるのは過去90日間のみという制約があります。90日より前の古いログをさかのぼって調査・監査することはコンソール上からは行えません。

そのため、実務やインシデント調査においてクロスアカウントの多段AssumeRoleを追跡・監査する際は、あらかじめCloudTrailのログをAmazon Athenaでクエリ検索できるようにセットアップしておけるとよいと思いました。

4. ロールチェイニングが抱えるセキュリティリスクと双方での設計の重要性

ここまでの確認で、アカウントY側のログだけでは、大元の呼び出し元までは分かりませんでした。アカウントY側から分かるのは、「アカウントXのロールセッション(ロールID AROAZ〜〜、セッション名 test-session-1)から引き受けられた」ところまでで、その先はアカウントX側のログをたどる必要があります。

事後の追跡に手間がかかるからこそ、そもそも想定外の主体が入口に入れないようにしておくことが重要だと感じました。引き受け先が信頼しているのは、あくまで「中間ロール(xxx-test-role)」です。その中間ロールを誰が引き受けられるかは、呼び出し元(アカウントX)側の設定に左右されます。もしX側の制御が甘いと、想定していない主体が中間ロールを経由して、Yのロールまで到達してしまうおそれがあります。

そのため、予防の観点では、次のように双方の設計をセットで考えるとよいと思います。

  • アカウントX: 中間ロールを引き受けられる主体を、必要最小限に絞る。合わせて、中間ロールが引き受けられるロールも、必要なものだけに限定する。
  • アカウントY: 信頼ポリシーの Principal を、アカウント全体ではなく、特定の中間ロールに絞る。

アカウントYの信頼ポリシーだけでなく、アカウントXの中間ロールの制御まで含めた、双方での絞り込みが欠かせないと感じました。


まとめ

今回調べるまでは、 「一度IAMロールを引き受けた状態から、さらに別のロールを引き受けるなんてできるのだろうか?」とそもそも思っていたため、多段AssumeRole(ロールチェイニング)がAWSの標準機能として提供されていること自体がとても良い勉強になりました。

ロールチェイニングのユースケース

今回の検証では「開発段階でLambdaの実行権限をローカルから模倣してクロスアカウントアクセスを事前テストする」という用途で使いました。
そのほか、踏み台(ジャンプ)アカウントを中央に置き、そこから各環境のアカウントのロールを引き受ける構成が、AWSのブログなどで紹介されており、定義上ロールチェイニングに当たります。

image.png

運用者やCI/CDパイプラインがいったん中央のID管理アカウントにログインし、そこから中間ロールを経由して各環境(開発・本番など)のアカウントのロールへと多段で権限を引き受ける構成です。

このように、ログインを受け付ける共通のID管理アカウントと実際のワークロードが動く環境別アカウントを分離し、多段のAssumeRoleでアクセスを中継することで、アカウント横断の権限管理を集約・シンプル化できます。

アカウントを跨ぐ場合のセキュリティ対策の重要性

アカウントを跨いだロールチェイニングでは、引き受け先の信頼ポリシーを強固にするだけでは、安全が完結しないと感じました。引き受け先が信頼しているのは中間ロールであり、その中間ロールを誰が引き受けられるかは、呼び出し元側の設定に左右されるためです。呼び出し元の制御が甘いと、想定していない主体が中間ロールを経由して、引き受け先のロールまで到達できてしまうおそれがあります。

そのため、ロールチェイニングを採用する場合は、予防の観点で、以下のように双方の設計をセットで考えるとよいと思いました。

  • 呼び出し元(アカウントA): 中間ロールを引き受けられる主体を、必要最小限に絞る。あわせて、中間ロールが引き受けられるロールも、必要なものだけに限定する。
  • 引き受け先(アカウントB): 信頼ポリシーの Principal を、アカウント全体ではなく、特定の中間ロールに絞る。

この記事が、ロールチェイニングの挙動やクロスアカウント事前検証、そしてそのセキュリティ設計を検討している方の参考になれば幸いです!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?