[AWS] IAMユーザーにMFA（多要素認証）を強要するポリシー


# 目的
[IAMのベストプラクティス](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/best-practices.html#enable-mfa-for-privileged-users) にもある通り、IAMユーザーのMFA有効化はセキュリティ強化に有効です。
なので必ず有効化するようにしたいところですが、ルール化しても面倒だと思ってやらなかったり、新しいユーザーが増えると伝え漏れたりしがち。

徹底するにはルールよりも仕組み。
MFA有効化しないとAWSを使えないようにしてみます。

# 方法
AWSマネジメントコンソールの仕様上、MFAを有効化していないユーザーをログインではじくということはできません。
ですので「MFAで認証していない場合に全権限を禁止」という方法を取ります。そういうポリシーをユーザーに付与します。

# ポリシー例

## MFAなしのときは、全てを禁止する

下記ポリシーを付与すると、MFAなしでログインしたときに何もできなくなります。

```json:policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": [
        "*"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}

```

`Condition` の `aws:MultiFactorAuthPresent: false` で、MFAされたかどうかを判断します。簡単だね！

…と言いたいところですが、このポリシーだとMFAの初回設定もできませんし、初回ログイン時のパスワード変更もできません。
パスワード・MFAを設定してから、このMFA必須ポリシーと本来必要な権限を付与する　という手順を踏む必要があります。


## MFAなしのときは、MFA設定とパスワード変更のみ許可

先の問題を解消するためのポリシーです。
下記のような権限構成となります。

* 自分自身のMFA設定とパスワード変更のみ常に許可。
* それ以外の操作は、MFA認証していないときは禁止。  
  MFA認証されたときの権限は任意（この他に設定されているポリシーによる）

```json:policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:ListUsers",
        "iam:ListVirtualMFADevices",
        "iam:ListMFADevices"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:EnableMFADevice",
        "iam:ResyncMFADevice",
        "iam:DeleteVirtualMFADevice",
        "iam:CreateVirtualMFADevice",
        "iam:DeactivateMFADevice",
        "iam:ChangePassword",
        "iam:CreateLoginProfile",
        "iam:DeleteLoginProfile",
        "iam:GetLoginProfile",
        "iam:UpdateLoginProfile"
      ],
      "Resource": [
        "arn:aws:iam::*:mfa/${aws:username}",
        "arn:aws:iam::*:user/${aws:username}"
      ]
    },
    {
      "Effect": "Deny",
      "NotAction": [
        "iam:ListUsers",
        "iam:ListVirtualMFADevices",
        "iam:ListMFADevices",
        "iam:EnableMFADevice",
        "iam:ResyncMFADevice",
        "iam:DeleteVirtualMFADevice",
        "iam:CreateVirtualMFADevice",
        "iam:DeactivateMFADevice",
        "iam:ChangePassword",
        "iam:CreateLoginProfile",
        "iam:DeleteLoginProfile",
        "iam:GetLoginProfile",
        "iam:UpdateLoginProfile"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    },
    {
      "Effect": "Deny",
      "Action": [
        "iam:EnableMFADevice",
        "iam:ResyncMFADevice",
        "iam:DeleteVirtualMFADevice",
        "iam:CreateVirtualMFADevice",
        "iam:DeactivateMFADevice",
        "iam:ChangePassword",
        "iam:CreateLoginProfile",
        "iam:DeleteLoginProfile",
        "iam:GetLoginProfile",
        "iam:UpdateLoginProfile"
      ],
      "NotResource": [
        "arn:aws:iam::*:mfa/${aws:username}",
        "arn:aws:iam::*:user/${aws:username}"
      ],
      "Condition": {
        "BoolIfExists": {
            "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}

```

なお、 `Condition` の `aws:MultiFactorAuthPresent` はログイン時にMFAが行われたかどうかを判断する条件です。
MFAを有効化しても即時で"可"にはなりません。
本来の権限を有効にするには、MFA初回設定のあとにログインしなおす必要があります。

# 備考（注意事項）
この記事のポリシーは仮想MFAでのみ検証しています。
物理デバイスは持っていないので未検証。