すべての AWS プリンシパルを信頼ポリシーで許可している IAM ロールが環境にないか確認する
うっかり広めに許可している IAM ロールはないかな
コンバンハ、千葉(幸)です。
IAM ロールを引き受け可能なプリンシパルは、IAM ロールの信頼ポリシーによって制御されます。
プリンシパルの種類には以下の種類があります。
# | プリンシパル | 例 |
---|---|---|
1 | AWS アカウント | "AWS": "arn:aws:iam::123456789012:root" |
2 | IAM ロール | "AWS": "arn:aws:iam::AWS-account-ID:role/role-name" |
3 | ロールセッション | "AWS": "arn:aws:sts::AWS-account-ID:assumed-role/role-name/role-session-name" |
4 | ウェブ ID セッション | "Federated": "cognito-identity.amazonaws.com" |
5 | SAML セッション | "Federated": "arn:aws:iam::AWS-account-ID:saml-provider/provider-name" |
6 | IAM ユーザー | "AWS": "arn:aws:iam::AWS-account-ID:user/user-name" |
7 | フェデレーテッドユーザー | "AWS": "arn:aws:sts::AWS-account-ID:federated-user/user-name" |
8 | AWS サービス | "Service": "service-name.amazonaws.com" |
9 | すべて | "AWS" : "*" |
ここで、一番下の「すべて」を許可するのは避けるべきです。それは言ってみればどんな AWS アカウントからでも AssumeRole 可能な状態です。「AWS アカウント番号」と「IAM ロール名」の組み合わせが何らかの形で外部のユーザーに把握されてしまうと、不正に利用され放題になります。
これからの設定を避けるのは当然として、うっかり「すべて」を許可している IAM ロールが自分の環境にないかな、を確認するアプローチを考えてみました。
すべてのプリンシパルを信頼した IAM ロールとはどんな状態か
確認手段を見ていく前に、「すべて」のプリンシパルを信頼ポリシーで許可している状態がどんなものかを見ていきます。
少し考えるスコープを絞って、IAM ユーザーが IAM ロールを引き受けるケースのみを考えます。観点として以下を挙げます。
- クロスアカウントかどうか
- IAM ロールの信頼ポリシーでどの範囲で許可されているか
- アカウント単位:
"AWS": "arn:aws:iam::123456789012:root"
- ユーザー単位:
"AWS": "arn:aws:iam::AWS-account-ID:user/user-name"
- すべて
"AWS" : "*"
- アカウント単位:
- IAM ユーザーの IAM ポリシーで許可があるか
パターンごとの AssumeRole 可否は以下の通りです。
# | アカウント | 信頼ポリシー | IAMポリシー | 結果 |
---|---|---|---|---|
1 | 同一 | アカウント単位で許可 | 許可あり | 許可 |
2 | 同一 | アカウント単位で許可 | 許可なし | 暗黙的な拒否 |
3 | 同一 | ユーザー単位で許可 | 許可あり | 許可 |
4 | 同一 | ユーザー単位で許可 | 許可なし | 許可 |
5 | 同一 | 「すべて」で許可 | 許可あり | 許可 |
6 | 同一 | 「すべて」で許可 | 許可なし | 許可 |
7 | 同一 | 許可なし | 許可あり | 暗黙的な拒否 |
8 | 同一 | 許可なし | 許可なし | 暗黙的な拒否 |
9 | クロス | アカウント単位で許可 | 許可あり | 許可 |
10 | クロス | アカウント単位で許可 | 許可なし | 暗黙的な拒否 |
11 | クロス | ユーザー単位で許可 | 許可あり | 許可 |
12 | クロス | ユーザー単位で許可 | 許可なし | 暗黙的な拒否 |
13 | クロス | 「すべて」で許可 | 許可あり | 許可 |
14 | クロス | 「すべて」で許可 | 許可なし | 暗黙的な拒否 |
15 | クロス | 許可なし | 許可あり | 暗黙的な拒否 |
16 | クロス | 許可なし | 許可なし | 暗黙的な拒否 |
トピックとしては #6,#13 があります。
同一アカウントの場合、「すべて」で許可していると IAM ユーザー側に許可がなくても AssuemRole が成功します。(#6)
クロスアカウントの場合、「すべて」で許可していると IAM ユーザーの IAM ポリシー側で許可があれば AssumeRole が成功します。(#13)そこだけで考えれば #9 や #11 と同じですが、範囲が限定されず世界中のあらゆる AWS アカウントから AssumeRole ができる状態なので怖いですね。
すべてのプリンシパルを許可した IAM ロールを作成してみる
あえてアンチパターンをやってみる、ということで"AWS" : "*"
を許可した信頼ポリシーを持つ IAM ロールを作成してみます。
ロールの作成を試み、最初のステップでカスタム信頼ポリシーとして以下のポリシー内容を設定して次に進みます。
(ポリシーの内訳は以下です。迂闊に真似しないでください。)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Principal": { "AWS" : "*" }, "Action": "sts:AssumeRole" } ] }
IAM ロールに権限は持たせず、名称等を指定して作成を試みます。作成実行前に確認が入ります。
広範なアクセス: ワイルドカード (*、?) を含むプリンシパルは過度に許容される可能性があります。
この信頼ポリシーを続行してよろしいですか?
「続行」を押して作成を完了させます。
ロールの作成自体は正常に完了します。ロールの詳細画面を開くと、上部に注意書きが表示されています。
作成自体はできるものの、要所で止めてくれたり作成後も分かりやすくしてくれていることが分かります。
プリンシパルでワイルドカードを設定するときに AWS キーの指定は必須
今回はプリンシパルで"AWS" : "*"
のように AWS キーを含む形で指定しました。リソースベースポリシーとしてはプリンシパルを単に"*"
と書くこともできるので、信頼ポリシーでもできるのか試してみました。
以下の信頼ポリシーを設定してロールの作成を試みます。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Principal": "*", "Action": "sts:AssumeRole" } ] }
エラーが発生しました。
ロール dummy-role2 の作成に失敗しました。
AssumeRolepolicy contained an invalid principal: "STAR":"*".
信頼ポリシーではキーなしのワイルドカードは指定できない、とドキュメントにも書いてあります。
信頼ポリシーを作成するときは、プリンシパルとしてワイルドカード (*) を指定することはできません。
AWS キーの指定が必須、というのはこの後にちょっとだけ関連します。
すべてのプリンシパルを許可している IAM ロールが無いかを確認する
ようやく本題です。
過去と管理者が違う、さまざまなステークホルダーがいるのできちんと統制が取れていない、などで IAM の管理が行き届いていないこともあるでしょう。
今後作成する分については気をつけるにしても、すでに「すべて」を許可している IAM ロールが環境に存在しないかを確認したいケースを想定します。
ここでは以下のパターンでの確認を考えました。
- コンソールの一覧から確認する
- IAM Access Analyzer で確認する
- AWS CLI で確認する
コンソールの一覧から確認する
一番とっつきやすいパターンです。
単にロールの一覧画面から「信頼されたエンティティ」列を確認するだけです。アカウント:*
となっているものがないかを確認します。
何かを有効化したり別途コマンドを叩いたりしなくて済むのは楽ですが、以下の注意事項があります。
- ロールの数が多いと単純に確認するのが辛い
- 信頼されたエンティティを基にフィルターできたりはしない
- プリンシパルが複数ある場合、
アカウント:*
が先頭に表示されるとは限らない
例えば以下のような信頼ポリシーのロールがあった場合、一覧上ではアカウント:000000000000
が先頭に来てアカウント:*
が確認できない場合があります。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::000000000000:root", "*" ] }, "Action": "sts:AssumeRole" } ] }
コンソール上で表示される順番には特に規則性が見つけられませんでした。読み込み直すたびに順番が変わっていたので、ランダムなのだろうと思っています。
IAM Access Analyzer で確認する
これが一番あるべき手段です。ただ有効化するだけで、分かりやすく検知してくれます。
"AWS" : "*"
を信頼ポリシーに含む IAM ロールは外部プリンシパルが「すべてのプリンシパル」として表現されて検出されます。
単発の確認手段としてもいいですし、EventBridge や Security Hub と組み合わせれば通知も実現できます。
今回のケースに関係なく、IAM Access Analyzer は有効化しておいて損はありません。無料です。
AWS CLI で確認する
取り急ぎ確認したいんだけど、環境に変更を加えるには許可がいるので IAM Access Analyzer がすぐには使えない……!というケースでは AWS CLI を使うのも選択肢のひとつかと思います。
以下のコマンドを実行することで一覧で取得できます。
% aws iam list-roles \ --query "Roles[?contains(AssumeRolePolicyDocument.Statement[0].to_string(Principal.AWS),\`*\`)].[RoleName]" --output text # dummy-role0 # dummy-role1 # dummy-role2
ただ、わたしの query 力が足りなく、上記のコマンドでは以下のように2番目以降のステートメントに"AWS": "*"
が含まれる場合は検出されません。 *1
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" }, { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "sts:AssumeRole" } ] }
あくまで副次的な手段として割り切って使っていただければと思います。
終わりに
IAM ロールの信頼ポリシーですべてのプリンシパルを許可しているものがないかを確認する手段をまとめてみました。
一番望ましいのは IAM Access Analyzer による確認です。まだ有効化されていない方は、これを機に有効化をお勧めします。それを第一選択肢としつつ、のっぴきならない事情でそれが叶わない場合には他の手段で頑張って確認しましょう。
IAM ロールの信頼ポリシーを意識し、セキュアな環境を保っていきましょう。
以上、 チバユキ (@batchicchi) がお送りしました。
関連
脚注
- いい書き方が思いついた方は教えていただけると嬉しいです ↩