はじめに
この記事は現在も多くの開発現場で使われている
MFA付き AssumeRole(クロスアカウント)の仕組みを、
ログや図解で腹落ちさせるためのまとめです。
自分は所属部署に異動してきて初めて本格的にクラウド(AWS)を触ることになり、
まず今回の内容がわからないという🐤の詰まり方をしました。
自分で調べたことをまとめる目的で記事を書きます。
※IAM Identity Center(SSO) ではないです
この記事の内容
-
~/.aws/configと~/.aws/credentialsの役割の違い -
source_profile / role_arn / mfa_serialが何を意味するか -
aws sts get-caller-identity --profile testの内部の流れ - 「今自分がどのアカウントの誰としてAPIを叩いているか」を確認する
今回説明する構成例
- AWS Organizations配下で複数アカウントをそれぞれ以下のような役割で運用している
- 親(management account):IAMユーザー(長期キー)で認証(ここが起点)
- 子(member account):STSでロールを引き受け、短期キーで操作(実作業の対象)
- MFAがロールを引き受ける(以下AssumeRole)タイミングで要求される
0.AWS CLIの認証はプロファイルで決まる
AWS CLI は profileという単位で「どの認証情報・どの設定で AWS を叩くか」を切り替えています。
今回の場合だとプロファイルの情報は主に次の2ファイルに分かれて保存されます。
-
~/.aws/config設定ファイル(どのロールに切り替えるか、リージョン、出力形式など) -
~/.aws/credentials認証情報ファイル(アクセスキーなど“秘密情報”)
アクセスキーは自動でファイルに保存されない
コンソール上でIAM→認証情報からユーザーのアクセスキーを発行した後、
一般的には以下で自分のPCに設定します。
以下のコマンドを叩くと必要な情報を入力することになるので、
その情報を元にファイルを作成してくれます。
※難しかったら手動でも作れます
aws configure --profile default
今回の構成は、
AWS CLIが source_profile(親)を起点にして AssumeRole し、子のロールを引き受ける
というものです。
~/.aws/config の例:
[default]
region = us-west-2
[profile test]
source_profile = default
role_arn = arn:aws:iam::子アカウントID:role/Developer
mfa_serial = arn:aws:iam::親アカウントID:mfa/MFAのデバイス
region = us-west-2 ←普段使うリージョンを設定
- source_profile:
AssumeRoleの起点となるプロファイルです。
testを使うとき、CLIは内部的にまずdefaultの資格情報を使ってSTSへアクセスします
※defaultのアクセスキー等の長期資格情報は通常~/.aws/credentialsの[default]に入っています(会社規定で配布されている/自身で設定している等)
~/.aws/credentialsの例:
[default]
aws_access_key_id = XXXXXX
aws_secret_access_key = YYYYYYYY
-
role_arn:
引き受けたい ロールのARNです。例だとarn:aws:iam::<子>:role/Developerなので、
子アカウントのDeveloperロールを引き受けます -
mfa_serial:
MFAデバイスのARNです。例だとarn:aws:iam::親:mfa/...の形なので、
親アカウント側のIAMユーザーに紐づいたMFAです -
region:
AWSサービスのリージョンです。普段触るリージョンを入れておくと事故が減ります
1. 最小の確認コマンド:今あなたは誰?どのアカウント?
まずは「親→子に切り替わっている」ことを ログで確認します。
aws --versionが動かない場合はAWS CLI をインストールしましょう。
aws --version
aws sts get-caller-identity --profile default
aws sts get-caller-identity --profile test
Enter MFA code for arn:aws:iam::親アカウントID:mfa/MFAのデバイス名:
これが出た場合は、AssumeRoleの要求にMFAが必須の設定になっています。
登録したMFAデバイスで表示される6桁コードを入力しましょう。
出力例
--profile default(親アカウントのIAMユーザー)
{
"UserId": "AIDA....",
"Account": "親アカウントID",
"Arn": "arn:aws:iam::親:user/IAMユーザー名"
}
-
arn:aws:iam::...:user/...なので IAMユーザーです -
Accountが 親なので、親アカウントの資格情報で認証できています
--profile test(MFA入力→子アカウントのロール)
{
"UserId": "AROA....:botocore-session-....",
"Account": "子アカウントID",
"Arn": "arn:aws:sts::子アカウントID:assumed-role/Developer/botocore-session-...."
}
-
arn:aws:sts::子:assumed-role/Developer/...
→ 子アカウントのDeveloperロール(開発者権限)を引き受けた状態 -
Accountが 子アカウントになっている
→ 以後このプロファイルで叩くAWS APIは「子アカウントのロール権限」で実行される
ここでどのアカウントを主体にしてAPIに署名しているかが切り替わっているわけですね。
短期キーはどこに“入る”?(親?子?)
--profile testの結果が
「Account: 子」 かつ 「arn:aws:sts::子:assumed-role/...」 になっているので、
短期キー(クレデンシャル)は“子アカウントのロール”として発行されています。
CLIの操作は、子アカウントの権限で実行されます。
2. 内部で起きていること
aws sts get-caller-identity --profile test
上記コマンド(現在のSTS情報を出す)の内部の流れを確認しましょう。
なんでSTS情報出すだけで流れがわかるの?
--profile testが子アカウントのロールとして実行するプロファイルなので、
CLIはコマンド実行のタイミングでsts:AssumeRole を実行して短期キーを取得し、
その短期キーで本来のAPI(ここでは GetCallerIdentity)を呼びます。
2.1 シーケンス
個人的にMFAが子アカウントに入った後じゃなくて、AssumeRole要求に添付されているのがわかったのが面白いと感じました。
2.2 AssumeRoleに渡している主要パラメータ(イメージ)
-
RoleArn:arn:aws:iam::<子>:role/Developer -
RoleSessionName:botocore-session-...(CLI/SDKが自動生成しがち) -
SerialNumber:arn:aws:iam::<親>:mfa/MFAの端末 -
TokenCode:MFAで入力した6桁コード
3. よくあるエラーと切り分け
3.1 AssumeRoleできない(AccessDenied)
- 親側IAMユーザーに
sts:AssumeRoleの権限がない - 子側ロールの信頼ポリシー(Trust Policy)が親側主体を許可していない
AssumeRole対象ロールが本当に合っているかをrole_arnで確認しましょう。
3.2 MFAを入れても弾かれる
-
mfa_serialが違う - ロールの信頼ポリシーにMFA必須条件があるのに
TokenCodeが渡っていない - 端末の時刻ズレでワンタイムが通らない
3.3 “どのアカウントにいるか分からない”
とりあえずこれ叩けば解決!
aws sts get-caller-identity --profile test
まとめ
自分の環境ありきの話もありましたが、調べたところ多く使われている手法のようなので
仕組みを理解する!という意味で読んでいただいていれば幸いです。
🐤的には子アカウント側は短期キーで、
起点の親アカウントはIAMユーザーの長期キーを切り分けるのが難しかったです。