AWS IAM の混乱した代理問題と ExternalId

AWS IAMの混乱した代理問題がクロスアカウントで起きる仕組みと、最小権限・STSセッション期限・ExternalIdを使った対策、信頼ポリシーとAssumeRoleの実装例をDVA向けに解説します。

学習順Step 7 / 101サービスIAM試験ドメインセキュリティ

AWS IAM の混乱した代理問題

**混乱した代理問題(confused deputy problem)**は、ある操作を実行する権限を持たない主体が、より強い権限を持つ正規の主体を誤った依頼によって動かし、その主体の権限で本来許可されない操作を実行させるセキュリティ上の問題です。正規の主体は自分の権限を使っているため、単純な「攻撃者に直接権限を付けてしまった」ケースとは異なります。攻撃者が代理者とリソース所有者の信頼関係を悪用して、代理者に不適切な対象へのアクセスをさせる点が要点です。

この種の権限昇格は、AWSに限らず、強い権限を持つサービスが別の利用者からの要求を代わりに処理する設計で起こり得ます。AWSでは、第三者事業者にアカウントをまたぐロールを引き受けさせる構成が代表例です。また、AWSサービスのサービスプリンシパルが別サービスのリソースへアクセスする**サービス間(cross-service)**の連携でも、呼び出し元を特定する条件が不足すると同種の問題が起こり得ます。

第三者サービスを介した問題の構造

顧客のAWSアカウントを監視する運用事業者を考えます。顧客は自分のアカウントにIAMロールを用意し、事業者のAWSアカウントを信頼するよう設定します。事業者は複数の顧客に対して同じ監視サービスを提供しており、それぞれの顧客アカウントでロールを引き受けます。

顧客甲がロールARNを事業者へ渡すと、事業者の正規の処理システムはそのロールを引き受け、甲のアカウント内で許可された監視情報を読み取ります。ところが、顧客乙が誤って、あるいは悪意をもって甲のロールARNを事業者に登録させた場合、事業者のシステムが乙からの依頼を甲のロールに向けて実行する可能性があります。信頼ポリシーが事業者のアカウント全体を信頼し、顧客ごとの依頼元を区別する条件がなければ、事業者は正規の権限を持ったまま、甲のリソースを乙の依頼のために操作してしまいます。

この例では、乙自身が甲のアカウントのロールを直接引き受ける必要はありません。権限を持つ事業者を乙が誤った文脈で動かせることが問題の本質です。ロールARNはアクセス先を指し示す識別子であって、秘密のパスワードではありません。ARNが知られていること自体を安全性の根拠にせず、どの顧客の依頼としてロールを引き受けるのかをAWS側でも検証できるようにします。

第三者サービスが顧客を取り違えて権限を使う混乱した代理問題とExternalIdによる検証

被害を抑える三つの観点

混乱した代理問題への対処では、「操作できる範囲」「認証情報を使える時間」「ロール引き受け要求が意図した顧客のものか」を別々に制御します。

最小権限で操作と対象を絞る

ロールを引き受けられる主体を必要な事業者・アカウント・プリンシパルに限定し、ロールの権限ポリシーでは必要最小限のアクションとリソースだけを許可します。たとえば、監査処理に必要なのが特定のログ保管先の読み取りであれば、アカウント全体への * 権限や無関係な書き込み操作まで与えず、対象の読み取りに範囲を絞ります。

最小権限は、ロールの誤用を識別する条件そのものではありません。しかし、代理者がだまされた場合でも、攻撃者が実現できる操作・対象・影響を小さくする防御層になります。信頼ポリシー上の引き受け元と、引き受け後の権限ポリシー上の操作範囲は別々に点検します。

STSセッションの有効時間を必要な範囲にする

STSでロールを引き受けると、期限付きの一時認証情報が発行されます。ロールセッションの期間を作業に必要な長さに設定すれば、認証情報が漏えいした場合や誤って使われた場合に、その認証情報を利用できる時間を制限できます。AWS CLIやSDKから AssumeRole を呼び出す際は DurationSeconds を指定できますが、要求できる値はロールの最大セッション期間やAPIの制約を満たす必要があります。

期限を短くすることは被害の継続時間を縮める対策であり、最初の誤ったロール引き受けを防ぐ条件判定の代わりにはなりません。期限内は一時認証情報で実際に操作できるため、最小権限と併用します。

ExternalIdで顧客ごとの引き受け要求を照合する

ExternalId(外部ID)は、第三者サービスなどが複数のAWSアカウントに代わってロールを引き受けるとき、顧客ごとの依頼を区別するための識別値です。事業者と顧客の間で値を決め、対象ロールの信頼ポリシーでは Condition の sts:ExternalId として期待値を指定します。事業者がSTSの AssumeRole を呼び出すときには、同じ値を ExternalId パラメータとして送ります。

AWSは、信頼ポリシーのPrincipalが認められていることに加えて、要求に含まれたExternalIdがConditionに一致することを評価します。一致しない要求や値を含まない要求は、ExternalIdを必須にする信頼ポリシーを満たせず、ロールを引き受けられません。これにより、事業者が甲のロールARNを乙の処理に誤って使おうとしても、甲向けのExternalIdをその要求に付けなければ拒否できます。

この仕組みは、ロールARNに秘密性を期待するものではありません。また、ExternalIdはIAMが秘密の認証情報として扱うパスワードではありません。ロールを参照できる権限がある利用者は信頼ポリシーから値を確認できる可能性があります。保護の中心は、信頼ポリシーのPrincipalによる制限と、第三者が各顧客の要求に正しい顧客IDを結び付けて送信することです。ExternalIdを「知っていれば誰でもロールを引き受けられる秘密鍵」と考えてはいけません。

マルチテナントの事業者は、顧客のAWSアカウントごとに一意な値を割り当て、顧客名・電話番号のような推測可能な値ではなく、ランダムで推測しにくい識別子を使うことが推奨されます。事業者側は、ロールARNと顧客の対応関係を正しく管理し、各 AssumeRole 要求に対応する顧客の値を常に含めます。顧客側は事業者からExternalIdを受け取り、信頼ポリシーに設定します。

ExternalIdを条件として要求する場合、AWS Management Consoleの通常のSwitch Roleではなく、ExternalIdを指定できるSTS APIやAWS CLIなどからロールを引き受けます。これはコンソールの画面操作に付けるパスワードではなく、API要求と信頼ポリシーの条件を一致させる仕組みです。

信頼ポリシーの設定例

データ集計を委託された事業者が、顧客アカウント内の集計ログを読み取るケースを示します。以下の値は説明用です。顧客アカウントに ThirdPartyLogReader ロールを作成し、事業者アカウントのIDをPrincipalに指定します。さらに、顧客専用のExternalIdが含まれる要求だけを受け付けるようにします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowVendorForThisCustomer",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::444455556666:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "cust-9f27c4a8-6d31-4b85-a170-83d2e5106c44"
        }
      }
    }
  ]
}

ここで、Principal は信頼する事業者アカウントを指定し、Action はロール引き受け操作を示します。Condition はExternalIdの完全一致を要求します。アカウントARNをPrincipalに書くことは、そのアカウントのあらゆる主体に無条件でアクセスを許す意味ではありませんが、事業者アカウント側でどの利用者・ロールが sts:AssumeRole を実行できるかを適切に制限する必要があります。

ロールの権限ポリシーは、この信頼ポリシーとは別に設定します。たとえば集計に必要なログオブジェクトの読み取りだけを許可し、不要な変更・削除や別のデータ領域へのアクセスは認めません。信頼ポリシーは「誰が、どの条件でロールを引き受けるか」を決め、権限ポリシーは「引き受けた後に何を実行できるか」を決めます。ExternalIdを信頼ポリシーに置いても、ロールの権限そのものが増えるわけではありません。

事業者は、顧客のロールARNと顧客別ExternalIdを使ってSTSに要求します。

aws sts assume-role \
  --role-arn arn:aws:iam::555566667777:role/ThirdPartyLogReader \
  --role-session-name log-audit-job-20261006 \
  --external-id cust-9f27c4a8-6d31-4b85-a170-83d2e5106c44 \
  --duration-seconds 1800

--role-arn は引き受けるロール、--external-id は顧客が信頼ポリシーに設定した値を指定します。--duration-seconds は要求するセッション時間です。値が信頼ポリシーと一致し、呼び出し元の sts:AssumeRole 権限など他の認可条件も満たすと、STSはそのロールの権限に従う一時認証情報を返します。取得した認証情報は実際の秘密情報です。ログやソースコードに出力せず、安全な方法でAWS CLIやSDKに渡してください。

この例では、事業者アカウント側の呼び出し元にも、対象ロールARNに対する sts:AssumeRole の許可が必要です。信頼ポリシーと呼び出し元ポリシーのどちらか一方だけでは、クロスアカウントのロール引き受けは成立しません。ロールを引き受けた後のログ操作には、ロールの権限ポリシーや対象リソース側の設定も関係します。

ExternalIdを使う際の設計・運用上の注意

  • ExternalIdは秘密情報ではない。 パスワードやアクセスキーのように、秘匿できていることを認可の根拠にしない。AWSではロールを参照できる権限を持つ者が値を確認できる場合がある。
  • ExternalIdはPrincipalの代替ではない。 誰でもロールを引き受けられるようにPrincipalを広げるのではなく、信頼する事業者アカウントや必要な主体を適切に限定する。
  • 顧客ごとに一意な値を割り当てる。 同じ第三者が複数顧客を扱うときに顧客IDを取り違えないよう、顧客アカウント単位で対応関係を維持する。推測されにくいランダム値を使う。
  • 値を両側で一致させる。 顧客の信頼ポリシーに設定した sts:ExternalId と、事業者が AssumeRole に渡す値が一致しなければ要求は許可されない。
  • 最小権限を別途適用する。 ExternalIdが一致しても、引き受けた後の操作はロール権限の範囲内に限る。対象アクション、対象リソース、必要なセッション時間を絞る。
  • AWSサービス間連携の条件と混同しない。 第三者によるクロスアカウントロール引き受けでは通常 sts:ExternalId を使う。一方、AWSサービスプリンシパルが別サービスのリソースにアクセスする構成では、サービスに応じて aws:SourceArn や aws:SourceAccount などの条件が使われる。要件に対応する条件キーを選ぶ。

DVA試験での判断ポイント

  1. 問題の中心は、権限のない第三者が強い権限を持つ代理者をだまして、代理者自身の権限で操作させること。
  2. 第三者事業者が多数の顧客アカウントを扱う場面では、ロールARNを知っている別顧客が事業者を介してロールを誤用させる可能性に注目する。
  3. ExternalIdは対象ロールの信頼ポリシーのConditionに sts:ExternalId として指定し、STS AssumeRole 要求側にも同じ値を含める。
  4. ExternalId条件により、信頼された事業者アカウントからの要求であっても、顧客ごとの値が合わないロール引き受け要求を拒否できる。
  5. ExternalIdはパスワードでも秘密鍵でもなく、ロールARNも秘密情報ではない。ExternalIdの秘匿だけに依存する説明は不適切。
  6. 最小権限は不正操作の範囲・影響を縮小し、STSセッション期限は悪用可能な時間を短縮する。ExternalIdによる要求の文脈確認と合わせて多層防御にする。
  7. 信頼ポリシーはロールを引き受ける主体・条件、権限ポリシーは引き受け後の操作範囲を制御する。ExternalIdは権限ポリシーに設定するものではない。
  8. クロスアカウントの AssumeRole では、対象ロールの信頼関係に加え、呼び出し元側の sts:AssumeRole 許可も確認する。

AWS公式ドキュメント

重要ポイント

  • ▸混乱した代理問題は、攻撃者がより強い権限を持つ正規の代理者をだまして、本来許可されない対象への操作を実行させる権限昇格の問題である
  • ▸第三者サービスが複数顧客のAWSロールを引き受ける場合、ロールARNだけでは顧客ごとの依頼を区別できず、別顧客の要求を誤って処理する危険がある
  • ▸最小権限は不正利用時に可能な操作と対象を狭め、STSの短いセッション期限は認証情報が悪用され得る時間を短縮する。どちらも単独で誤った引き受け要求を識別する仕組みではない
  • ▸ExternalIdは信頼ポリシーのConditionに置く識別値であり、正規の第三者はAssumeRole要求に同じ値を指定する。PrincipalとExternalIdの両方が条件を満たす要求だけがロールを引き受けられる
  • ▸ExternalIdはパスワードや秘密情報ではなく、権限を与える値でもない。ARNが知られてもExternalId条件は有効だが、外部ID自体を秘密として扱う設計に依存してはならない
  • ▸顧客ごとに一意で推測されにくいExternalIdを用い、信頼ポリシーのPrincipal、ロール権限、STSセッション時間をそれぞれ必要な範囲に制限する

このトピックの学習を完了しますか?

完了状態はいつでも切り替えられます