← すべての記事 IAM

iam:PassRole: 仕組み、攻撃者による悪用、範囲の絞り方

概要

  • iam:PassRole は、プリンシパルが IAM ロールをサービスに渡すときに AWS がチェックする権限です。たとえば Lambda 関数の実行ロールや EC2 インスタンスのインスタンスプロファイルとして渡す場合です。この権限に対応する独自の API 呼び出しはありません。
  • AWS が受け渡しを許可するのは、3 つの条件がそろったときだけです。呼び出し元のポリシーがそのロールに対する iam:PassRole を許可していること、ロールの信頼ポリシーが対象サービスを許可していること、そしてロールが呼び出し元と同じアカウントにあることです。
  • コンピューティングを作成または更新する権限と組み合わさると、iam:PassRole によってプリンシパルは、一度も付与されていないロールとしてコードを実行できるようになります。Pathbreak の攻撃マップでは、権限昇格経路の 55 パーセントがこの権限に依存しています。
  • CloudTrail は受け渡しそのものについてはイベントを記録しません。そのため検知は、作成または更新の呼び出しと、ロール ARN を運ぶリクエストパラメータに頼ることになります。
  • 修正方法は、Resource 要素に特定のロール ARN または IAM パスを指定することです。ワイルドカードのリソースに iam:PassedToService 条件を付けると、サービスは絞られますが、そのサービスを信頼するすべてのロールは引き続き許可されます。

iam:PassRole は、プリンシパルが AWS サービスにどのロールを渡せるかを制御する AWS IAM の権限です。渡す対象には、Lambda 関数の実行ロール、EC2 インスタンスのインスタンスプロファイル、CodeBuild プロジェクトのサービスロールなどがあります。また、Pathbreak の攻撃マップで最も多く登場する権限でもあります。マップ内の権限昇格経路の 55 パーセントがこの権限に依存しており、それらの経路は 23 の AWS サービスに及びます。あなたに代わってワークロードを実行するサービスはどれも、あなたが渡すロールを受け入れるからです。ワイルドカードのリソースはポリシーレビューでは無害に見え、受け渡しそのものは CloudTrail に一切現れないため、この権限は広く付与しすぎてしまいがちです。この記事では、この権限が何をするのか、AWS が行うチェック、攻撃者による使い方、ログに残る内容、そして経路を閉じるための範囲の絞り方を説明します。

iam:PassRole とは

多くの AWS サービスは、リソースを設定するときに指定した IAM ロールで動作します。Lambda 関数は実行ロールとして実行され、EC2 インスタンスはインスタンスプロファイルから認証情報を取得し、CodeBuild プロジェクトはサービスロールで AWS を呼び出します。そのロールをサービスに引き渡すことを「ロールを渡す」と言い、AWS は呼び出し元にそれが許可されているかをチェックします。

そのチェックが iam:PassRole です。AWS のドキュメントは、PassRole は権限であって API 呼び出しではないと明記しており、SDK に PassRole というオペレーションは存在しません。ロール ARN は別の呼び出しのパラメータとして渡されます。たとえば Lambda の CreateFunction の Role パラメータです。サービスはその呼び出しを処理する際に、呼び出し元の iam:PassRole 権限をチェックします。

この権限は、プリンシパルが自分の持つ以上のアクセス権をサービスに渡すのを防ぐために存在します。Amazon S3 の権限を持たない開発者が S3 を許可するロールを渡せるとしたら、サービスはその開発者に代わって S3 のアクションを実行してしまいます。これこそ、AWS が同じページで警告している権限昇格です。

ロールが渡されるときに AWS が行う 3 つのチェック

PassRole に関する AWS Security Blog の記事は、サービスが渡されたロールを使えるようになる前に、すべて満たされていなければならない 3 つの条件を示しています。

  1. 呼び出し元がそのロールを渡すことを許可されている。呼び出し元のアイデンティティベースのポリシーが、Resource 要素にそのロールを含む形で iam:PassRole を許可し、そのステートメントのすべての条件が満たされている必要があります。さらに、サービスコントロールポリシー、アクセス許可の境界、セッションポリシー、VPC エンドポイントポリシーを含め、ほかの何によっても拒否されていない必要があります。
  2. ロールが対象サービスを信頼している。ロールの信頼ポリシーがサービスプリンシパルを許可している必要があります。たとえば Lambda の実行ロールであれば lambda.amazonaws.com です。AWS によると、信頼がなくてもリソース自体は作成される場合がありますが、その場合サービスはロールを使用できません。
  3. ロールと呼び出し元が同じアカウントにある。IAM ユーザーガイドには、iam:PassRole がロールを渡せるのは同じ AWS アカウント内のサービスに限られると記載されています。そのため、クロスアカウントの設計では、2 つ目のアカウントに、1 つ目のロールを引き受けられるロールが必要です。

攻撃者にとっては、2 つ目の条件が標的のリストを決めます。攻撃者がリソースを作成できるサービスを信頼ポリシーに指定しているロールは、アカウント内のどれもが候補になり、1 つ目の条件が、攻撃者がそれを使えるかどうかを決めます。

PassRole のチェックが行われる場面

このチェックは、サービスロールを指定してリソースを作成するたびに、また既存のリソースを新しいロールで更新するたびに実行されます。Lambda 関数の実行ロールの変更はこの種の更新にあたるため、関数の作成と同じ権限が必要です。

サービスにリンクされたロールを使うサービスは、通常そのロールを自ら作成して管理するため、受け渡しは発生しません。名前を指定したサービスにリンクされたロールで作成する Amazon EC2 Auto Scaling グループのように、サービスにリンクされたロールを選択できるサービスでは、AWS は同じように iam:PassRole をチェックします。

次の表は、ロールを渡す一般的な呼び出しの例と、ロールを運ぶリクエストパラメータを示しています。検知ルールが読み取る必要があるのも、このパラメータです。

サービスロールを渡す呼び出しロールを運ぶパラメータ攻撃マップの項目
LambdaCreateFunctionRoleLambda にロールを渡す
EC2RunInstancesIamInstanceProfile (ロールを含むインスタンスプロファイル)EC2 にロールを渡す
CloudFormationCreateStackRoleARNCloudFormation にロールを渡す
CodeBuildCreateProjectserviceRoleCodeBuild にロールを渡す

マップには、Glue ジョブ、SageMaker のトレーニングジョブ、ECS タスク、Step Functions、Bedrock AgentCore など、Pathbreak が追跡するすべての受け渡しが掲載されています。攻撃マップを iam:PassRole で絞り込めば、それらをまとめて確認できます。

攻撃者による iam:PassRole の悪用方法

01 Attacker principal CreateFunction 02 New Lambda iam:PassRole 03 Passed role runs as role 04 Administrator
iam:PassRole と lambda:CreateFunction を併せ持つプリンシパルは、関数を作成し、そこに特権ロールを渡し、その関数はそのロールとして実行されます。受け渡しが独立したイベントとして CloudTrail に現れることはありません。

どのサービスが関わる場合でも、悪用は同じ 3 つのステップをたどります。

サービスを信頼する特権ロールを見つける。iam:ListRoles は各ロールの信頼ポリシーを AssumeRolePolicyDocument フィールドで返すため、1 回の呼び出しで、どのロールが Lambda、EC2、CodeBuild などのサービスを信頼しているかがわかります。攻撃者は、広い権限を持ち、自分がリソースを作成できるサービスを信頼ポリシーに指定しているロールを探します。

そのロールをアタッチしたリソースを作成する。そのロールに対する iam:PassRole と lambda:CreateFunction があれば、攻撃者は特権ロールを実行ロールとする関数を作成します。呼び出し元のポリシーが受け渡しを許可し、ロールが lambda.amazonaws.com を信頼しているため、AWS はこの受け渡しを受け入れます。

そのロールとしてコードを実行する。攻撃者が関数を呼び出すと、自分で書いたコードが何であれ、特権ロールの権限で実行されます。そのロールが管理者であれば、作成 1 回と呼び出し 1 回でアカウントは攻撃者のものになります。同じ手口は EC2 のユーザーデータ、CodeBuild の buildspec、CloudFormation テンプレート、Glue ジョブのスクリプトでも成立します。範囲の広すぎる iam:PassRole の付与が 1 つあるだけで、多くの経路が一度に開いてしまうのはこのためです。

この連鎖の Lambda 版については、各ステップの CloudTrail イベントとあわせて AWS の権限昇格攻撃 3 例: CloudTrail に残る証拠と修正方法 で取り上げています。

iam:PassedToService だけでは不十分な理由

iam:PassedToService は、ロールを渡せるサービスを制限する条件キーです。役に立つ条件であり、AWS 自身のポリシー検証も、ワイルドカードのリソースを指定した iam:PassRole に対してセキュリティ警告を出し、特定のロール ARN かこの条件のどちらかを推奨しています。ただし、この 2 つの選択肢は同等とは程遠いものです。条件はサービスを絞りますが、ワイルドカードは依然としてアカウント内のすべてのロールを対象にするからです。

AWS 管理ポリシー AWSLambda_FullAccess を見ると、この差がはっきりわかります。このポリシーは lambda:*、iam:ListRoles、iam:GetRole を付与し、iam:PassedToService を lambda.amazonaws.com に設定したうえで、"Resource": "*" に対する iam:PassRole を許可しています。このポリシーを持つプリンシパルは、アカウント内のロールを一覧表示し、信頼ポリシーで Lambda を許可しているロールを見つけ、そのロールで関数を作成して呼び出せます。アカウント内の特権ロールが Lambda を信頼していれば、受け渡し先は実際に Lambda なので、この条件は権限昇格を何も止めません。

この条件が真価を発揮するのは、特定のリソースと組み合わせたときです。特定のロール ARN がどのロールを渡せるかを決め、iam:PassedToService がそれをどのサービスに渡せるかを決めます。これは、ロールが複数のサービスを信頼している場合に重要になります。

CloudTrail で iam:PassRole の悪用を検知する方法

AWS は PassRole については CloudTrail ログが生成されない と明言しているため、証拠となるのは常に、ロールを受け取った作成または更新の呼び出しです。

  • パラメータを監視する。Lambda の場合は、リクエストパラメータにロール ARN を含む CreateFunction 管理イベントです。Lambda の CloudTrail リファレンスではイベント名が CreateFunction20150331 と示されているため、ルールはイベント名の接頭辞で照合する必要があります。同じリファレンスによると、Environment と ZipFile のパラメータはログから除外されるため、攻撃者がアップロードしたコードはイベントに含まれません。
  • ロールと呼び出し元を比較する。強いシグナルは、呼び出し元のプリンシパルよりも多くの権限を持つロールをアタッチする作成呼び出しです。そのリソースタイプを作成した履歴のないプリンシパルからのものであれば、なおさらです。
  • 後続のイベントを有効にする。Lambda の Invoke はデータイベントであり、AWS が確認しているとおり、CloudTrail は既定ではこれを記録しません。Lambda データイベントを有効にすれば、ルールで作成と数分後の呼び出しを組み合わせられます。
  • 失敗を読む。CloudTrail は失敗した呼び出しをエラーコードとエラーメッセージとともに記録します。AWS のトラブルシューティングガイドにあるとおり、受け渡しが拒否されると、AWS が返すエラーには iam:PassRole とロール ARN が示されます。それぞれ異なるロールを指定した作成呼び出しが続けて拒否されていれば、それはどのロールを渡せるかを試している攻撃者の姿です。

受け渡しが成功した後は、ロール自身のアクティビティが最後の確認先です。1 時間前には存在しなかった関数やインスタンスから、渡されたロールとして行われた API 呼び出しは、詳しく調べる価値があります。

iam:PassRole の範囲を絞る方法

目標は、各プリンシパルが、職務に必要なロールだけを、それを使うサービスにだけ渡せるようにすることです。

  • ロールを名前で指定する。Resource 要素に特定のロール ARN を指定します。ロールが頻繁に作成される場合は、AWS Security Blog が推奨しているように、arn:aws:iam::111122223333:role/application_role/* のような IAM パスや名前の接頭辞を使い、そのパスに作成される新しいロールがポリシーを変更せずに対象になるようにします。
  • iam:PassedToService を追加する。特定のリソースと併用し、複数のサービスを信頼するロールでも、ワークロードが使うサービスにしか渡せないようにします。
  • 適する場合は iam:AssociatedResourceArn を使う。この条件キーは、ロールをアタッチできるリソースを制限します。リソースを再作成すると ARN が変わるリソースもあるため、多くの組織は代わりにリソースを変更できる人を制限している、と AWS は述べています。
  • タグベースの制御を避ける。AWS は、iam:PassRole に対する ResourceTag 条件では信頼できる結果が得られないと警告しています。そのため、ロールのタグはこの権限の制御手段として適切ではありません。
  • SCP で特権パスを保護する。サービスコントロールポリシーを使えば、保護されたパス (たとえばセキュリティチームが使うロール) に対する iam:PassRole を、呼び出し元が特定のタグを持つか承認済みのパスにある場合を除いて拒否できます。
  • 開発者が作成するロールに境界を設ける。開発者が自分でロールを作成できる場合は、それらのロールにアクセス許可の境界を必須とし、専用のパスにあるロールだけを渡せるようにします。そうすれば、開発者が作成してから渡すロールが境界を超えることはありません。

どの変更も、チームが頼りにしている機能は維持したまま、渡す必要のなかったロールを通る経路を閉じます。

PassRole の範囲を絞っても解決しないもの

iam:PassRole の範囲を絞ると、新しいリソースから始まる経路は閉じます。しかし、すでに特権ロールがアタッチされているリソースには何の効果もありません。それらのリソースが実行する内容を変更しても、ロールの受け渡しは一切発生しないからです。こうした経路には、変更系の権限に対する独自の制御が必要です。

  • Lambda 関数のコード。lambda:UpdateFunctionCode は既存の関数のコードを置き換え、実行ロールはそのまま残します。そのため、次に関数が呼び出されたとき、攻撃者のコードがそのロールとして実行されます。
  • EC2 のユーザーデータ。ec2:StopInstances、ec2:ModifyInstanceAttribute、ec2:StartInstances があれば、攻撃者はインスタンスを停止し、ユーザーデータを書き換えて、再び起動します。ユーザーデータは既定では初回起動時にしか実行されないため、攻撃者は起動のたびに実行される cloud-init の設定を指定し、スクリプトはインスタンスの既存のプロファイルのもとで実行されます。
  • SSM コマンド。ssm:SendCommand はマネージドインスタンス上でスクリプトを実行し、そのスクリプトはインスタンスにすでにアタッチされているロールの認証情報を読み取れます。
  • CloudFormation スタックのロール。AWS が指摘しているように、サービスロールがいったんスタックにアタッチされると、そのスタックを操作できるユーザーは、iam:PassRole を持っているかどうかにかかわらずそのロールを使えます。そのため、スタックを更新したり変更セットを実行したりできるプリンシパルは、そのロールを引き継ぎます。UpdateStack の亜種も同じように機能します。
  • CodeBuild プロジェクト。buildspec を上書きして既存のプロジェクトのビルドを開始すると、攻撃者のコマンドがプロジェクトのサービスロールのもとで実行されます。

iam:PassRole だけを確認して終わるアカウントレビューでは、これらをすべて見逃します。マップがこれらを別々の項目として掲載しているのはそのためです。

特権ロールを渡せるのが誰かを確認する方法

1 つのプリンシパルと 1 つのロールについてであれば、IAM ポリシーシミュレーターですぐに答えが得られます。シミュレーターは、指定したプリンシパルについて、条件を含めてアイデンティティベースのポリシーとサービスコントロールポリシーを評価します。

aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::111122223333:user/dev-user \
--action-names iam:PassRole \
--resource-arns arn:aws:iam::111122223333:role/AdminRole

プリンシパルのポリシーが iam:PassedToService を使っている場合は、iam:PassedToService キーに lambda.amazonaws.com などの対象サービスを設定する --context-entries 引数を追加します。これがないと、シミュレーターには比較する値がありません。結果が答えるのは、3 つのチェックのうち最初の 1 つだけです。ロールの信頼ポリシーがそのサービスを許可しているかどうかは別の問題で、ロールの AssumeRolePolicyDocument を読んで確認します。また、呼び出し元にはそのサービスでの作成権限も必要です。AWS は、シミュレーターの結果が実際の環境と異なる場合があることにも触れています。

1 組だけなら対応できますが、数百のプリンシパルとロールがあるアカウント全体では現実的ではありません。無料のオープンソースツール pathbreak-audit は、1 つのアカウントの IAM を読み取り、悪用可能な権限や、iam:PassRole と作成アクションのような組み合わせを持つロールとユーザーを、それぞれの修正方法とともに、出発点として一覧にします。Pathbreak はさらに踏み込み、すべての受け渡しを呼び出し元のポリシー、境界、SCP、ロールの信頼ポリシーと照らし合わせて解決します。そのため、実際に成功する経路だけが、渡されたロールの到達先に応じて順位付けされて報告されます。

よくある質問

iam:PassRole は何をするものですか。

iam:PassRole は、プリンシパルが IAM ロールをサービスに与えるときに AWS がチェックする権限です。たとえば Lambda 関数の実行ロールや EC2 のインスタンスプロファイルとして与える場合です。プリンシパルがどのロールをサービスに渡せるかを制御し、サービスが、そのプリンシパルに本来意図された以上のアクセス権で動作することがないようにします。Pathbreak は、あなたのアカウント内のどのプリンシパルが各特権ロールを渡せるかを示します。

iam:PassRole は単独でも危険ですか。

単独では危険ではありません。lambda:CreateFunction や ec2:RunInstances のように、ロールを受け入れるリソースを作成または更新する権限と組み合わさり、かつ特権ロールがそのサービスを信頼している場合に、権限昇格の経路になります。Resource 要素を特定のロールに絞れば、この経路はなくなります。Pathbreak は経路を検証する際、各ロールの受け渡しについて信頼ポリシーと条件を確認します。

CloudTrail は iam:PassRole を記録しますか。

記録しません。AWS のドキュメントによると、PassRole は権限であり、CloudTrail イベントを生成しません。受け渡しは、リソースを作成または変更した呼び出しのパラメータとして現れます。たとえば Lambda の CreateFunction イベント内のロール ARN です。拒否された受け渡しは、エラーメッセージに iam:PassRole が示される、失敗した作成呼び出しとして現れます。

iam:PassedToService があれば iam:PassRole は安全ですか。

リソースがワイルドカードの場合は安全ではありません。この条件はサービスを制限しますが、そのサービスを信頼するアカウント内のすべてのロールは引き続き渡せます。AWSLambda_FullAccess 管理ポリシーがまさにこのケースです。iam:PassedToService は、特定のロール ARN または IAM パスと組み合わせてください。

自分のアカウントで特権ロールを渡せるのが誰かを調べるにはどうすればよいですか。

単一のプリンシパルであれば、iam:PassRole とロール ARN を指定した aws iam simulate-principal-policy で、そのプリンシパルのポリシーが受け渡しを許可しているかがわかり、ロールの信頼ポリシーを見れば、どのサービスがロールを受け取れるかがわかります。アカウント全体では、pathbreak-audit がこれらの権限を持つプリンシパルを一覧にし、Pathbreak がどの受け渡しが成功するかを検証して、到達先に応じて順位付けします。

関連記事

今日あなたのアカウントでどのプリンシパルが特権ロールを渡せるのか、そして各経路を閉じる 1 つの変更を確認してください。

デモを申し込む デモを見る