AWS
EC2
Docker
IAM

EC2 + IAM Role で供給されたクレデンシャルを環境変数として使う


2016-12-09 14:15 追記

EC2 上の Docker コンテナ内からでも、AWS_ 環境変数を設定することなくインスタンスプロファイルが使えました。

AWS SDK は AWS_* 環境変数設定されてなかったら自動で http://169.254.169.254/latest/meta-data/... を叩いてクレデンシャルを取りに行きます。で、ホスト直実行でもコンテナ挟むのでもつなぎに行くネットワークは同じ AWS なので問題なくインスタンスプロファイルを取れるのでした。

したがって、この記事に書いてあるような手間をかける必要はありません…


tl;dr

AWS_SECURITY_TOKEN AWS_SESSION_TOKEN を忘れるな


2019-03-11 追記

awscli は AWS_SECURITY_TOKEN で実行できますが、 AWS SDK は AWS_SESSION_TOKEN でないと動作しないものがあるようです。

ログイン画面から発行されるワンタイムパスワードも現在は AWS_SESSION_TOKEN であるため、そちらに統一する方が良さそうです。


時代は IAM Role

EC2 上で AWS リソースにアクセスする場合、専用の IAM ユーザを作ってクレデンシャルを発行してもいいのですが、IAM Role を EC2 に紐付けると便利です。クレデンシャルをアプリケーションコードやスクリプトに埋め込む必要がなくなるからです。

しかし awscli や AWS SDK を埋め込んだコードをホスト上で直に実行する場合は彼らがよしなにクレデンシャルを取得するのでいいのですが、Docker コンテナ上で実行する場合は少々面倒です。-e AWS_ACCESS_KEY_ID= でクレデンシャルを渡したいのですが値はどこから取ればいいのか。

※ 今回は ECS 上ではなく1、直接インスタンス上で docker run する場合の話です。


metadata からクレデンシャルを取り出す

EC2 インスタンス内部から http://169.254.169.254/latest/meta-data/iam/security-credentials/<role name> を叩くと、いま現在有効なクレデンシャルが得られます。これを jq なりでパースして値だけ抜き出せばそのまま使えます。Expiration の時刻になったらクレデンシャルは入れ替わります。

core@ip-10-0-2-126 ~ $ curl -w '\n' http://169.254.169.254/latest/meta-data/iam/security-credentials/<role name>

{
"Code" : "Success",
"LastUpdated" : "2016-10-03T09:13:16Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "awsaccesskeyid",
"SecretAccessKey" : "awssecretaccesskey",
"Token" : "SecretToken",
"Expiration" : "2016-10-03T15:26:54Z"
}

ただ、このクレデンシャルを使うには AccessKeyId (= AWS_ACCESS_KEY_ID) と SecretAccessKey (= AWS_SECRET_ACCESS_KEY) だけ抜き出すのでは足りません :cry: Token (= AWS_SECURITY_TOKEN) も一緒にアプリケーション / スクリプトへ渡してあげる必要があります。

シェルスクリプトにするとこういう感じです (curl, jq 前提)。

#!/bin/bash

metadata=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/<role name>/)
export AWS_ACCESS_KEY_ID=$(echo $metadata | jq -r .AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $metadata | jq -r .SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $metadata | jq -r .Token)

docker run \
--rm \
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
-e AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN \
awesome:latest

自分はこれで数時間ハマったので、今後同じことをする人の助けになれば幸いです。


REF