ありがたい事に職場外でも多くの方と共同でモノを作る機会が増えてきた最近、自分以外のAWSアカウントのIAMロール権限を貰ったり、逆に自アカウントのIAMロール権限を他の人に渡したりで、STSで一時認証情報を受け取り/受け渡す事が頻繁に発生するようになってきました。
その際に、CLI用の設定ファイルに毎回内容を手動で追記するのが面倒に感じるようになってきたり、設定ファイル内に多数の一時情報が残り続ける事により「このprofileは何用途だっけ?」と自分でも分からなくなってしまったり、逆に受け取った情報を削除してしまい同じ内容を再度聞く羽目になったりなど、一時認証情報をCLIで使用する際の管理方法に幾つか課題を感じるようになりました。
そこで、CLIで一時認証情報を使用する場合にどんな方法が存在するのかと、それぞれの問題点を整理して、一時認証情報の管理を少しだけ楽にするこんなものを作ってみましたというのが今回の内容になります。
今回解決したい課題
今回解決したい課題は、以下三つです。
1. 一時認証情報を毎回手動で追記する手間を最小化したい
一時認証情報を使用する為の記述を、AWS CLI用の設定ファイルや環境変数に追記するだけと言えばそれまでですが、毎回これをやるのは結構面倒です。
委譲元から渡される情報が毎回変わる為完全な自動化は難しいものの、引数に情報を渡してコマンド一発で登録完了させるぐらいまでの自動化はさせたいです。
2. 一時情報の有効期限を意識することなく使えるようにしたい
STSで委譲される一時認証情報には、使用可能な有効期限が存在します。
一時情報という特性上当たり前と言えば当たり前ですが、CLIでコマンドを実行時に有効期限切れで再度一時認証情報を取得して設定ファイルを上書きしてからコマンドを実行し直すのはやはり面倒なので、コマンド実行時に有効期限切れが起こらないようにする状態は作りたいです。
3. 受け取った一時認証情報を管理可能にしたい
一時認証情報を貰う度にCLI用の設定ファイルに追記していると、ファイル内のprofileがどんどん増えていってしまい、自分でもこのprofileは何の用途だったを忘れてしまうなど管理が難しくなってきます。
かと言って、毎回profileを削除/上書きしていると、「以前に使用したあの一時認証情報をまた使いたくなったけど、ロールARNを消してしまったので再度教えてもらわなきゃ…」なんて事態にもなってしまうので、削除/上書きされた情報はどこかに残しておき、いつでも復元可能にもしておきたいです。
そこで、設定ファイルへ追記/削除/上書き時にどんな情報がいつ何の用途で変更(追加/削除/上書き)されたのかを自動で記録でき、いつでも確認できる仕組みを作り、一時認証情報を管理可能な状態を作ります。
今回用意したサンプル環境
一時認証情報を使用する際の確認用のサンプル環境として、以下を用意しました。
権限を委譲する側アカウントのIAMロール
まずは各種操作の権限を委譲する側アカウントのIAMロールを作成します。
今回は、TestSTSProviderRoleというIAMロールを作成しました。
セッションの有効期限の最大時間はデフォルトの1時間で、プリンシパルには委譲される側のアカウントのAWSアカウントIDを許可しています。
* 委譲される側のアカウントにMFAでの多要素認証を強制したい場合は、Principalの条件のmultifactorAuthPresentにtrueを指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::xxxxxxxxxxxx:root" }, "Action": "sts:AssumeRole", "Condition": { "Bool": { "aws:multifactorAuthPresent": "true" } } } ] } |
指定したIAMユーザのみを許可する場合は、Principalのroot部分を許可するIAMユーザ名に変更する事で制御可能ですが、今回は対象アカウントの全IAMユーザに対して許可するようにしています。
アタッチするポリシーは、S3のテストバケットに対するRead権限のみとしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:Get*", "s3:List*" ], "Resource": [ "arn:aws:s3:::test-s3-bucket-for-sts" ] } ] } |
委譲される側のアカウントのAWS CLI用IAMユーザ
次に、権限を委譲される側のアカウントに、上記で作成したIAMロールから権限を引き受けて使用するIAMユーザを作成します。
今回は、TestSTSProvidedUserというIAMユーザを作成しました。
アタッチするポリシーは、作成したIAMロールへのSTS.AssumeRole権限のみです。
1 2 3 4 5 6 7 8 9 10 |
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": [ "arn:aws:iam::xxxxxxxxxxxx:role/TestStsProviderRole" ] } } |
作成したユーザを使用したCLI操作を可能にする為、test-sts-provided-userというprofile名で設定ファイルにクレデンシャル情報を追記すれば準備は完了です。
1 2 3 |
[profile test-sts-provided-user] region = ap-northeast-1 output = json |
1 2 3 |
[test-sts-provided-user] aws_access_key_id = xxxxxxxxxxxxxxxxxxxx aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
【前提】一時認証情報取得/使用時のフロー
準備が整ったところで、まずはSTSのAssumeRoleを使用して一時認証情報を取得/使用する際のフローのおさらいです。
今回は、各種SDKでプログラム上から使用する場合を例に見ていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import boto3 from boto3.session import Session iam_user_session = Session( aws_access_key_id="xxxxxxxxxxxxxxxxxx", aws_secret_access_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxx", region_name="ap-northeast-1", ) token_code = input("Enter MFA code: ") ## SerialNumberとTokenCodeは多要素認証必須時のみ sts_response = iam_user_session.client("sts").assume_role( RoleArn="arn:aws:iam::xxxxxxxxxxxx:role/TestStsProviderRole", RoleSessionName="sts_test_session", DurationSeconds=900, ## between 900 and 3600 SerialNumber="arn:aws:iam::xxxxxxxxxxxx:mfa/TestStsProvidedUser", TokenCode=token_code, ) sts_session = Session( aws_access_key_id=sts_response["Credentials"]["AccessKeyId"], aws_secret_access_key=sts_response["Credentials"]["SecretAccessKey"], aws_session_token=sts_response["Credentials"]["SessionToken"], region_name="ap-northeast-1", ) s3_client = sts_session.client("s3") s3_client.list_objects(Bucket="test-s3-bucket-for-sts") |
上記のようなコードになり、分解すると以下3ステップに分ける事ができます。
- 委譲される側のアカウントのIMAユーザのクレデンシャルを使用してsts.assume-roleを実行して、一時クレデンシャル情報を取得
- 取得した一時クレデンシャル情報を使用して一時的なセッションを作成
- 作成した一時セッションを使用して、委譲された権限でアクセス可能な各種リソース(今回はs3)のクライアントやリソースを使用
とてもシンプルなフローで、迷う事はほぼないと思います。
CLIから一時認証情報を使用する場合を考える
次に、CLIからSTS.AssumeRoleで一時認証情報を取得/使用する場合にどんな方法があるかを考えていきます。
プログラム上からの実行時は、取得した一時認証情報はプログラムの実行終了時まで持っていれば十分だった性質上、プログラム内から参照可能な変数に格納する方法が取れましたが、CLIからの実行時には有効期限内は何度でもコマンドを実行する可能性がある為、一時変数へ保存する方法が使えません。
よって、取得した一時認証情報をCLI用の設定ファイルに保存して管理する必要が出てくるのですが、どう管理するかには幾つか方法がある為、その方法を選択時にどんなメリット/デメリットがあるかを一つずつ見ていきます。
1. sts assume-roleのコマンドを都度叩き、取得したクレデンシャル情報を登録して使用する
最も原始的な方法です。
SDKを使用してプログラム上から実行したフローの3ステップをそのままなぞっていく感じで、一時認証情報が必要になる度に毎回CLIでsts assume-roleのコマンドを叩き、返ってきたクレデンシャル情報を登録して使用する(取得した情報は、有効期限内であれば継続使用可能)使い方です。
登録方法は2種類あり、環境変数(AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_SESSION_TOKEN)に登録するか、CLI用の設定ファイルにprofile付きで追記するかのどちらかです。
環境変数に登録した場合は、コマンド実行時にprofileの指定をする煩わしさを回避できるメリットがある反面、デフォルト設定が一時認証情報に書き換わってしまう関係で普段使用するアカウントとのスイッチロールが面倒(別タブを開いて操作などで対処)なデメリットがあります。
逆に、CLI用の設定ファイルに追記した場合は、各アカウント間でスイッチロールしながら操作を行う時が便利な反面、一時認証情報を使用する場合に毎回コマンドでprofileを指定しなければならない欠点があります。
- 委譲される側のアカウントのIMAユーザのクレデンシャルを使用してsts.assume-roleを実行して、一時クレデンシャル情報を取得
- 取得したクレデンシャルを登録して、一時認証情報を使用可能にする
- 環境変数に登録する場合
- CLI用の設定ファイルに追記する場合
- 登録した情報を使用して、委譲された権限でアクセス可能な各種リソース(今回はs3)のクライアントやリソースを使用
委譲される側のアカウントのtest-sts-provided-userをprofileに指定して、コンソールからstsのassume-roleコマンドを叩きます。
今回は、セッション名をsts_test_session、有効期限を1時間で指定します。
serial-numberとtoken-codeの指定は、多要素認証必須時のみです。
1 2 3 4 5 6 7 |
$ aws sts assume-role \ --role-arn arn:aws:iam::xxxxxxxxxxxx:role/TestStsProviderRole \ --role-session-name sts_test_session \ --duration-second 3600 \ --profile test-sts-provided-user --serial-number arn:aws:iam::xxxxxxxxxxxx:mfa/TestStsProvidedUser --token-code xxxxxx |
下記のようなレスポンスが返ってくるので、Credentials内のAccessKeyId,SecretAccessKey,SessionTokenの3つをメモしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "Credentials": { "AccessKeyId": "{AWS_ACCESS_KEY_ID}", "SecretAccessKey": "{AWS_SECRET_ACCESS_KEY}", "SessionToken": "{AWS_SESSION_TOKEN}", "Expiration": "2020-08-04T05:32:36+00:00" }, "AssumedRoleUser": { "AssumedRoleId": "{USER_ID}:sts_test_session", "Arn": "arn:aws:sts::xxxxxxxxxxxx:assumed-role/TestStsProviderRole/sts_test_session" } } |
メモしたクレデンシャル情報を、環境変数に登録 or CLI用の設定ファイルに追記のどちらかの方法で登録して使用可能にします。
メモしたクレデンシャル情報を、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_SESSION_TOKENの三つの環境変数に登録します。
1 2 3 |
export AWS_ACCESS_KEY_ID=${メモしたAccessKeyId} export AWS_SECRET_ACCESS_KEY=${メモしたSecretAccessKey} export AWS_SESSION_TOKEN=${メモしたSessionToken} |
メモしたクレデンシャル情報を、ユーザホームの.awsディレクトリ配下のconfig,credentialsの2ファイルに追記します。
今回は、sts-sessionというprofile名で登録します。
1 2 3 |
[profile sts-session] region = ap-northeast-1 output = json |
1 2 3 4 |
[sts-session] aws_access_key_id = ${メモしたAccessKeyId} aws_secret_access_key = ${メモしたSecretAccessKey} aws_session_token = ${メモしたSessionToken} |
登録した情報を使用してcliコマンドを実行すると、委譲する側のIAMロールで許可したアクションが実行可能になっている事が確認できます。
1 2 |
$ aws s3 ls s3://test-s3-bucket-for-sts --profile sts-session 2020-08-04 04:37:19 0 test.txt |
また、sts get-caller-identityの実行結果からも、委譲元アカウントのIAMロールのassumed-roleを使用してCLIを実行できているのが確認できます。
1 2 3 4 5 6 |
$ aws sts get-caller-identity --profile sts-session { "UserId": "{USER_ID}:sts_test_session", "Account": "xxxxxxxxxxxx", "Arn": "arn:aws:sts::xxxxxxxxxxxx:assumed-role/TestStsProviderRole/sts_test_session" } |
この方法を用いるメリット
- 取得したクレデンシャル情報を外部ツールのAWS連携などにも利用できる
- 一時認証情報取得/使用する流れを理解/イメージし易い
sts assume-roleコマンド実行時のレスポンスで取得するクレデンシャル情報を、AWS連携を行う各種外部ツールなどにも使用する事ができます。
有効期限付きという性質上、一時的な用途以外での使用はできませんが、外部ツールからAWSリソースへの疎通確認時など何かと便利です。
一時認証情報を委譲される流れを一つずつ愚直に行っていく為、全体の流れを非常に理解し易いです。
別の方法を取る場合でも内部的には同じ事を行っている為、最初に全体の流れを理解しておくと動きがイメージし易くなると思います。
この方法を用いるデメリット
- 有効期限を過ぎる度に、一時認証情報を再取得して登録し直す必要がある
- CLI用の設定ファイルに記載されたprofileの管理が難しい
- 取得したクレデンシャルを毎回ファイルに追記するのが面倒
取得したクレデンシャル本体を登録する形をとっている為、一時認証情報に使用可能な有効期限が存在する関係上、有効期限が切れたら再度一時認証情報を取得し直してクレデンシャルを登録し直す必要があります。
委譲する側のIAMロールで設定する有効期限の最大時間のデフォルトは一時間で設定されており、一時間を超えて作業する場合などに不便に感じるケースが発生してきます。
取得したクレデンシャルをCLI用の設定ファイルに追記して使用する方法を取った場合に主に感じる課題で、不要なprofileが溜まり続けてしまったり、必要なprofileを削除してしまい、再度使用したくなった場合にまた委譲元アカウントから情報を教えてもらう必要が発生してしまう問題です。
取得したクレデンシャルを環境変数に登録して使用する方法を取った場合でも、不要なprofileが溜まる事はないものの、必要なprofileを再度使用したくなった場合の問題は発生します。
たかが登録するだけ、されど登録するだけで、取得時に表示されたクレデンシャルの内容をコピーした後で、CLI用の設定ファイルを都度開いて貼り付けたりといった追記作業は面倒です。
面倒な作業は、コマンド一発でぱぱっと終わらせられるようにしたいです。
長々書いてみましたが、この方法の冒頭にも書いた通りで、たまに一時認証情報を貰って作業するぐらいであれば課題間を感じる事もほとんどないと思います。
実際、自分がCLIからSTSの一時認証情報を使って作業する時も何も考えずにこの方法を選択していましたし、一時認証情報を貰って作業する機会が頻繁に発生するようになってきた頃に、少しずつ課題間を感じるようになってきた感じでした。
2. 委譲元のIAMロール ARNをAWSのconfigファイルに登録するだけで使用可能にする
課題間を感じるようになってきた後で、世の中一般的にはIAM ロールで委譲された一時認証情報をどうやって管理するのが一般的なんだろう?と調べてみた結果で、AWSの公式ドキュメントにも記載されている方法です。
- AWSのconfigファイルのrole_arnに委譲元のIAMロール ARNを、source_profileに委譲される側のアカウントのprofile名を登録
- 登録したprofileを使用して、委譲された権限でアクセス可能な各種リソース(今回はs3)のクライアントやリソースを使用
~/.aws/configを編集して、role_arnに委譲元のIAMロールとして用意したTestStsProviderRoleのARNを、source_profileに委譲される側のアカウントのprofileとして登録済のtest-sts-provided-userを指定したprofileを追記します。
今回は、sts-sessionというprofile名で登録します。
mfa_serialの指定は、多要素認証必須時のみです。
1 2 3 4 5 6 |
[profile sts-session] role_arn = arn:aws:iam::xxxxxxxxxxxx:role/TestStsProviderRole source_profile = test-sts-provided-user mfa_serial = arn:aws:iam::xxxxxxxxxxxx:mfa/TestStsProvidedUser region = ap-northeast-1 output = json |
委譲元IAM ロールのARNを登録するだけでも、一時認証情報が使用可能になっている事が確認できます。
1 2 3 4 5 6 7 |
$ aws sts get-caller-identity --profile sts-session Enter MFA code for arn:aws:iam::xxxxxxxxxxxx:mfa/TestStsProvidedUser: { "UserId": "{USER_ID}:botocore-session-{SESSION_ID}", "Account": "xxxxxxxxxxxx", "Arn": "arn:aws:sts::xxxxxxxxxxxx:assumed-role/TestStsProviderRole/botocore-session-{SESSION_ID}" } |
セッション名が、botocore-session-xxxになっているのも確認できます。
sts assume-roleを明示的に叩いていた場合の、role-session-nameの部分です。
この方法を用いるメリット
- 有効期限が自動でリフレッシュされる為、一時認証情報の再登録が不要
この方法を取る場合の一番のメリットがこれで、有効期限が切れた状態で一時認証情報を使用しようとしても、自動で再取得してくれるので設定ファイルへの再登録などの面倒な作業が不要で、有効期限を意識せずに使用することができるようになります。
sts get-caller-identityの実行結果を見る限り、一度取得した一時認証情報の有効期限が残っている間は同一のセッションIDを使い回して使用し、有効期限が切れた時だけ裏側でsts assume-roleを実行して再取得する内部挙動になっているようです。
この方法を用いるデメリット
- CLI用の設定ファイルに記載されたprofileの管理が難しい
- 委譲元IAM ロールのARNを毎回ファイルに追記するのが面倒
クレデンシャル情報を明示的に取得/登録する方法と同じく、委譲元IAM ロールのARNを登録するprofileの管理は悩みどころとして残ります。
こちらもクレデンシャル情報を明示的に取得/登録する方法と同じくで、configファイルへの登録だけで済むようになったのでcredentialsファイルへの登録が不要になった分若干楽になったかなーぐらいでしょうか。
一番面倒だった一時認証情報の有効期限問題が解消されたので、大分快適に一時認証情報を使用することができるようになりました。
ベースの使い方はこれで十分なので、後はデメリットに挙げた2点を解消する方法をオプション的に作るぐらいで今回解決したかった課題は解決できそうです。
3. 委譲元IAM ロールのARNをコマンド一発で登録し、一時認証情報を管理できる仕組みを作成する
上の方法で残った課題二つを解決する仕組みとして、manage-sts-authorized-infoというツールを作ってみました。
何を提供するツールか?
このツールは、以下二つの価値を提供します。
- 委譲元IAM ロールのARNなど、一時認証情報を使用する為の設定をconfigファイルに追記する手間の削減
- 一時認証情報の管理を可能に
ログインシェルの設定ファイルにconfigファイルに追記する処理を行う関数を登録することで、毎回ファイルを開いて追記を行わなくてもコマンドから関数を呼び出して対話式のプロンプトで必要な情報を登録するだけで自動的にconfigファイルに受け取った情報を登録できるようになります。
委譲元IAM ロールのARNなどの受け取った情報のAWS CLI用のconfigファイルへの変更履歴を自動で保存し、どんな情報がいつ何の用途で変更(追加/削除)されたのかを履歴からいつでも確認することができるようになります。
一時認証情報をconfigファイルに登録時に、任意のコメントを付けて保存できるようになっています。
どうやって使うか?
READMEにも記載してあるので詳細はご参照いただければと思いますが、基本的な使い方は最初にログインシェルに関数を登録(セットアップ)したら、後はコマンドを叩いて必要な情報を入れるだけです。
- ログインシェルに関数を登録
- register_sts_assumed_role関数を実行
GitHubのリポジトリからcloneした後で、プロジェクトルートからsetup.pyを実行します。
1 2 3 |
$ cd ${PROJECT_ROOT} $ python setup.py Setup successed. please run `source /Users/masakimisawa/.zshrc` command. |
ログインシェルの設定ファイルを再読み込みすると、register_sts_assumed_role関数が使用可能になります。
コマンドを叩いてプロンプトで表示される必要な情報を入力するだけです。
1 |
$ register_sts_assumed_role |
AWS CLI用のconfigファイルに入力した一時認証情報が登録されていて、同階層に作られるsts_assumed_role.logに変更履歴が書き込まれているのが確認できれば完了です。
今回は受け取った情報をAWS CLI用のconfigファイルに登録、一時認証情報の管理を行う為の方法を作ってみましたが、STSで委譲された一時認証情報は、登録した後の情報をどう使うか(cliコマンド実行時に毎回profileのオプションを付ける手間をどう減らすかなど)についても色々と考える点が多いので、ここら辺も自分に合った方法にうまくカスタマイズしておきたいですね。
と言う事で、今回は終わりです!