はじめに
実務では作業者レベルに付与されるIAMユーザにはほぼ権限が与えられておらず、開発・テスト用などのロールにスイッチして初めて色々な作業が可能となるような運用は多いのかと思っています。
ロールの仕組みは深く理解できておらず、手順に沿って当たり前のようにロール切替して作業していた方も多いのではないでしょうか?(私です)
ローカル環境のテストでaws-sdkを使用してAWSサービスにアクセスが必要となった際、
このロール権限に対する認識が浅かったため大いに苦労しました。
戒めを含め、学んだことを整理したいと思います。
aws-cli使用時にロール権限でアクセスする
まず、ローカル環境でaws-cliを使うときは以下のような基本設定になります。
% cat ~/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXX
% cat ~/.aws/config
[default]
region = ap-northeast-1
output = json
ですが、冒頭でお伝えした通りIAMユーザではなくIAMロールに主体となる権限が与えられている場合、configの設定をいじってロール権限でアクセスする必要が出てきます。
その場合は以下のように編集した上で、コマンド実行時に --profile UserRole
を付けるか、環境変数 AWS_PROFILE=UserRole
を設定してあげる必要があります。
MFA認証は今回省いているのでmfa_serialは設定していません
% cat ~/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXX
% cat ~/.aws/config
[default]
region = ap-northeast-1
output = json
[profile UserRole]
region = ap-northeast-1
output = json
role_arn = arn:aws:iam::111122223333:role/user-role
source_profile = default
この設定により、指定したUserRoleというIAMロールの権限で各種リソースにアクセスができるわけなのですが、
role_arn
指定後のコマンド実行では見た目に表れない処理が内部で行われていることを知りました。
AssumeRoleというものです。
AssumeRole
AssumeRoleとは?
AWS Security Token Service (AWS STS)という機能で提供されている処理で、一時認証情報を取得できます。
つまり、ロール権限が欲しいならIAMユーザのアクセスキーではなく、そのロールを使用するための一時認証情報をAssumeRoleを使って取得してね、ということになります。
以下のようなsts:AssumeRole
を実行可能なポリシーがIAMユーザに付与されていると思います。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:root"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
AssumeRoleはいつ実行されている?
普段マネコン上で当たり前のようにスイッチロールしていましたが、どうやらその時内部では AssumeRole が毎回実行されているようでした。
前述の通りaws-cli使用時にrole_arnを指定する場合も実際には内部で AssumeRole が実行されています。
また、AssumeRoleはAWSリソースにロール権限を設定している場合も内部では実行されることになります。
つまり、IAMロールの裏側には必ずAssumeRoleが潜んでいるということですね。
では AssumeRole で取得される一時認証情報とはどのようなものか?
実際にaws sts assume-role
を実行すると以下のような結果が返却されます。
% aws sts assume-role \
--profile default \
--role-arn arn:aws:iam::111122223333:role/user-role \
--role-session-name test-session
{
"Credentials": {
"AccessKeyId": "XXXXXXXXXXXXXXXXX",
"SecretAccessKey": "XXXXXXXXXXXXXXXXX",
"SessionToken": "XXXXXXXXXXXXXXXXX....長い文字列...XXXXXXXXXXXXXXXXX",
"Expiration": "2023-09-02T07:06:21+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "XXXXXXXXXXXXXXXXX:test-session",
"Arn": "arn:aws:sts::111122223333:assumed-role/user-role/test-session"
}
}
ここで返却される AccessKeyId や SecretAccessKey はIAMユーザ設定のものとは異なるものです。
これを使うことでロールの切り替えを許可しているんですね、なるほど。
aws-sdk使用時にロール権限でアクセスする
普段マネコンでスイッチロールする時やCLIを使う時は裏側でAssumeRoleしてくれちゃうので意識したことなかったのですが、
ローカル環境からロール権限でaws-sdk API を使用したい!
となった際には assumeRole の理解が必須です。
aws-sdkを使用する場合は裏で勝手にロール切替してくれるわけではなく、自分でassumeRoleの工程を挟んであげる必要があったからです。
このようなケースでは
- 取得した一時認証情報を各sdk-clientの初期化処理に埋め込む(プログラムで対応)
- 環境変数に取得した一時認証情報を設定する
のどちらかになると思います。
私の場合は2.の手法で解決しました。(1.は試さなかったし長くなっちゃうので割愛)
手順としては単純で、
AssumeRole取得情報を
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXX
export AWS_SESSION_TOKEN=XXXXXXXXXXXXXXXXX
という感じに設定してあげるだけです。
なせこれで解決するかというと、aws-sdkの設定参照に関する優先順位が関係しています。
優先順位:
- コード内・サービスクライアントで定義された明示的な設定
- Java/Kotlin のみ:(関連する設定がある場合)JVMシステムプロパティの設定
- 環境変数
- ~/.aws/credentials情報
- SDK コードベース自体が提供するデフォルト値
コード内でAssumeRole取得値の設定orハードコーディングしていなければ、環境変数が優先される仕組みです。
ここまで理解できれば、
aws sts assume-role
に加えてaws sts get-caller-identity
のコマンドと組み合わせて、一時キーを環境変数に設定する作業をワンライナーで実行するスクリプトなんかも作れます。
(既に色々テンプレート提供してくれている方がいるので紹介は割愛します)
ということで、無事ローカル環境でもaws-sdkを使ったテストを可能とすることができました。
参考
IAM ロールの PassRole と AssumeRole をもう二度と忘れないために絵を描いてみた
https://dev.classmethod.jp/articles/iam-role-passrole-assumerole/
Assume Roleをいい感じにするスクリプトを書いた
https://dev.classmethod.jp/articles/eazy-assume-role-with-fzf/
AWS CLI を使用して IAM ロールを引き受けるにはどうすればよいですか?
https://repost.aws/ja/knowledge-center/iam-assume-role-cli
構成と認証設定のリファレンス
https://docs.aws.amazon.com/ja_jp/sdkref/latest/guide/settings-reference.html