IAM Roles for EC2を使ってみる(そしてSecurityTokenを無視してハマった話。)

新サイトを立ち上げる時期になったので、という口実でVPCを触り始めています。VPC関係やENIなんかもいろいろと独自の概念があって分かりづらいけども、ある程度、悪戦苦闘したあとには、よくできてんなー、コレという感想になるのがAWSってすげーなと思う所以なのかなと思う今日この頃。VPCやらは日本語情報は少ないものの、公式のドキュメントは充分充実してるし、SlideShareにある資料なんかも参照しながら、普通にドキュメントを読み進めていけば、という感じで進めていたのだけど、とりあえずその一環でIAM Rolesで個人的にハマったアホなポイントの備忘録。

IAM Rolesを使う理由は私の利用範囲だと、たぶん2つのどっちかかな、というところで上げると、

  1. credentialsまわりをAMIに保存しなくても(もしくは起動時に独自に取得しなくても)、一時的なcredentialsを利用できるのとその利用を簡略化された手順で利用できるという話
  2. EC2からアクセスできるリソース範囲を制限したいという話

という感じでしょうか。今回は1番目のAMIなんかにcredentialsを事前に保存したり、起動時に取得したりしないでも、STS経由で取得できるところを主に目的として利用しています。(利用制限も妥当な範囲ではかけますが、規模が小さく人数も少ないのでそこまで厳格に運用はまだしなくて良いかなと思っています。)

まず、STS(AWS Security Token Service)とはなんぞやというところ。ぶっちゃけ、 公式ドキュメント を読みましょう以外のなにものでもないけれど、今回はIAM Rolesの制限に従った各種APIにアクセスできる一時的なトークンを取得できるAPIくらいの認識でしょうか。

で、使い始めてみる

とりあえず、IAMでRoleつくって、EC2でRoleを割当する、というところは割愛。私は自分の作業環境などの関係で、iam-cliで作ったりとかec2-run-instances経由で立ち上げてはいますが、IAM Roleの作成やインスタンスの起動はManagement Consoleでもできるので、特に難しいところはないはず。

まずは手軽な利用方法。 各種のメタデータが簡単に使えるhttp://169.254.169.254のURLを使います。

$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/role-otto-app

"Code" : "Success",
"LastUpdated" : "2013-12-09T00:50:03Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "XXXXXXXXXXXXXXXXXXX",
"SecretAccessKey" : "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
"Token" : "AAAAAAAAAAAAAAAAAA//////////ZZZZZZZZZZZZZZZZZZZZZ/TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT/QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ==",
"Expiration" : "2013-12-09T06:49:51Z"

みたいな感じで、さくっと、AccessKeyIdとSecretAccessKeyを取得できます。これをつかって、IAM Roleに割り当てられた範囲でAPIが使えるようになるという手軽さ。これを起動時とかに読み込んで、環境変数に設定すればいいんだな、と思い込んだのが間違いのはじまり。ちゃんとドキュメントを読まなかっただけなんですが、Tokenという長い行があるなーくらいでどういう時に使うのかとか考えなかった。

botoから使う場合

で、ということで、実際に使う時は自分の場合、全体的にPythonでboto経由で使うことになるので、botoを使う前にurllibとか使って、AccessKeyId, SecretAccessKeyを抜き出して、それをbotoに設定します(Tokenは別にいらんかなとおもって無視しました、コレが。。。)。その上で、適当なbotoスクリプトでS3のバケット一覧とかを試しに取るところでエラーになります。

実行するとわかるんですが、AccessKeyIdがちげーよ(InvalidAccessKeyId)というエラーがでて認証に失敗します。えー、となってなんか設定まちがってんのかなぁとおもって、IAM Roles経由のCredentialのほうを疑いまくります。実際になにをしたかはもう思い出せないレベルですが、2-3時間くらいは、urllibでCredential取るところを疑ったりだとか、IAM Roleの設定を間違ってS3にアクセスできないようにしてるのかなとかそういう疑いをもってしらべました、たぶん。いやー、このときは苦しかったw

んで、最初からこれやればよかったんですが、最後にboto側がもしかしてと思って、自分でS3のAPIにアクセスするようにとおもって、書き始めたときに気づきます。あれ、IAM Rolesのtemporary credentialsでアクセスするときは、x-amz-security-tokenにTokenを入れろという文面を発見します。あー、あー、あー、みたいな感じで今までの間違いに気づきました。

で、ここまでくれば結論は簡単です。x-amz-security-tokenを設定して素でアクセスすると事も無くアクセスができました。

というわけで、いろいろ後悔が駆け巡るわけですが、ここまできて検索してみると、StackOverflowにそもそもbotoはIAM Rolesに対応していることにも気づきます。というわけで、事前に環境変数も、botoに取得したCredentialsを渡すこともなく、なにも設定しないで、さらっとboto経由でアクセスするスクリプトを実行します。はい、動きましたー。

大体筋を理解していると、”IAM Role boto”と検索するだけで、StackOverflowにモロそのままの回答が書かれています。これ ですね。

要はboto 2.5.1以降はIAM Rolesに対応しているので、特に事前に設定する必要はないよ、そうすれば勝手にCredentialsを取得するから。自分で事前に取得した場合は、ちゃんとSecurity Tokenも設定しないとね、と。そう、ただそれだけの話だったのです。

結論というか感想

とりあえず得た知見というほどでもなく感想レベルだけど。

  1. IAM Rolesで取得したCredentialsを使う場合にはちゃんとSecurity Tokenもx-amz-security-tokenに設定する必要がある。
  2. でも、botoが2.5.1以降であればそもそもIAM Rolesに対応しているわけで、環境変数もコードの中でCredentialsも渡さなければ自動的に取得して使ってくれるので深く考えるな。

というわけで、なんとなくの想像で使うの良くないという話。ちなみに、aws-sdkとかec2-api-toolsもIAM Roleに対応しているので、そのまま実行すれば自分でCredentialsを取ってくれるようです。

まあ、そんなこんなはあったものの、これでcloudinitでCredentialsを設定するようなことをするとかそういうのは必要なくなり、セキュリティ的にも改善して、どうやってAccessKeyIdとか渡そうかなぁという悩みがなくなるよ、という感じで、IAM Roleは便利だよという話、ただし、思い込みで変な使い方をしなければ。