[AWS] MFAを登録するまで他のリソースに触れないようにするポリシーを作成する

## この記事について

AWSはセキュリティの観点から、MFA (Multi-Factor Authentication)を設定することを推奨しています。2024年の半ばからルートユーザーはMFAが義務化されますが、個人的にはIAMユーザーについても出来るだけ設定するようにしたいです。この記事では、IAMユーザーに、MFAの登録を義務付ける方法を書きます。

## やりたいこと

MFAを登録するまでは、全リソースを触れなくしたいです。これには下記の2つの方法があります。
- ポリシーだけで設定する
[こちら](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_iam_mfa-selfmanage.html)に公式のポリシー設定のサンプルがあります
- IAM Identity Centerでサインイン時に強制する
[こちら](https://docs.aws.amazon.com/ja_jp/singlesignon/latest/userguide/how-to-configure-mfa-device-enforcement.html)に公式の手順が書いてあります

IAM Identity Centerは一元管理出来るので、ユーザーが大量にいる場合はこちらが良いと思うのですが、筆者の用途だとそこまでは必要なかったので、ポリシーだけで実現する方法を採用しました。

## MFAを義務付けるポリシーの設定

デフォルトだと、IAMユーザーは自身のMFAデバイスを設定する権限すらありません。そのため、以下のようなポリシーが必要です。

- 自身のアカウント情報を見る権限
- 自身のアカウントにMFAデバイスを設定する権限
- MFAをするまで他のリソースには触れなくする権限

概ね先ほどの[公式のポリシー設定のサンプル](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_iam_mfa-selfmanage.html)と同じ内容で良いですが、一部変える必要があります。サンプルの説明と修正した部分のコメントを付けたもの下記に示します。

(下記のコード内には、説明用にコメント文を入れていますが、実際に使う場合は消してください)
```json-doc
{
    "Version": "2012-10-17",
    "Statement": [
        // ユーザーのリストを見る権限
        // これがないとMFAの設定画面に辿り着けない
        {
            "Sid": "AllowListActions",
            "Effect": "Allow",
            "Action": [
                "iam:ListUsers",
                "iam:ListVirtualMFADevices"
            ],
            "Resource": "*"
        },
        // MFAのデバイスを設定するための権限
        {
            "Sid": "AllowUserToCreateVirtualMFADevice",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice"
            ],
            "Resource": "arn:aws:iam::*:mfa/*"
        },
        // 自身のMFAの設定を有効化, 表示, 再同期をするための権限
        {
            "Sid": "AllowUserToManageTheirOwnMFA",
            "Effect": "Allow",
            "Action": [
                "iam:EnableMFADevice",
                "iam:GetMFADevice",
                "iam:ListMFADevices",
                "iam:ResyncMFADevice"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        // 自身のMFAの設定を削除する権限
        {
            "Sid": "AllowUserToDeactivateTheirOwnMFAOnlyWhenUsingMFA",
            "Effect": "Allow",
            "Action": [
                "iam:DeactivateMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::*:user/${aws:username}"
            ],
            "Condition": {
                "Bool": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        },
        // MFAの設定が終わるまで、それ以外の権限を無効化する
        // 追加箇所がないと、初回ログイン時にパスワードの変更が出来なくて詰む
        {
            "Sid": "BlockMostAccessUnlessSignedInWithMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:GetUser", // 追加箇所
                "iam:ChangePassword", // 追加箇所
                "iam:CreateVirtualMFADevice",
                "iam:EnableMFADevice",
                "iam:ListMFADevices",
                "iam:ListUsers",
                "iam:ListVirtualMFADevices",
                "iam:ResyncMFADevice"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }
    ]
}
```

上記のポリシーをアタッチすることで、MFAの登録を必須にしたIAMユーザーを払い出すことが出来るようになります。

(注意点)
MFA登録直後に、他のリソースへアクセスできるようになるわけではなく、一旦ログアウトして、MFAを用いて再度ログインする必要があります。