【待ってた】「東京リージョンだけでXXXの実行を許可する」を簡単に実現するIAMのアップデート
はじめに
中山(順)です
待望のアップデートです!
すべてのAWSサービスで特定リージョンへのAPIリクエストを制御できるようになりました!
Easier way to control access to AWS regions using IAM policies
IAM Policyを記述する際、Conditionに"aws:RequestedRegion"というキーを利用することで指定したリージョンへのAPIリクエストを許可/拒否することができます。
これまで
EC2であれば、EC2専用のCondition Keyでリージョンを指定することが可能でした。
これから
まずはサンプルを見てください。
サンプル
見てもらうとわかりますが、非常にシンプルな使い方ができます。(以下の公式ドキュメントより拝借)
Available Global Condition Keys
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "StringNotEquals": { "aws:RequestedRegion": [ "eu-central-1", "eu-west-1" ] } } } ] }
このポリシーは、「アイルランドリージョンおよびフランクフルトリージョンを除く(StringNotEquals)リージョンですべてのアクションを拒否する」というものになっています。
ちなみに、後ほど理由も含めて述べますがこのポリシーには少々問題があると考えています。
やってみた
公式ドキュメントのサンプルポリシーと併せてAWSが提供するマネージドポリシーである"AdministratorAccess"を適用したユーザーでログインして動作を確認します。
今回はEC2のトップ画面を各リージョンごとに開き、正常に表示できるか確認します。(権限がない場合、リソースの数などが正常に表示できません)
以下、結果です。
アイルランド(OKな例)
東京(NGの例)
以上のように期待した結果を得ることができました。
注意点
しかし、すでに述べたとおりこのポリシーには少々問題があります。
グローバルサービス
多くのサービスは各リージョンごとに独立したサービス提供が行われています。 しかし、一部のサービスはリージョンに依存しない(ように見える)グローバルサービスとして提供されています。 それらのサービスはマネージメントコンソールの右上に「グローバル」と表示されるサービスです。
具体的には以下のサービスです。(他にもあるかも)
- IAM
- S3
- Route53
- CloudFront
- Mobile Analytics
- Support
- Cost Explorer, Budget
- Personal Health Dashboard
公式ドキュメントにあるポリシーをそのまま使ってしまうと、マネージメントコンソールを正常に表示できませんでした。 「東京リージョンのみ利用できるように制限したい」という要件を満たすためにこのポリシーをそのまま使ってしまうと、上記のグローバルサービスの利用に支障が出る可能性があります。
ちなみに、「サービスごとに許可設定を追加すればいいんじゃね?」と思われるかもしれませんが明示的なDenyは明示的なAllowよりも優先される仕様です。 詳細は以下のドキュメントを確認してください。
IAM JSON Policy Evaluation Logic
エンドポイント
なぜそのようなことが発生するのでしょうか。 その理由はサービスを提供するエンドポイントにあると考えてます。
こちらのドキュメントはAWSが提供するサービスのエンドポイントです。
先ほど列挙したサービスの一部は、バージニアリージョンにしかエンドポイントがありません。
- Route53
- CloudFront
- Mobile Analytics
- Support
- Cost Explorer, Budget
- Personal Health Dashboard
それ以外のサービスについては、各リージョンにエンドポイントはあるもののマネージメントコンソールの仕様上バージニアリージョンのエンドポイントにアクセスしてるものと推測されます。
- IAM
- S3
適切な使い方の例(異論は認める)
以下のサンプルをご覧ください。(冒頭でご紹介した公式ブログから引用)
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:DescribeAccountAttributes", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeVpcAttribute", "ec2:DescribeVpcs", "ec2:DescribeInstances", "ec2:DescribeImages", "ec2:DescribeKeyPairs", "rds:Describe*", "iam:ListRolePolicies", "iam:ListRoles", "iam:GetRole", "iam:ListInstanceProfiles", "iam:AttachRolePolicy", "lambda:GetAccountSettings" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:RunInstances", "rds:CreateDBInstance", "rds:CreateDBCluster", "lambda:CreateFunction", "lambda:InvokeFunction" ], "Resource": "*", "Condition": {"StringEquals": {"aws:RequestedRegion": "eu-central-1"}} }, { "Effect": "Allow", "Action": [ "iam:PassRole" ], "Resource": "arn:aws:iam::account-id:role/*" } ] }
権限の付与には、大きく2つのアプローチがあると思います。
- 「あらゆるアクションを許可するポリシーを付与」+「制限したいアクションを拒否するポリシーを付与」(引き算)
- 「必要最低限のアクションのみを許可するポリシーを付与」(足し算)
前者のアプローチには先ほど述べたような問題が起こりえるため、厳密な統制/無用なトラブルの防止を実現したい場合には十分な事前評価が必要だと考えます。
後者のアプローチは多少手間ではありますが、IAMのベストプラクティスである必要最低限度の権限付与を確実に実現できると思います。
私個人としては、後者のアプローチが好みです。
まとめ
少しだけ注意が必要ですが、「東京リージョンだけXXXを使えるようにしたい」のようなポリシーを簡単にかけるようになりました。
過去、アクセスキーが漏洩して海外リージョンに高価なEC2インスタンス立てられてbitcoin掘られるみたいな事件も発生したような記憶がありますが、そういったリスクの軽減にもつながりますね。
より安全かつ無理のないAWS運用のために、よりよいポリシーを書いていきましょう。
現場からは以上です。