以下のような前提で考えます
- 対象アカウントには、Organization のSCP でMFA必須のポリシーが設定されいている
- 開発者は認証アカウントのアクセスキーを利用して、対象アカウントにAssumeRole でアクセスする
- AssumeRole を呼び出す際は必ずMFA が必須とする
図示すると以下のような場合です。
MFA 必須SCPとは具体的には以下のようなポリシーです。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllDenyWithoutMFA", "Effect": "Deny", "Action": [ "*" ], "Resource": "*", "Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" } } } ] }
対象アカウントのIAM ロールの信頼ポリシーには、MFA 必須の設定がされています。
以下、信頼ポリシー
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<auth_account_id>:user/<iam_username>" }, "Action": "sts:AssumeRole", "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } } } ]
また、IAM ロールのアクセス権限には AdministratorAccess
ポリシーを設定していて、AssumeRole したら何でもできるといった前提とします。
以上がシナリオの前提です。
AssumeRole にMFA トークンを指定する場合
上記のシチュエーションでは、以下のようにAssumeRole を呼び出すことができ一時的認証情報を得ることができます。
aws configure set aws_access_key_id <auth_account_access_key>
aws configure set aws_secret_access_key <auth_account_secret>
aws sts assume-role --role-arn <target_account_role_arn> \
--serial-number <your_mfa_device_arn> \
--role-session-name <any_name> \
--token-code <your_token_code> \
一時的認証情報の例
{
"Credentials": {
"AccessKeyId": "xxxx",
"SecretAccessKey": "xxxx",
"SessionToken": "xxxxxx",
"Expiration": "2020-04-04T02:54:37+00:00"
},
・・・略・・・
}
では、今回の前提で上記一時的認証情報を使ってAWS API を実行するとどうなるでしょか?
例えば以下のようなコマンドを実行します。(一時的認証情報を dev プロファイルに設定しているとします。)
$ aws s3 ls --profile dev
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
今回の前提ではIAM ロールのアクセス権限に AdministratorAccess
ポリシーを設定しているので呼び出しは成功しても良いはずですが、Access Denied になってしまいました。
GetSessionToken + AssumeRole をする場合
以下のようなスクリプトを組みます。これはまずGetSessionToken を実行してMFA 認証済みの一時的認証情報を入手してから、その認証情報を利用してAssumeRole をするという流れです。
ファイル名: assume-role.sh
以下のように実行します。
$ aws configure set aws_access_key_id <auth_account_access_key>
$ aws configure set aws_secret_access_key <auth_account_secret>
$ assume-role.sh <your_token_code>
$ aws s3 ls --profile dev
… 実行がうまくいく …
この場合は、今回の前提においても成功します。
2つの挙動の違い
以下のドキュメントに記載があります。
GetSessionToken
によって返される一時的な認証情報には MFA 情報が含まれているので、認証情報によって実行される各 API オペレーションで MFA を確認できます。https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html
AssumeRole
によって返される一時的な認証情報のコンテキストには MFA 情報が含まれていないので、MFA に対する個別の API オペレーションを確認できません。
AssumeRole にMFA トークンを指定して呼び出すだけの場合、取得できる一時的認証情報には、MFA 情報が含まれません。CloudTrail のログを見るとリクエストのuserIdentity の情報としては以下のようになっています。
"userIdentity": {
"type": "AssumedRole",
"principalId": "xxx:xxx",
"arn": "arn:aws:sts::xxxxx:assumed-role/xxxx/xxxxx",
"accountId": "xxxxx",
"accessKeyId": "xxxxxxx",
"sessionContext": {
"attributes": {
"mfaAuthenticated": "false",
"creationDate": "2020-04-04T01:58:27Z"
},
"sessionIssuer": {
"type": "Role",
"principalId": "xxxxxx",
"arn": "arn:aws:iam::xxxxxx:role/xxxxxx",
"accountId": "xxxxxx",
"userName": "xxxxxxx"
}
}
}
“mfaAuthenticated” : “false” となっています。
次に、GetSessionToken -> AssumeRole の場合の、CloudTrail のログを見てみます。同じように”userIdentity” の内容です。
"userIdentity": {
"type": "AssumedRole",
"principalId": "xxxxx",
"arn": "arn:aws:sts::xxxxx:assumed-role/xxxx/xxxxx",
"accountId": "xxxxx",
"accessKeyId": "xxxxxx",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "xxxxx",
"arn": "arn:aws:iam::xxxxxxx:role/xxxxx",
"accountId": "xxxxxxx",
"userName": "xxxxxx"
},
"webIdFederationData": {},
"attributes": {
"mfaAuthenticated": "true",
"creationDate": "2020-04-04T00:53:53Z"
}
}
この場合、”mfaAuthenticated” : “true” となっており、MFA 認証情報が含まれていることがわかります。
今回の前提では、SCP にて”mfaAuthenticated” : “true” 以外のリクエストはすべてDeny する設定になっているため、GetSessionToke + AssumeRole の場合だけ、正常に実行できたということになります。
以上です。