AWS CLIでの多要素認証を簡単にできるWindowsバッチを作ってみた

## はじめに
弊社ではAWSアカウントを利用する際にまず多要素認証（MFA）が設定されることが必須条件であり、MFAなしでは、ごく一部のAPIを除きほとんどの操作（コンソール画面とCLI両方を含む）を実行できないようにするためのIAMポリシーが各IAMユーザーにアタッチされます。となると、操作を行う前にまずMFA認証を通す必要があり、コンソール画面でのMFA認証はそこまで不便ではないが、CLIでの手順が少々手間が掛かります。ざっくり言うと：

1. `STS:GetSessionToken` APIで一時認証情報を取得
2. 取得した一時認証情報を環境変数に入れる（Linuxの場合は `export` 、Windowsの場合は `set`）

せいぜい1分程度の手順ではありますが、こんなルーチンワークを少しでも減らしたいのがエンジニアという生き物です。なので今回この手順を5秒に短縮できるツールを作ってみました。（開発環境がWindowsであるためとりあえずバッチファイルで）

## Windowsバッチの中身（ソースコード）
`--duration-seconds` と `--serial-number` を適宜書き換えるように。

```batch:sample.bat
@echo off

set /p useCurrentToken="Refresh token? (y/n): "

if %useCurrentToken%==y (
    setlocal ENABLEDELAYEDEXPANSION
    set /p mfa="Please enter MFA One-Time-Password: "
    aws sts get-session-token --duration-seconds 86400 --serial-number arn:aws:iam::xxxxxxxx:mfa/xxxxxxxx --token-code !mfa! --output json > temp.json
    endlocal
)

for /f "tokens=1,2 delims=:{} " %%A in (temp.json) do (
    If "%%~A"=="AccessKeyId" set accessKey=%%~B
    If "%%~A"=="SecretAccessKey" set secretAccessKey=%%~B
    If "%%~A"=="SessionToken" set sessionToken=%%~B
)

set accessKey=%accessKey:,=%
set accessKey=%accessKey:"=%
set secretAccessKey=%secretAccessKey:,=%
set secretAccessKey=%secretAccessKey:"=%
set sessionToken=%sessionToken:,=%
set sessionToken=%sessionToken:"=%

set AWS_ACCESS_KEY_ID=%accessKey%
set AWS_SECRET_ACCESS_KEY=%secretAccessKey%
set AWS_SESSION_TOKEN=%sessionToken%

echo Token has been set into environment variables.
```

## 挙動
### バッチ実行前の準備
まず通常のアクセスキーとシークレットキーをAWSコンソールから発行して端末にセットします。そうしないとバッチの中にある `aws sts get-session-token` コマンド自体実行できなくなります。

### バッチ実行前のCLI挙動を確認してみよう
試しに `aws s3 ls` コマンドでS3のバケット一覧を出してみたところ、予想通り `Access Denied` になっています。MFA認証はまだ通していないからです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779499/929f4623-029b-98b4-8689-cf96145d2f77.png)

### バッチを実行する
では早速バッチを叩きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779499/7db69d7a-82e4-4277-5e29-0fdf2f61a4a3.png)
まず最初の `Refresh token?` では、一時認証情報を新規に発行したい場合は `y` を入力し、さらにMFAコードが求められ、ワンタイムパスワードをここに入力し、Enterを押します。

処理が正常終了したら、バッチファイルと同じ階層に `temp.json` ファイルが生成され、その中にAWS STSが発行してくれた一時認証情報が保存され、かつ、この一時認証情報が上記の処理によって自動的に環境変数にセットされます。（環境変数が正しくセットされているかは、Windowsの `set` コマンドで確認できます）

逆に `Refresh token?` で、一時認証情報を新規発行せずに既存の `temp.json` を使いたい場合は `n` を入力し、そうするとワンタイムパスワードの入力が不要となり、既存の一時認証情報で環境変数のセットを行えます。なぜこのような機構を用意したかというと、例えばVSCodeなどのターミナルでバッチを実行した後に一度VSCodeを閉じたら、セットされた環境変数の設定も消えてしまいます。ただ `temp.json` に格納されている一時認証情報自体はまだ有効期限を過ぎておらず、再度環境変数にセットすると引き続き利用できるので、わざわざもう1回ワンタイムパスワードを入力せずに、直接環境変数にセットする処理を実行するのはこちらの分岐になります。

### バッチ実行後のCLI挙動を確認してみよう
同じく `aws s3 ls` コマンドを実行してみます。今度は無事S3のバケット一覧を出すことができました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779499/acda912b-5e54-6a98-f3ba-746998852043.png)

## 最後に
シェルスクリプトよりバッチスクリプトのほうが不慣れなため、作るのそこそこ大変でした:confounded:

しかしこれでMFAを前提にしたCLI利用の心理的ハードルが以前よりだいぶ下がったので収穫がかなり大きいと思います！

## 参考記事
IAMユーザーの一時認証情報の詳細について下記記事がかなり分かりやすいです。
[AWS IAMユーザーに対して一時的な認証情報をリクエストする(STS:GetSessionToken)](https://dev.classmethod.jp/articles/temp-credentials-request-against-iam-user/)

本ツールと同じ趣旨のものがほかにも存在しますので、適宜参考にしてみてください。
[AWS CLIからのMFA(多要素認証)を楽にするツール(aws-mfa)を使ってみた](https://qiita.com/ogady/items/c17ffe8f7c8e15b15f77)