IAMロール徹底理解 〜 AssumeRoleの正体
よく訓練されたアップル信者、都元です。最近私はIAM尽くしです。フルコースでIAM貪りまくりです。
さて、皆様はIAMにどのようなイメージをお持ちでしょうか。プロジェクトに関わる複数人で1つのAWSアカウントを扱う時、各メンバーに配布するアカウントを作れる機能。そして、その気になればアカウントをグループ分けし、権限を厳密に管理できる機能。といったところかと思います。
上記のユースケースで出てきた主なエンティティ(要素)はUserとGroupですね。IAMのManagement Consoleで見てみると、IAMはこれらの他にRoleやIdentity Providerというエンティティによって構成されているようだ、ということがわかります。今日はRoleにフォーカスを当てて、その実態を詳しく理解します。
IAM Role
IAM Roleを使うと、先に挙げたIAMのユースケースの他に、下記のようなことが出来るようになります。
要するに、「IAM Roleを使えば、EC2インスタンスにAPIアクセス権限を委譲できる」わけですが、ここで間違って欲しくはないのは、「IAM RoleはEC2インスタンスにAPIアクセス権限を委譲するため【だけ】に存在する機能である」というわけではない、ということです。コレが今日の本題。
まぁ確かに、IAM Roleのユースケースは、九分九厘、EC2インスタンスに対して権限委譲を行うことだとは思います。しかしそのイメージが強すぎて、IAM Roleの本来の意義とその他の使い方があまりにも知られていません。というわけで、まず新しい使い方を知るにあたって、EC2への権限委譲機能は一旦忘れてください。その上でIAM Roleを見つめ直します。
IAM Roleを構成する要素
ところで、IAM UserはUserName + Path、IAM GroupはGroupName + Pathから作成できます *1。Pathというのはあまり馴染みが無いかもしれませんが、大規模なユーザ管理を行う場合に、ユーザをディレクトリ分けするような仕組みです。ただ、小規模の場合はデフォルトの/を使うことが多いです。まぁここは本題ではないので割愛します。
さて、これと同じように、IAM Roleは下記3つの情報から作成できます *2。
- RoleName
- Path
- AssumeRolePolicyDocument
これら User, Group, Role に対しては、作成後の後付けで Policy を付与(put)できます。ユーザやグループに対して、ポリシーを付けられるのはお馴染みですね。ロールに対しても同様、ということです。
名前を指定すればユーザやグループが作れて、そこにポリシーを付与することによって権限の定義ができる、というのは直感的に理解できますね。ロールもほとんど同じ構成で、唯一の違いがAssumeRolePolicyDocumentという設定値が増えていることくらいです。この設定値については後ほど詳しく説明しますので、一旦脇へ。
IAM Roleの使い道
さて、一般的にユーザを作ったらAPIキー作成やパスワード設定を行い、APIアクセスなりManagement Consoleに対してログインして使いますね。グループを作ったら、ユーザを追加したり削除したりで権限のコントロールをしますね。
ではロールを作ったら何に使うんでしょうか。その答えはsts:AssumeRoleです。
皆さんは、Security Token Serivce (STS)というAWSプロダクトをご存知でしょうか。IAMに従属するサブプロダクト的な位置付けで、Management Consoleが用意されていないため、少々日陰感があります *3。
さて、AssumeRoleはSTSに対するAPIアクションの一つです。このリクエストによって、役割(role)を引き受ける(assume)ことができます。わかります? 私はさっぱりでしたw
私は長らくこのassumeという単語にヤられていました。さっぱり意味がわからんのです。辞書を引くと「当然〜と思う」「〜だと仮定/想定する」「〜を本当だと思う」という記述が並びます。さっぱりじゃありませんか? まぁこの辺りでギブアップしていました。先を読み進めれば「〜を引き受ける」「〜な性質を帯びる」「〜を装う」といった記述があり、理解した後で考えればこの辺りの雰囲気が近いんですが。
ちなみに、公式ドキュメントではassumeを「引き受ける」と訳してあります。
ロールの引き受けとは
最終的に私は、単語の意味を考えると訳わがらなくなるようなので、アクションの方法と結果、つまりAPIの入出力を考えることにしました。結局枝葉を取り去ると、「AssumeRoleはRoleArnを入力するとCredentialsを返すAPIだ」ということがわかります。
RoleArnというのは、IAM Roleの一意な名前で、arn:aws:iam::123456789012:role/role-nameといった文字列 *4です。返されるCredentialsは一時キー *5で、有効期限は1時間でした。
さて、ここまで情報が出揃うと、皆さん大体予想がついてくるかと思います。そうです、AssumeRoleの結果得られたAPIキーは、Roleに対して付与された権限を持っています。結果として、元々のユーザが本来持っていた権限とは別の範囲の権限を、一時キーとして手に入れたことになります。私の脳内イメージだとUNIXコマンドのsu *6、もしくは将棋の成駒 *7のような…。もしくは、別人に成りすますための「お面」をかぶるイメージかもしれません。
このように、ロールに設定された権限を持った一時キーを入手することを「役割(role)の引き受け(assume)」と言います。
IAMロールのセキュリティ
このように、IAM Roleは第三者に「自アカウントのAPI権限を委譲する」ためのものです。しかし、自アカウントのロールを誰でも無邪気に引き受け(assume)出来てしまったら、セキュリティもへったくれもありません。各ロール毎に、第三者に対して明示的に引き受けを許可する設定が必要です。この設定がAssumeRolePolicyDocumentです。脇に置いといた話が戻って参りました。ちなみに、ここで「許可を受けた第三者」のことをTrusted Entityと呼んだりします。
AssumeRolePolicyDocumentは、ユーザやグループに付与するPolicyと同じ形式で記述します。が、可変部は主にPrincipalの部分だけです。その他の部分は基本的に変更しません。
第三者第三者と表現していますが、Principalでその第三者を表します。下記の通りいろんなモノを信頼できます。
他のAWSアカウントを信頼する
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "AWS": [ "123456789012" ] // ← AWSアカウントを信頼 }, "Action": "sts:AssumeRole" } ] }
このようなポリシーを設定すると、他のAWSアカウント(のAPIキーを使って)がAssumeRoleできるようになります。つまり、アカウントを超えたリソースの操作(クロスアカウントアクセス)が実現できます。S3であればbucket policy等で別アカウントを指定することによりクロスアカウントアクセスができましたが、その他全てのAWS APIコールにおいてクロスアカウントアクセスが実現できるわけです。
AWSサービスを信頼する
{ "Version" : "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ec2.amazonaws.com" ] // ← EC2サービスを信頼 }, "Action": "sts:AssumeRole" } ] }
さて、ここで封印した記憶を呼び起こします。「EC2サービス」を信頼することにより、「EC2がAssumeRoleを行えるように」なります。
具体的に、EC2インスタンス内から http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name にアクセス *8があると、「EC2サービス」がAssumeRoleを行い、その結果をJSONとしてHTTPレスポンスに乗せて返すわけです。
EC2によるIAM Roleの利用は、「ロールによる権限委譲」という基盤の上に構築された単なる一機能である、ということがご理解頂けるかと思います。ちなみに、AWSサービスに対する信頼はEC2だけではなく、CloudHSM, Data Pipeline, Elastic Transcoder, OpsWorks を指定することもできます。
Facebookユーザを信頼する
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRoleWithWebIdentity", "Principal": { "Federated": "graph.facebook.com" }, "Condition": { "StringEquals": { "graph.facebook.com:app_id": "012345678901234" // ← FacebookアプリケーションID } } } ] }
かなりマニアックな領域に入ってきましたが、Facebookアプリを介して、Facebookユーザを信頼することもできます。この手法は、モバイルアプリケーションにとって非常に有力で魅力的な仕組みとなります。Facebookユーザに対してAssumeRoleを許すということは「モバイルアプリでFacebook認証を使って、AWSの一時キーを手に入れられる」ということに他なりません。AWS as mBaaSへの入り口です。
この信頼は、Facebookだけでなく、GoogleやAmazon.comのIDでも実現できます。さらに(冒頭に出てきた)Identity Providersとして、独自のシステムをSAML Providerとして登録すれば、そのシステムに認証を委譲することも可能です。
まぁ、そんな話はいずれまた。
まとめ
いかがでしたでしょうか。IAM RoleはEC2に対する権限付与のための機能である、という固定観念を打ち破ることはできましたか? 突き詰めると非常に面白い機能であることが伝われば幸いです。
脚注
- 参考: iam:CreateUser, iam:CreateGroup ↩
- 参考: iam:CreateRole ↩
- 往年のAutoScalingのような立ち位置でしょうか。彼もEC2に従属するサブプロダクト的な位置付けで、長らくManagement Console経由での操作ができませんでした。 ↩
- 参考: Amazon Resource Names (ARNs) and AWS Service Namespaces ↩
- 参考: IAMによるAWS権限管理運用ベストプラクティス (2) ↩
- UNIXのsu対象は「ユーザ」ですが、Roleは「ログインできる主体ではない」というのが相違点です。 ↩
- 元のユーザが強化されるわけではなく、別のクレデンシャルが支給される、というのが相違点でしょうか。 ↩
- 参考: Instance Metadata and User Data ↩