aws-mfa で MFA 強制した IAM ユーザーの AWS アクセスキーを簡単に更新する

# 背景

IAMユーザーにMFA強制して、アクセスキーを発行すると、物事が煩雑になります。AWSによると以下のようにやる必要があります。

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

`aws sts get-session-token` が返してきたJSONを `jq` でバラして環境変数にセットするなど、ワンライナーで頑張りようはありますが、複数AWSアカウントにまたがると、かなり厳しいものがあります。

`aws-mfa` というPython製CLIツールを使うと、取り回しがかなり簡単になりますので紹介します。

# つかうもの

* https://github.com/broamski/aws-mfa

# インストール手順

```bash
$ pip3 install aws-mfa
```

# IAM の設定

* IAMユーザーを作成します
* MFA強制します
* アクセスキーを発行します

# awscli の設定

さきほど発行したアクセスキーで、プロファイルを作ります。 `aws-mfa` の規約に従い、プロファイル名の末尾に `-long-term` というのを付けて作ります。アクセスキーとシークレットアクセスキーを入れて作ります。

```bash
$ aws configure --profile hoge-long-term
AWS Access Key ID [None]: AKIAXXXXXXXXXXXXXXXXX
AWS Secret Access Key [None]: XXXXXXXXXXXXXXXXXXXX
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

もうひとつ、 `-long-term` を **外した名前のプロファイル** も作っておきます。こちらはアクセスキーとシークレットアクセスキーは空欄で作ります。

```bash
$ aws configure --profile hoge
AWS Access Key ID [None]: 
AWS Secret Access Key [None]: 
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

実行後、こうなってるはず。

```ini
$ cat ~/.aws/config
[profile hoge-long-term]
region = ap-northeast-1
output = json
[profile hoge]
region = ap-northeast-1
output = json
$ cat ~/.aws/credentials
[hoge-long-term]
aws_access_key_id = AKIAXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXX
```

もうひと手間いれて、後で楽できるようにします。IAMユーザー画面から、MFAデバイスのARNをコピってきて、 `~/.aws/credentials` のプロファイル `hoge-long-term` に  `aws_mfa_device` というのを追加し、MFAデバイスのARNをセットします。以下のように。

```ini
$ cat ~/.aws/credentials
[hoge-long-term]
aws_access_key_id = AKIAXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXX
aws_mfa_device = arn:aws:iam::123456789012:mfa/user
```

# aws-mfa を実行

プロファイル名は `-long-term` を **外したもの** を指定します（わかりにくい）。実行すると `Enter AWS MFA code for device` で止まるので、MFAデバイスに表示された数字を入力します。

```bash
$ aws-mfa --profile hoge
INFO - Validating credentials for profile: hoge
INFO - Short term credentials section hoge is missing, obtaining new credentials.
Enter AWS MFA code for device [arn:aws:iam::123456789012:mfa/user] (renewing for 43200 seconds):123456
INFO - Fetching Credentials - Profile: oct-dev, Duration: 43200
INFO - Success! Your credentials will expire in 43200 seconds at: 2019-10-01 17:55:38+00:00
```

MFAの数字を入れ、成功すれば、有効期限やらが表示され、裏では `~/.aws/credentials` に有効期限つきのシークレットキーなどなどが設定されています。

```ini
$ cat ~/.aws/credentials
[hoge-long-term]
aws_access_key_id = AKIAXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXX

[hoge]
assumed_role = False
aws_access_key_id = ASIAXXXXXXXXXXXXXXXXX
aws_secret_access_key = YYYYYYYYYYYYYYYYYYYYYYY
aws_session_token = WWWWWWWWWWWWWWWWWWWWWWW
aws_security_token = ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
expiration = 2019-10-01 17:55:38
```

# awscli で操作

awscliなどで何かやるとき、プロファイル名は `-long-term` を **外したもの** を指定して実行します。以下のように。

```bash
$ aws --profile hoge s3 ls
```

# アクセスキーが有効期限切れしたら

初回とまったく同じように `aws-mfa` を実行すれば、 `~/.aws/credentials` を更新してくれます。

```bash
$ aws-mfa --profile hoge
```

# もうちょい有効期限を長め/短めにしたい

`duration` オプションに秒数指定で、任意の期限に設定できます。ただし指定できるのは15分から36時間の範囲です。

```bash
$ aws-mfa --duration 秒数 --profile hoge
```

# 〆

IAM と awscli の仕組みでは、

* MFAでガードされた無期限のAWSアクセスキーを使って、
    * MFAでガードされてるので、他人は使えない
* MFAでガードされていない期限付きのAWSアクセスキーを発行する
    * 期限付きなので、期限切れたら使えない

ことで、従来の

* MFAでガードされていない無期限のAWSアクセスキーを発行する

にくらべて、アクセスキー漏洩した際のダメージ期間を限定することができます。できますが、期限付きAWSアクセスキー発行の手順が面倒臭すぎて、二の足を踏んでいました。

`aws-mfa`で簡単にできますので、使っていきましょう。