AWSでのMFAをちょっと便利に扱いたい

## はじめに

この記事は [フューチャーAdvent Calendar 2020](https://qiita.com/advent-calendar/2020/future) の19日目の記事です。

AWSのIAMユーザのセキュリティ上、IAMユーザにMFA(他要素認証)を導入するケースがあります。MFAを有効にしているIAMユーザでGUI経由でログインする場合は、ログイン時に認証情報が求められて、MFAデバイスが出力するトークンを入力することでログインできます。一方AWS CLIを用いてリソースにアクセス場合はコマンド発行時に認証情報は求められません。つまりAWSのサービスにアクセスすることができません。

上記の解決策の一つとして、AWS CLIの場合は認証情報が求められないようにする設定する方法があります。

- [AWS CLI を使用する IAM ユーザーに MFA による認証を適用するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/mfa-iam-user-aws-cli/)

上記の場合はIAMポリシーで `MultiFactorAuthPresent` のキーを用いて、AWS CLIの場合は認証情報が求められないようにしています。しかしながらセキュリティを考慮すると、AWS CLIの場合にも認証情報が必須にしたいという場合が多く、上記のような解決策が取れないケースもあります。

そこでMFAの認証情報を用いてAWS CLI経由でAWSのリソースにアクセスする別の方法として以下のような方法があります。

- [MFA トークンを使用して、AWS CLI 経由で AWS リソースへのアクセスを認証する方法を教えてください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/authenticate-mfa-cli/)

つまり以下のような `get-session-token` コマンドを発行することで一時的な認証情報を発行する、ということです。

```
$ aws sts get-session-token --serial-number arn-of-the-mfa-device --token-code code-from-token --profile my-login-profile
```

コマンドが成功すると、以下のようなJSONがレスポンスとして返ってきます。

```
{
    "Credentials": {
        "SecretAccessKey": "secret-access-key",
        "SessionToken": "temporary-session-token",
        "Expiration": "expiration-date-time",
        "AccessKeyId": "access-key-id"
    }
}
```

返ってきたレスポンス `SecretAccessKey`, `SessionToken` を `~/.aws/credentials` に記述することでAWS CLI経由でAWSのリソースにアクセスできるようになります。

## 問題

上記のJSONの値を `~/.aws/credentials` に記述することでリソースにアクセスできるようになったものの、`get-session-token` コマンドを発行した認証情報は最大で129600秒(=36時間)です。一時的な認証情報という意味では妥当ですが、AWS CLIは頻繁に利用するため、ほぼ毎日 `get-session-token` コマンドで出力したJSONの値を `~/.aws/credentials` に貼り付ける作業が発生するようになりました。これはちょっと面倒だな...と思っていました。

本記事では、上記のJSONコピペの問題を解決する方法を紹介します。

いうてもコマンドを実行して出力されたJSONをファイルに貼り付けるくらいの作業です。退屈なことは~~python~~Goにやらせよう、とはよくいったものですので、薄いCLIツールを作りました。ほぼ毎日使っていますが、特に問題は発生していません。

<a href="https://github.com/d-tsuji/awsmfa"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/d-tsuji/awsmfa.png" width="460px"></a>

## awsmfa

### インストール

- From source code

```
$ go get github.com/d-tsuji/awsmfa/cmd/awsmfa
```

- From binary

https://github.com/d-tsuji/awsmfa/releases を参照してバイナリを取得ください。

### 使い方

`sts get-session-token` と同じオプションを取れるようになっています。

```
$ awsmfa --serial-number arn:aws:iam::123456789012:mfa/my-login-role --profile my-login-profile code-from-token
```

認証情報のプロファイル名はデフォルトで `mfa` としています。別のプロファイル名で保存したい場合はオプションに `--mfa-profile-name` を指定します。上記の `awsfma ...` コマンドを実行すると以下のように `mfa` のプロファイルが追加されます。2回目以降は `~/.aws/credentials` の `mfa` プロファイルの値を更新するようになっています。

- `~/.aws/config`

```
[default]
region = us-east-1
output = json

[profile mfa]
```

- `~/.aws/credentials`

```
[default]
aws_access_key_id     = ABCDEFGHIJKLMNOPQRST
aws_secret_access_key = ChEXAMPLEraRNW5iy8XgDyR4QNRT44kKRPmKEGQT

[mfa]
aws_access_key_id     = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
aws_session_token     = AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE
```

### 雑記

- ファイル形式

開発雑記ですが、`~/.aws/config` や `~/.aws/credentials` のファイル形式は `INI` ファイル形式である、ということです。最初 `TOML` 形式と誤解していたためファイルをパースできず困っていました。`aws-sdk-go` のソースを見ていたところ、INIファイルのパーサがあって、INIファイル形式であることに気づきました。

https://github.com/aws/aws-sdk-go/tree/master/internal/ini

- ツール

`d-tsuji/awsmfa` 以外にも [`99designs/aws-vault`](https://github.com/99designs/aws-vault) をなどのツールも存在します。

## まとめ

AWSでのMFAを使用する際にちょっとだけ便利に扱うツールを紹介しました。こうしたちょっとだけ便利にする薄いツールは今後もたくさん作っていきたいと思います。