CLI

AWS CLI 2段階認証(MFA)制限のスイッチロールで環境切替え

AWSマルチアカウント環境で、2段階認証(MFA)制限をかけたロールに対してAWS CLIでスイッチします。

ついでにセッション名の固定というTipsもご紹介します。

(AWS Vaultというツールで安全にアクセスキーを保存しつつ同様のことができますこちらの記事をご参照ください)

スポンサーリンク

前提

いくつか事前準備や前提知識が必要になります。

2段階認証(MFA)制限付きのロール設定

2段階認証(MFA)制限付きのロール設定自体は、AWSマネジメントコンソールで行います。

設定手順や実行環境などの説明は、以下の記事をご参照ください。


今回は、この手順が完了しているものとして進めます。AWSアカウントIDは引き続き以下を使用します。

環境AWSアカウントID
踏み台(JUMP)111111111111
開発(DEV)222222222222
本番(PROD)333333333333

またスイッチ先のロール名は、管理者用として作成した AdminRoleFromJump を使用します。

AWS CLI 名前付きプロファイル

AWS CLIで –profile というオプションを使用します。

設定手順や説明は、以下の記事をご参照ください。

スイッチロールで環境切替え

それでは設定していきます。 といっても1コマンド打って1ファイル編集するだけです。

AWS CLIの設定

IAMユーザーのアクセスキー保存

まず踏み台環境(JUMP)に作成した、IAMユーザーの認証情報(アクセスキー)の設定をします。

$ aws configure --profile tester-01-jump
AWS Access Key ID [None]: xxxxxxxxxxx
AWS Secret Access Key [None]: yyyyyyyyyyyyy
Default region name [None]: ap-northeast-1
Default output format [None]:
$

AWS CLI設定ファイル スイッチロールの設定

次に、~/.aws/configへスイッチ先環境(開発、本番)のロールの設定を追加します。

aws configure set というサブコマンドでの設定も可能ですが、編集内容が多く、configファイルの場所を把握している場合は、viなどで直接編集したほうが楽です。

$ vi ~/.aws/config
...

## 踏み台環境(JUMP) のIAMユーザーは、aws configure で既に設定されています
[profile tester-01-jump]
region = ap-northeast-1

## 開発(DEV)の設定を追加します
[profile tester-01-dev]
region = ap-northeast-1
role_arn=arn:aws:iam::222222222222:role/AdminRoleFromJump
source_profile=tester-01-jump
mfa_serial=arn:aws:iam::111111111111:mfa/tester-01

## 本番(PROD)の設定を追加します
[profile tester-01-prod]
region = ap-northeast-1
role_arn=arn:aws:iam::333333333333:role/AdminRoleFromJump
source_profile=tester-01-jump
mfa_serial=arn:aws:iam::111111111111:mfa/tester-01

...

以下、設定項目の説明です。

role_arn

スイッチ先のロールARNを指定します。
arn:aws:iam::AWSアカウントID:role/ロール名

source_profile

スイッチ元のプロファイル名を指定します。
上記例では tester-01-jump で設定したプロファイルのIAMユーザーからスイッチします。

mfa_serial

QRコードを読み取ったMFAデバイスのARNを指定します。
arn:aws:iam::AWSアカウントID:mfa/IAMユーザー名

なおMFAデバイスのARNは、AWSマネジメントコンソールのIAMユーザーの認証情報画面から確認できます。

スイッチロール確認

以上で設定完了したので確認します。

コマンド実行時、MFAコードの入力を求められます。

$ aws s3 ls --profile tester-01-dev
Enter MFA code for arn:aws:iam::111111111111:mfa/tester-01:[6桁のコードを入力]
...
DEV環境のバケット一覧が出力されます
...

$
$ aws s3 ls --profile tester-01-prod
Enter MFA code for arn:aws:iam::111111111111:mfa/tester-01:[6桁のコードを入力]
...
PROD環境のバケット一覧が出力されます
...

$


なお踏み台アカウントのプロファイルを指定しても、踏み台のIAMユーザーには、実質MFA作成以外の操作を拒否するpolicyを設定しているのでエラーとなります。

$ aws s3 ls --profile tester-01-jump

An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
$

Tips

スイッチロール時(AssumeRole)の認証情報

コマンド実行時、MFAの入力は毎回求められるわけではありません。

~/.aws/cli/cache に認証情報が保存され、情報の有効期限(デフォルト1時間)内であれば6桁のコードを入力せずにコマンド実行できます。

## スイッチロール単位で作成され、同じファイルが更新されます
$ find  ~/.aws/cli/cache -type f
/Users/xxx/.aws/cli/cache/xxxxx.json
/Users/xxx/.aws/cli/cache/yyyyy.json
/Users/xxx/.aws/cli/cache/12345.json
/Users/xxx/.aws/cli/cache/56789.json
$
## 中身を確認してみます
$ cat /Users/xxx/.aws/cli/cache/56789.json | jq
{
  "Credentials": {
    "AccessKeyId": "aaa",
    "SecretAccessKey": "bbb",
    "SessionToken": "ccc==",
    "Expiration": "2021-07-12T22:47:36+00:00"
  },
  "AssumedRoleUser": {
    "AssumedRoleId": "xxx:botocore-session-1626126444",
    "Arn": "arn:aws:sts::222222222222:assumed-role/AdminRoleFromJump/botocore-session-1626126444"
  },
  "ResponseMetadata": {
    "RequestId": "xxx-yyy-zzz-111-222",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "x-amzn-requestid": "xxx-yyy-zzz-111-222",
      "content-type": "text/xml",
      "content-length": "1522",
      "date": "Mon, 12 Jul 2021 21:47:35 GMT"
    },
    "RetryAttempts": 0
  }
}
$

上記例では、 “Expiration”: “2021-07-12T22:47:36+00:00″、日本時間(JST)はその時刻から+9時間なので13日のAM 07:47が期限となります。
(が僕の環境では、それより早めに(15分ほど前)に期限切れとなってる気がしました。。

セッション名を固定して操作履歴を追跡する

~/.aws/config で role_session_name を指定できます。

[profile tester-01-prod]
region = ap-northeast-1
role_arn=arn:aws:iam::333333333333:role/AdminRoleFromJump
source_profile=tester-01-jump
mfa_serial=arn:aws:iam::111111111111:mfa/tester-01

## セッション名を追加します
role_session_name=tester-01

セッション名を特に指定しない場合は、自動的に生成されます。(AWS CLIでは botocore-session-ランダム数値 になる模様)



この role_session_name は任意ですが、IAMユーザー名と同じにすると誰かと重複することなく AWS CloudTrailでAWS CLIからのアクセス履歴を簡単に追えるようになります。

以下のように、CloudTrailのイベント履歴画面でユーザー名を条件に、素早く正確に検索できるようになります。

これがbotocore-session-ランダム数値 のままだと問題がおきたときに、誰が何をしたかがサクッと追えなくなってしまいます。

またAWSマネジメントコンソールでのスイッチロールのセッション名は自動でIAMユーザー名が設定されているようで、その点からもセッション名を統一したほうが追跡が楽になります。

セッション名にIAMユーザー名を適用することを強制する

role_session_name を IAMユーザー名でお願いね! とチームでルールづくりしても設定ミスや詐称の不安は拭えないので、システムでチェックします。

こちらの記事の開発環境(DEV)・本番環境(PROD)用 YAMLファイル作成 のロールStringLike: sts:RoleSessionName: ${aws:username} の設定を追加します。

# 管理者ロール
Resources: 
  AdminRoleFromJump:
    Type: AWS::IAM::Role
    Properties:
      RoleName: "AdminRoleFromJump"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !Sub "arn:aws:iam::${JumpAccountID}:user/tester-01"
            Action:
              - 'sts:AssumeRole'
            Condition:
              Bool:
                aws:MultiFactorAuthPresent: true

              ## この StringLike の条件を追加します
              StringLike:
                sts:RoleSessionName: ${aws:username}
...


この条件を設定した上で、IAMユーザー名と一致しないセッション名でスイッチロールすると以下のようにエラーで弾いてくれます。

$ aws s3 ls --profile tester-01-prod
Enter MFA code for arn:aws:iam::111111111111:mfa/tester-01:[6桁のコードを入力]

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::111111111111:user/tester-01 is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::333333333333:role/AdminRoleFromJump
$



今回は以上です〜ノシ

参考

アリガト━━━ヾ(´∀`)ノ━━━━♪

AWS CLI での IAM ロールの使用 多要素認証を使用する
サポートされる config ファイル設定
[アップデート] IAMロールセッション名にユーザー名を強制できる条件 sts:RoleSessionName が使えるようになりました