【AWS・GCP】クロスアカウントアクセスの「穴」を塞ぐ:Confused Deputy問題を無力化する実践的ガードレール
現場で数多のインシデントを見てきたが、クラウドにおける「信頼関係」ほど、設計者の性善説が裏切られやすい場所はない。
今日話すのは、クロスアカウントアクセス、つまり「他人のアカウントから自分のリソースを触らせる」時のセキュリティだ。特にAWSにおいて、IAMロールの信頼ポリシー(Trust Policy)を適当に書いているなら、それは「鍵付きのドアを、鍵を差し込んだまま放置している」のと同じだ。
今回は、攻撃者が好む「Confused Deputy(混乱した代理人)」攻撃を防ぎ、堅牢な環境を作るための実務的なアプローチを共有する。
—
1. 誰もが陥る「Confused Deputy」の罠
クロスアカウントアクセスを実装する際、多くのエンジニアは以下のようなポリシーを書く。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::123456789012:root" },
"Action": "sts:AssumeRole"
}
]
}
一見、問題ないように見えるだろう。だが、これがなぜ危険なのか?
攻撃者は、あなたが信頼しているアカウント(123456789012)に既に侵入しているとする。そのアカウント内の権限を悪用し、あなたの環境のロールをAssumeRoleしようとする。もしあなたのロールが「外部ID(External ID)」というガードレールを持っていなければ、攻撃者はあなたの環境に潜り込み、データへ自由にアクセスできる。
これが「Confused Deputy問題」だ。「信頼できるアカウント」であっても、「そのアカウント内の誰が、どの目的でアクセスしているか」を検証しなければ、セキュリティは崩壊する。
—
2. 実装:External IDによる「合言葉」の強制
これを防ぐ唯一の解は、sts:ExternalId を信頼ポリシーに組み込むことだ。これは、第三者ベンダーにリソースを触らせる時や、別アカウントから操作する際に必須となる「共通の合言葉」だ。
修正後のセキュアな信頼ポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::123456789012:root" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "MY-SECRET-UNIQUE-ID-2023" // ここに一意の文字列を設定
}
}
}
]
}
この設定により、たとえ攻撃者が123456789012アカウントの操作権限を持っていたとしても、MY-SECRET-UNIQUE-ID-2023 という合言葉を知らなければ、あなたのロールを奪うことはできない。
—
3. Pythonによる安全なAssumeRoleの実装例
クライアント側(操作する側)の実装も重要だ。boto3 を使って安全に接続するサンプルコードを置いておく。
import boto3
def assume_role_with_security():
sts_client = boto3.client('sts')
# 信頼ポリシーで設定したExternalIdを必ず付与する
assumed_role_object = sts_client.assume_role(
RoleArn="arn:aws:iam::987654321098:role/TargetRole",
RoleSessionName="AssumeRoleSession",
ExternalId="MY-SECRET-UNIQUE-ID-2023" # ここを一致させる
)
# 一時的な認証情報を取得
credentials = assumed_role_object['Credentials']
# これ以降は取得したクレデンシャルで操作を行う
return boto3.client(
's3',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken']
)
—
4. 運用のためのチェックリスト
技術的な実装以上に、以下の運用ルールをチームで徹底してほしい。
1. 最小権限の原則(Least Privilege):
AssumeRole を許可するロールには、必要最小限のアクションしか許可しないこと。AdministratorAccess をクロスアカウントで渡すのは論外だ。
2. External IDの使い回し禁止:
IDは接続先ごとにユニークなものを生成し、パスワード管理ツールやシークレットマネージャーで保護すること。
3. CloudTrailの監視:
AssumeRole のログには requestParameters に externalId が含まれる。これをアラート監視対象に入れ、不正なIDでのアクセス試行を検知し、即座に遮断するフローを確立すること。
—
最後に:なぜ「泥臭い」確認が必要なのか
セキュリティは、ツールを導入して終わりではない。今回紹介した ExternalId も、運用側の意識が低ければ単なる「長い文字列」として放置される。
「この信頼関係は本当に必要か?」「この権限は広すぎないか?」と、コードをコミットする前に一度立ち止まる。この泥臭い自問自答こそが、最大の防御壁になる。
君たちの環境が、攻撃者にとって「割に合わないターゲット」になることを願っている。もし設定に不安があれば、いつでもコードを見せてくれ。一緒にレビューしよう。
コメント