ForgeVision Engineer Blog

フォージビジョン エンジニア ブログ

同アカウント内でのスイッチロールなら、AssumeRole アクションは要らないんですって!

こんにちは、AWS グループの尾谷です。

主題の件、スイッチロールには、sts:AssumeRole アクションと信頼ポリシーがセットで必要だと思っていました。
でも、クロスアカウントスイッチロールは両方が必須ですが、同アカウント内でスイッチロールする場合は、信頼ポリシーで IAM ユーザーの ARN さえ設定しておれば、AssumeRole を設定する必要がありませんでした。

非常に勉強になったので、アウトプットさせていただきます。

このブログで言いたいこと

  1. クロスアカウントのスイッチロールは、AssumeRole のアクションが必要
  2. 同アカウント内のスイッチロールは、信頼ポリシーがあれば AssumeRole のアクションは不要
  3. どちらの場合も、信頼ポリシーは ARN で指定が必要

スイッチロールとは

スイッチロールは、あるユーザーがロールを引き受けて、そのロールの権限でアクションを実行できるようになる仕組みです。

例えば、A さん用に発行した IAM ユーザーに「ReadOnlyAccess」のポリシーがアタッチされているとします。
IAM ユーザー「A-san」は、AWS のリソースを読み取ることはできますが、EC2 を起動したり、RDS をシャットダウンするといった書き込みを伴うアクションができません。

でも、「AmazonEC2ReadOnlyAccess」と、「RebootInstances」のポリシーがアタッチされた IAM ロールにスイッチロールすると、EC2 インスタンスを起動できるようになります。

これがスイッチロールの仕組みです。
設定をすれば、別アカウントへのスイッチもできます。

スイッチロールの許可

スイッチロールを行うには、以下の通り、ユーザーにもロールにもポリシーの設定が必要です。(だと思っていました。)

  1. IAM ロールの信頼関係に A ユーザーの ARN を指定
  2. A さんに「sts:AssumeRole」ポリシーをアタッチ

でも、同じアカウント内のスイッチであれば A さんにアタッチした「sts:AssumeRole」ポリシー (2. の作業) は不要だったのです。

実験

実際に、IAM ユーザーと IAM ロールを作ってスイッチロールを試してみました。

シナリオ 1

以下のシナリオは、スイッチができません。

リソース ポリシー 有/無
IAM ユーザー sts:AssumeRole なし
IAM ロール 信頼ポリシー root

IAM ユーザー「A-san」を作成し、AWS 管理ポリシーの「ReadOnlyAccrss」をアタッチしました。
「sts:AssumeRole」はアタッチしていません。

IAM ロール「SwitchRole」を作成し、AWS 管理ポリシーの「AmazonEC2ReadOnlyAccess」とインラインポリシーで「RebootInstances」のアクションをアタッチしました。

作成直後の「SwitchRole」ロールの信頼ポリシーには、アカウントの root が設定されています。
この root というのは特殊で、ルートアカウントのみを許可するという指定ではなく、アカウント内の全てのユーザーを許可するという指定です。*1

IAM ユーザー「A-san」でサインインしました。

ReadOnlyAccess ポリシーがアタッチされているため、当然ですが、IAM や、CloudFront ディストリビューションなどの全てのリソースを参照できます。

しかし、設定を変更して保存ボタンをクリックすると、エラーになります。
書き込みアクションが拒否されている状態が確認できます。

「ロールの切り替え」から「SwitchRole」へのスイッチを試みましたが

エラーになりました。スイッチロールできませんでした。

シナリオ 2

このシナリオはスイッチができます。

リソース ポリシー 有/無
IAM ユーザー sts:AssumeRole あり
IAM ロール 信頼ポリシー root

IAM ユーザー「A-san」に「sts:AssumeRole」をアタッチしました。

すると、スイッチできました。
直後に、CloudFront の管理コンソールはエラーになり、EC2 管理コンソールしか参照できなくなりました。
スイッチロールは、その名の通り、権限をスイッチするので、元のポリシーに ReadOnlyAccess がアタッチされていても、切り替え後は機能しなくなります。
あくまでロールの権限で動作します。

ということで、スイッチ成功しました。

シナリオ 3

このシナリオはスイッチができます。

リソース ポリシー 有/無
IAM ユーザー sts:AssumeRole あり
IAM ロール 信頼ポリシー あり

IAM ロールの信頼ポリシーで、ユーザー「A-san」を明示的に指定しました。
これは双方を指定しているので、スイッチできて当然ですね。

シナリオ 4

このブログでお伝えしたかったのは、このシナリオの事象です!
なんとスイッチできちゃいます。

リソース ポリシー 有/無
IAM ユーザー sts:AssumeRole なし
IAM ロール 信頼ポリシー あり

「A-san」ユーザーから、「sts:AssumeRole」を含むインラインポリシーを削除しました。
「ReadOnlyAccess」ポリシーのみアタッチされている状態なので「sts:AssumeRole」という書き込みアクションはできないはずなのに、スイッチができちゃいました。
信頼ポリシーに「root」の ARN を指定してもスイッチできないのに、IAM ユーザーの ARN を指定するとスイッチできるようになります。

シナリオ 5

最後は、おまけです。
シナリオ 5 はスイッチできます。

リソース ポリシー 有/無
IAM ユーザー sts:AssumeRole なし。代わりに、PowerUser をアタッチ
IAM ロール 信頼ポリシー root

「A-san」にアタッチしていた「ReadOnlyAccess」をデタッチし、

代わりに「PowerUserPolicy」をアタッチしました。

これもスイッチできます。
「PowerUserAccess」は、IAM サービスのアクションの許可を全て例外にしていて、結果、IAM サービスには読み込みも書き込みもできませんが、

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "NotAction": [
                "iam:*",
                "organizations:*",
                "account:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "account:GetAccountInformation",
                "account:GetPrimaryEmail",
                "account:ListRegions",
                "iam:CreateServiceLinkedRole",
                "iam:DeleteServiceLinkedRole",
                "iam:ListRoles",
                "organizations:DescribeOrganization"
            ],
            "Resource": "*"
        }
    ]
}

sts は、IAM に属していないので、書き込みさえできれば実行できるんです。

AWS ドキュメント

この IAM の挙動がバグではないか?と、ドキュメントを探すも、自分では見つけられず、AWS サポートに問い合わせして、教えていただきました。*2

ページの一部を引用します。

リソースベースのポリシー – リソースベースのポリシーは、プリンシパルとして指定されたプリンシパル (中略...)リソースベースのポリシーが評価されると、ポリシーで指定されたプリンシパル ARN によって、他のポリシータイプの暗黙的な拒否が、最終的な決定に適用されるかどうかが決まります。

よく考えてみると、IAM ユーザーや IAM ロールのポリシーは ID ベースのポリシーですが、信頼ポリシーのタブはリソースベースのポリシーです。これは勉強になりました。

ただ、IAM ポリシーは Allow がない場合に暗黙的な拒否が発生します。
今回の場合は、IAM ユーザーに AssumeRole アクションを許可していないので、暗黙の拒否が発生しているはずなので、この説明はよく分かりませんでした。
ただ、リソースベースポリシーが許可されて、アイデンティティベースのポリシーが省略されたと覚えておこうと思います。

ですので、信頼ポリシー (リソースベースのポリシー) で Allow 効果が指定されていると、アイデンティティのポリシーで拒否が設定されていないと評価が省略されるようです。

試しに、以下の追加シナリオで試したみたところ、スイッチに失敗しました。
やはり、Deny は強力なようです。

追加シナリオ

リソース ポリシー 有/無
IAM ユーザー sts:AssumeRole Deny
IAM ロール 信頼ポリシー あり

クロスアカウントの場合

一方で、クロスアカウントの場合は、リソースベースポリシーとアイデンティティベースのポリシーの両方で評価を行うために、AssumeRole アクションがないとスイッチできないようです。*3

シナリオ 4 の謎

では、なぜシナリオ 1 はスイッチできないのでしょうか。

シナリオ 1 (再掲)

リソース ポリシー 有/無
IAM ユーザー sts:AssumeRole なし
IAM ロール 信頼ポリシー Root

リソースベースポリシー「Root」でアカウント内の全ての IAM が許可されているように見えます。
これに関しても、AWS サポートより、ドキュメントを紹介していただきました。 *4

リソースベースのポリシーにある Principal 要素か、プリンシパルをサポートする条件キーで、AWS アカウント の識別子を指定できます。これにより、権限がアカウントに委譲されます。

つまり、権限が委譲された際には、ID ベースのポリシーにて許可が必要となるようですが、ARN を指定しないと、ID ベースのポリシー評価が実行されると覚えておこうと思います。

まとめ

いかがでしたでしょうか。

IAM は、非常に細かいルールに基づいて評価されます。
AWS の認証は、IAM をベースにしているので、この大量の評価を一瞬で処理していると考えると、AWS のインフラの力は改めてすごいと感じました。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/images/PolicyEvaluationHorizontal111621.png [引用] アカウント内でのリクエストの許可または拒否の決定より

結論、省略しなければ事故がない、という感じです。

最後までお読みくださり、ありがとうございました。