リモートワークでSecurity Groupの変更をユーザーの所属するプロジェクトだけ許可する設定をABACでやってみた
こんにちは、臼田です。
みなさん、アクセス制御してますか?(挨拶
今回は比較的簡単なABAC(Attribute Based Access Control / 属性ベースのアクセス制御)としてSecurity Groupのルール変更だけを許可する設定をやってみたいと思います。
どんなことを実現したいか
説明の前提として、AWSの管理者と、EC2を利用して作業をしたいユーザーがいるとします。ざっくり以下のことを実現したいとします。
- ユーザーはEC2にアクセスしたい
- リモートワークをしているのでIPはユーザーに設定させたい
- 管理者はユーザーにあまり強い権限を渡したくないためEC2にアタッチしたSecurity Groupの変更のみを許可したい
- 他にもEC2やSecurity Groupがあるので変更を許可するリソースを限定したい
ここまでの条件の場合、「IAMポリシーで対象のリソースを指定すればいいのでは?」と考えると思います。それでも可能ですが、更に以下の条件を考えるとリソースの指定が大変になります。
- 制御したいユーザーとリソースとプロジェクトがたくさんある
この場合、管理者はプロジェクトが増えるたびIAMポリシーを作成したり、リソースが増えるたびにIAMポリシーを変更したりしなければなりません。
これを解決するのがABACです。ABACはAWSのドキュメントでは以下のような図で説明されます。
図の左側はIAMリソースです。これは帽子のアイコンなのでIAM Roleですが、IAMユーザーやIAMグループでも同じように利用することが可能で、重要なのは帽子の右上についているタグです。3種類のタグがあると表現されています。そして右側の各種リソースも、それぞれタグが付いています。真ん中にあるのがIAMポリシーです。ABACはタグを利用したアクセスコントロールで、IAMリソースについているタグと操作対象のリソースについているタグが同じ場合にのみ利用できるようにIAMポリシーを記述して制御します。
今回の要件を満たす場合、ユーザーに渡すIAMに付与したProjectタグと、Security Groupに付与したProjectタグを一致させ、それをつなぐためのABACのIAMポリシーを作成してユーザーのIAMに付与すればOKです。
ABACやってみた
それでは実際にやってみます。
ABAC対応のIAMポリシー作成
まずABACに対応したIAMポリシーを作成します。これが今回の肝です。
IAMのポリシー画面からポリシーの作成を始めます。直接jsonを指定してもいいですが、今回はビジュアルエディタで説明します。サービスでEC2
を選択(Security GroupはEC2のサービスAPIです。VPCも)、アクションはAuthorizeSecurityGroupIngress
(Security Groupのインバウンドルールの追加)とRevokeSecurityGroupIngress
(Security Groupのインバウンドルールの削除)を選択、リソースは比較的自由ですが今回はリージョンとアカウントまでは絞っておきます。そしてリクエスト条件を展開して「条件の追加」をします。
リクエスト条件の追加では、条件キーとしてaws:ResourceTag
を選択します。これは操作する対象に付与されたタグを条件にします。条件キーは候補がたくさんあって、グローバルの条件キーとサービスレベルの条件キーという2つの種類に分類されてリストがソートされているのと、似たような名前の条件キー(aws:RequestTag
など)があるので注意して下さい。TagKeyはリソースに付けられた、条件にしたいタグのKeyです。今回はProjectというタグを利用するためProject
と入力します。限定条件は対象のリソースによって変えますが今回はデフォルトのまま。演算子は一致であるStringEquals
にします。そして値はポリシー変数である${aws:PrincipalTag/タグキー}
を利用します。ポリシー変数はIAMポリシーを記述する際に活用できる変数です。詳細はこちら。aws:PrincipalTag
はプリンシパル、つまりAPIを実行するIAMなどの認証情報側のタグを意味していて、今回は${aws:PrincipalTag/Project}
とすることで値をプリンシパルに付いているProjectタグの値を利用することができます。今回はリソース側のタグとプリンシパルのタグを同じProject
としていますが、別々のものを利用することもできます。
ついでに今回はすべてのSecurity Groupが見れるようにDescribeSecurityGroupsも条件を付けずに追加しておきます。
ここまでのポリシーをjsonにすると以下のようになっています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "ec2:RevokeSecurityGroupIngress", "ec2:AuthorizeSecurityGroupIngress" ], "Resource": "arn:aws:ec2:ap-northeast-1:999999999999:security-group/*", "Condition": { "StringEquals": { "aws:ResourceTag/Project": "${aws:PrincipalTag/Project}" } } }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": "ec2:DescribeSecurityGroups", "Resource": "*" } ] }
適当な名前を(今回はAllowEditSecurityGroupABACPolicy)付けて作成します。
IAMユーザーへポリシーをアタッチ
続いて作成したIAMポリシーをIAMユーザーへアタッチします。もちろんIAMグループやRoleでも大丈夫ですが、今回はユーザーで簡単に試します。
適当にproject-a-userという名前のユーザーを作ります。作成時に先ほど作成したIAMポリシーを直接アタッチします。IAMユーザーへの直接アタッチはベストプラクティスではないので、ちゃんとやるときはグループを使って下さい。
そしてIAMユーザーのタグとしてProject: Project-A
を付与します。後ほどこれと同じものをSecurity Groupにも付与します。これでユーザー作成を完了します。
Security Groupの作成
操作の対象となるSecurity Groupを作成します。作成時に前述の通りこちらにもタグとしてProject: Project-A
を付与します。これで準備は整いました。
インバウンドルールの追加
実際にABACを利用したインバウンドルールの追加をやってみます。
作成したユーザーでログインした後、SSHをマイIPで指定して作成してみます。
成功しました。
これだけだと本当に制御されているか分かりづらいので、元の権限でログインし直してIAMユーザーのProjectタグをProject-B
にしてみます。ユーザー名はproject-a-user
だけどタグはProject-B
なんて、実環境では絶対にやめたほうがいい設定ですが。
再度作成したユーザーでログインして今度はHTTPのマイIPを追加してみます。
エラーとなり失敗しました。これで、タグが適切に評価されてABACが実現できていることが確認できました。
まとめ
ABACを利用してSecurity GroupのIPアドレス設定をユーザーに任せつつ、制御をタグで行う方法を紹介しました。リモートワークでのIPアドレス管理が少し楽になると思います。
もちろんSecurity Group以外のリソースもABACで制御ができます。是非試してみて下さい。
ABACの条件をより詳細に理解したい場合は以下を参考にして下さい。読み応えがあります。
また、IPアドレスの設定を任せる場合にはうっかり0.0.0.0/0からのアクセスを許可しないよう周知徹底しつつ、以下のようなチェックや自動修復、あるいはポリシーで禁止するなども合わせて検討するといいでしょう。