🔐 sts:ExternalId 完全マスターガイド

マンション管理で理解する!「混乱した代理」問題と多層防御の完全解説

📚 目次
1結論ファースト
2マンション管理のたとえ
3混乱した代理問題
4解決策:ExternalId
5技術詳細・条件キー比較
6実装例(IAM/CFn/Terraform)
7実際のSaaSサービス例
8トラブルシューティング
9CloudTrail監査方法
10ベストプラクティス
11設定チェックリスト
12FAQ・まとめ

📌 1. 結論ファースト:ExternalIdとは何か?

🔑
秘密の合言葉
サードパーティサービスがあなたのAWSアカウントにアクセスする際、「本当にあなたからの依頼か」を確認するための秘密のコード
🛡️
なりすまし防止
悪意のある第三者が「他人のふりをして」あなたのアカウントにアクセスすることを完全にブロック
🎯
必須の場面
SaaS連携、外部ベンダーアクセス、マルチテナント環境などサードパーティとの連携時は必須
🎯 一言で言うと
「IAMロールARNを知っているだけではアクセスできない」ようにする追加の本人確認コード

🏢 2. マンション管理で完全理解

🔑 クロスアカウントアクセス = マンション管理会社への鍵の預け

📊 登場人物と関係図

🏠
あなた(マンション所有者)
= AWSアカウント所有者
🔑 マスターキー預け
➡️
🔐 合言葉も設定
🏢
管理会社
= SaaSサービス(複数顧客を管理)
😈
悪意のある住人B
= 攻撃者(同じSaaSの別顧客)
❌ Aさんの部屋番号だけ伝える
➡️
❌ 合言葉を知らない
🚪
マンションのドア
= AWS STS(アクセス制御)

🔄 たとえ話 ↔ AWS の対応表

🏠 あなたのマンション
=
☁️ あなたのAWSアカウント
🏢 管理会社(複数の住人を管理)
=
🔧 SaaSサービス(マルチテナント)
🔑 マスターキー
=
🎭 IAMロール(AssumeRole権限)
🚪 部屋番号(101号室)
=
📋 IAMロールARN
🔐 合言葉(秘密のパスワード)
=
🔐 ExternalId

😈 3. 「混乱した代理」問題とは?

⚠️ ExternalIdがないと何が起こる?
攻撃者が「他人のふりをして」あなたのリソースにアクセスできてしまう!
🎬 攻撃シナリオ:時系列で見る「混乱した代理」
😇
正規顧客A
(被害者)
😈
悪意の顧客B
(攻撃者)
🏢
SaaSサービス
(代理人)
☁️
AWS STS
(認証)
1 顧客A: SaaSに登録、IAMロールARN arn:aws:iam::111111:role/ServiceRole を設定
2 顧客A: IAMロールの信頼ポリシーでSaaSアカウントを許可(ExternalIdなし
3 攻撃者B: 同じSaaSに登録、AさんのARNを自分の設定に入力!
4 攻撃者B: SaaSに「自分のAWS環境でジョブを実行して」と依頼
5 SaaS: Bの設定にあるARN(実はAのもの)でAssumeRole実行
6 AWS STS: ARNとPrincipalが一致 → アクセス許可!(ExternalIdチェックなし)
💀
結果:攻撃者BがAさんのAWSリソースにアクセス成功!
SaaSは「混乱した代理」となり、Bからの依頼を「Aからの正当な依頼」と誤認。
データ窃取、リソース破壊、不正課金などの被害が発生する可能性あり。

🎭 なぜ「混乱した代理」と呼ばれるのか?

SaaSサービス(代理人)は、顧客Bから「Aさんのアカウントにアクセスして」と頼まれても、
それが本当にAさん本人からの依頼かどうか区別できない(混乱している)。
結果として、SaaSは善意で動いているのに、攻撃者の共犯者になってしまう。

✅ 4. 解決策:ExternalIdの導入

🛡️ ExternalIdで「なりすまし」を完全ブロック!

📋 ExternalId導入の流れ

1
🏢 SaaSが顧客ごとに固有のExternalIdを発行
SaaSサービスに登録すると、あなた専用のExternalIdが発行されます。
このIDは推測困難なランダム文字列で、顧客ごとに異なります。
あなたのExternalId: customer-a-x8K9mP2nL5vQ
2
👤 顧客がIAMロールの信頼ポリシーにExternalIdを設定
発行されたExternalIdを、IAMロールの信頼ポリシーにConditionとして追加します。
これにより「このExternalIdを提示した場合のみアクセス許可」となります。
"Condition": { "StringEquals": { "sts:ExternalId": "customer-a-x8K9mP2nL5vQ" } }
3
🔐 SaaSがAssumeRole時にExternalIdを提示
SaaSがあなたのアカウントにアクセスする際、登録済みのExternalIdを一緒に送信します。
AWS STSは信頼ポリシーのConditionと照合し、一致する場合のみアクセスを許可します。
aws sts assume-role --role-arn "..." --external-id "customer-a-x8K9mP2nL5vQ"
🛡️ 攻撃者Bはアクセス不可能!
攻撃者BはAさんのExternalIdを知りません。
BのExternalId(customer-b-yZ3qR7...)とAさんの信頼ポリシーが一致しないため、
アクセスは即座に拒否されます!
正規ユーザーA
SaaSが正しいExternalIdを提示
→ アクセス許可 ✓
攻撃者B
Bの ExternalIdはAのポリシーと不一致
→ アクセス拒否 ✗

⚙️ 5. 技術詳細:STS条件キーの比較

🔧 STSで使用できる条件キーの違い
🔐
sts:ExternalId
目的:サードパーティサービスとの連携時に「混乱した代理」問題を防止
📌 使用場面
• SaaS/外部ベンダーとの連携
• マルチテナント環境での分離
• クロスアカウントの本人確認
🏷️
sts:SourceIdentity
目的:セッションに人間が読める識別子を付与し、監査ログでの追跡を容易にする
📌 使用場面
• ユーザー別の操作追跡
• CloudTrailログの可読性向上
• ロールチェーン時のID保持
🔢
aws:SourceAccount
目的:リクエスト元のAWSアカウントIDを検証する
📌 使用場面
• AWSサービス間の連携
• S3イベント通知の制限
• Lambda呼び出し元の制限

🎯 ExternalIdと他の条件キーの組み合わせ

ExternalIdは単独でも強力ですが、aws:PrincipalArnaws:SourceAccount
組み合わせることで、より堅牢なアクセス制御を実現できます。
多層防御(Defense in Depth)の考え方が重要です。

💻 6. 実装例

📝 各種フォーマットでの実装
IAM Policy (JSON)
CloudFormation
Terraform
AWS CLI
📄 IAM信頼ポリシー(trust-policy.json)
// ExternalIdを必須にした信頼ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        // SaaSサービスのAWSアカウント
        "AWS": "arn:aws:iam::999999999999:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          // ★ ここがポイント!ExternalIdの検証
          "sts:ExternalId": "a1b2c3d4-unique-secret-12345"
        }
      }
    }
  ]
}
📄 CloudFormation テンプレート
AWSTemplateFormatVersion: '2010-09-09'
Description: 'ExternalId付きクロスアカウントロール'

Parameters:
  ExternalId:
    Type: String
    Description: 'SaaSサービスから提供されたExternalId'
    NoEcho: true  # 機密情報として扱う

Resources:
  CrossAccountRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'SaaSServiceRole'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS: 'arn:aws:iam::999999999999:root'
            Action: 'sts:AssumeRole'
            Condition:
              StringEquals:
                sts:ExternalId: !Ref ExternalId
📄 Terraform
variable "external_id" {
  description = "SaaSサービスから提供されたExternalId"
  type        = string
  sensitive   = true  # 機密情報として扱う
}

resource "aws_iam_role" "saas_service_role" {
  name = "SaaSServiceRole"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::999999999999:root"
        }
        Action = "sts:AssumeRole"
        Condition = {
          StringEquals = {
            "sts:ExternalId" = var.external_id
          }
        }
      }
    ]
  })
}
🔧 AWS CLI / boto3 呼び出し例
# AWS CLI
aws sts assume-role \
  --role-arn "arn:aws:iam::111111111111:role/SaaSServiceRole" \
  --role-session-name "SaaSSession" \
  --external-id "a1b2c3d4-unique-secret-12345"

# Python (boto3)
import boto3

sts_client = boto3.client('sts')
response = sts_client.assume_role(
    RoleArn='arn:aws:iam::111111111111:role/SaaSServiceRole',
    RoleSessionName='SaaSSession',
    ExternalId='a1b2c3d4-unique-secret-12345'  # 必須!
)

credentials = response['Credentials']

🏢 7. 実際のSaaSサービス例

📱 ExternalIdを使用する主要SaaSサービス
🐕
Datadog
監視・オブザーバビリティ
AWS環境のメトリクス収集、ログ分析、APMのために、S3、CloudWatch、Lambda等にアクセス。
🔄 連携フロー
1 Datadogコンソールで「AWS Integration」を設定
2 自動生成されたExternalIdをコピー
3 CFnテンプレート or 手動でIAMロール作成
📊
New Relic
パフォーマンス監視
インフラストラクチャ監視、APM、ログ管理のためにAWSリソースの情報を収集。
🔄 連携フロー
1 New Relicで「AWS Integrations」を追加
2 アカウント固有のExternalIdが表示
3 提供されるCFnスタックをデプロイ
💰
CloudHealth
コスト管理・最適化
AWSコストの可視化、リソース最適化、ガバナンス機能を提供。
🔄 連携フロー
1 CloudHealthで「AWS Account」を追加
2 自動生成のExternalIdと手順書を取得
3 読み取り専用IAMロールを作成
🔒
Prisma Cloud
クラウドセキュリティ
クラウド環境のセキュリティ監視、コンプライアンスチェック、脅威検出。
🔄 連携フロー
1 Prisma Cloudで「Cloud Account」を追加
2 自動生成CFnテンプレートをダウンロード
3 ExternalId込みのロールが自動作成

🔧 8. トラブルシューティング

⚠️ よくあるエラーと解決方法
エラー1: AccessDenied - ExternalId不一致
An error occurred (AccessDenied) when calling the AssumeRole operation:
User: arn:aws:iam::999999999999:user/service is not authorized to perform: sts:AssumeRole
on resource: arn:aws:iam::111111111111:role/ServiceRole
🔍 原因
  • AssumeRole時に指定したExternalIdが、信頼ポリシーのConditionと一致しない
  • ExternalIdを指定し忘れている
  • ExternalIdにタイプミス(空白、大文字小文字)がある
✅ 解決方法
1. 信頼ポリシーのExternalIdを確認
2. AssumeRole時に指定しているExternalIdと完全一致か確認
3. 前後の空白や改行がないか確認
4. SaaSサービスのダッシュボードで正しいExternalIdを再確認
エラー2: MalformedPolicyDocument
An error occurred (MalformedPolicyDocument) when calling the UpdateAssumeRolePolicy operation:
Invalid condition key sts:externalid
🔍 原因
  • 条件キーの大文字小文字が間違っている
  • 正しくは sts:ExternalId(EとIが大文字)
✅ 解決方法
条件キーを sts:ExternalId に修正(大文字小文字を正確に)
エラー3: 信頼関係が確立されていない
An error occurred (AccessDenied): Not authorized to perform sts:AssumeRole
(Principal not in trust policy)
🔍 原因
  • 信頼ポリシーのPrincipalにSaaSのアカウントIDが含まれていない
  • SaaSアカウントIDが間違っている
✅ 解決方法
信頼ポリシーのPrincipalに正しいSaaSアカウントのARNを追加
(SaaSサービスのドキュメントで正しいアカウントIDを確認)

📋 9. CloudTrailでの監査方法

🔍 AssumeRoleイベントの確認方法
1
CloudTrailでイベント検索
CloudTrailコンソールまたはAthenaで、AssumeRoleイベントを検索します。
# CloudTrail Insights または Athena クエリ
SELECT eventTime, userIdentity.arn, requestParameters
FROM cloudtrail_logs
WHERE eventName = 'AssumeRole'
AND requestParameters LIKE '%ServiceRole%'
ORDER BY eventTime DESC
LIMIT 100;
2
ExternalIdの確認
イベントのrequestParametersexternalIdが含まれているか確認。
{
"eventName": "AssumeRole",
"requestParameters": {
"roleArn": "arn:aws:iam::111111:role/ServiceRole",
"roleSessionName": "SaaSSession",
"externalId": "customer-a-x8K9mP2nL5vQ"
}
}
3
不審なアクセスの検出
ExternalIdなしでAssumeRoleが試行されていないか、失敗イベントを確認。
# 失敗したAssumeRole試行を検索
SELECT eventTime, sourceIPAddress, errorCode
FROM cloudtrail_logs
WHERE eventName = 'AssumeRole'
AND errorCode = 'AccessDenied'
ORDER BY eventTime DESC;

⭐ 10. ベストプラクティス

💡 ExternalId活用の鉄則
🎲
推測困難な文字列を使用
UUID v4形式など、暗号学的に安全な乱数を使用。短い文字列や連番は避ける。
✅ a1b2c3d4-e5f6-7890-abcd-ef1234567890
❌ customer-001, test123
👤
顧客ごとに固有の値
SaaSサービスは顧客ごとに異なるExternalIdを発行すべき。共通IDは意味がない。
顧客A: cust-a-xK9mP2nL5vQ
顧客B: cust-b-yZ3qR7tW8uE
🔒
秘密として厳重管理
ExternalIdはパスワード同様に秘密にする。GitHubにコミットしない、ログに出力しない。
✅ AWS Secrets Manager / Parameter Store (SecureString)
❌ ソースコード直書き、環境変数のみ
🔄
定期的なローテーション
漏洩リスクを低減するため、定期的にExternalIdを更新。漏洩が疑われる場合は即座に変更。
推奨: 90日〜1年ごとにローテーション
📋
最小権限の原則
ExternalIdに加えて、IAMロールの権限も必要最小限に。読み取り専用で十分な場合が多い。
例: s3:GetObject, cloudwatch:GetMetricData のみ
🛡️
多層防御の実践
ExternalIdだけでなく、aws:SourceAccount、セッション時間制限も組み合わせる。
+ MaxSessionDuration: 1時間
+ aws:SourceAccount条件

✅ 11. 設定チェックリスト

📋 ExternalId導入時の確認項目
🔐 ExternalIdの準備
  • SaaSサービスからExternalIdを取得した
  • ExternalIdは推測困難な文字列である
  • ExternalIdを安全な場所に保管した
📄 IAMロール設定
  • 信頼ポリシーにConditionでExternalIdを設定した
  • PrincipalにSaaSの正しいアカウントIDを設定した
  • 権限ポリシーは最小権限になっている
  • MaxSessionDurationを適切に設定した
🧪 動作確認
  • 正しいExternalIdでAssumeRoleが成功する
  • 誤ったExternalIdでAssumeRoleが失敗する
  • ExternalIdなしでAssumeRoleが失敗する
📊 監視・監査
  • CloudTrailでAssumeRoleイベントが記録されている
  • 失敗したAssumeRole試行のアラートを設定した
  • 定期的なアクセスレビューの計画がある

❓ 12. よくある質問

FAQ
Q ExternalIdは誰が生成するの?
サードパーティサービス(SaaS側)が生成します。
顧客がサービスに登録すると、サービス側が顧客専用のExternalIdを発行し、「このIDをIAMロールに設定してください」と案内します。顧客が自分で作成する場合もありますが、その場合はサービス側にそのIDを伝える必要があります。

重要:SaaSが発行する場合、そのExternalIdは顧客ごとに固有である必要があります。共通のExternalIdを全顧客に使いまわすと、混乱した代理問題を防げません。
Q 自社のクロスアカウントアクセスにも必要?
自社内のアカウント間では通常不要です。
ExternalIdは「第三者サービスとの連携」で発生する「混乱した代理」問題を防ぐためのもの。自社で管理するアカウント同士なら、Principal(信頼するAWSアカウント)を正確に指定すれば十分です。

ただし例外:社内でもマルチテナント型の共有サービスを運用している場合は、ExternalIdの使用を検討してください。
Q ExternalIdを設定し忘れるとどうなる?
2つのケースがあります:

① 信頼ポリシーにExternalId条件あり、AssumeRole時に指定なし
→ アクセス拒否(AccessDenied)。これは安全な状態。

② 信頼ポリシーにExternalId条件なし
脆弱な状態!ARNを知っている誰でもAssumeRole可能。すぐに修正を!
Q ExternalIdが漏洩したらどうする?
即座にローテーションしてください:

1. SaaSサービスのダッシュボードで新しいExternalIdを発行(または自分で生成)
2. IAMロールの信頼ポリシーを新しいExternalIdに更新
3. SaaSサービスに新しいExternalIdを設定
4. CloudTrailで不審なアクセスがなかったか確認

予防策:ExternalIdをソースコードにハードコードしない。AWS Secrets Managerなどで管理。
Q ExternalIdだけで完全に安全?
ExternalIdは重要な防御層ですが、完璧ではありません。

ExternalIdで防げること:
• 混乱した代理問題(なりすまし)
• ARNを知っているだけの不正アクセス

ExternalIdで防げないこと:
• ExternalId自体の漏洩
• SaaSサービス自体が侵害された場合
• 過剰な権限を持つIAMロールの悪用

多層防御を推奨:ExternalId + 最小権限 + セッション時間制限 + 監視アラート

🎓 まとめ

🔐
ExternalIdとは
なりすましを防ぐ
秘密の合言葉
本人確認用コード
😈
防げる攻撃
混乱した代理問題
なりすましアクセス
不正なAssumeRole
使うべき場面
SaaS連携
外部ベンダー
マルチテナント
⚙️
実装方法
信頼ポリシーに
Condition追加
StringEquals使用
🏢 マンション管理のたとえで覚えよう!

🔑 マスターキー(IAMロール)を管理会社に渡すときは
🔐 合言葉(ExternalId)も設定しておく
😈 合言葉を知らない人がキーを使おうとしても拒否される!

🎯 サードパーティ連携 → ExternalId必須
🛡️ 多層防御で堅牢に
📋 CloudTrailで監査

Created by SSuzuki1063

AWS SAP Learning Resources