AWS IAMユーザにMFA必須ポリシーを当てる

当記事は[AWS初心者 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/aws_beginner)の25日目の記事です。

## はじめに
　みなさん、コンソールログイン出来る AWS IAMユーザにMFAを当てていますか？
　勿論皆さん当てていると思いますが、そのアカウントにいる他のユーザはどうですか？MFAを有効化していないユーザはいましたか？　いなかったですか。それなら良かったです。え？　貴方は……そうですか。いましたか。
　困りましたね。あ、早速注意しに行くのですね。ふむふむ、素直にMFAを設定してくれましたか。それは良かった。後は……それはお客様のIAMユーザですね。slackでお願いしますか？　でも10人全員に説明するのは大変だし。あ、その人は中々連絡が付かない人ですね。
　
　お久しぶりです。あの後、無事全員のMFAを設定出来ましたか？　全員設定してくれたけど、またMFA設定されてないユーザが作成された？　困りましたね。`here` をつけて注意喚起でもしてみますか?

## MFAを設定しないと何も操作出来ないようにする
　ちょっと待ってください。そんなに胃をキリキリさせて周囲のモラルを恨まなくても済む方法がありますよ。
　試しに、テストユーザを作成して、admin権限と以下のポリシーをアタッチしてみてください。テストユーザは[AWS マネジメントコンソールへのアクセス]にチェックを付けてください。

`ユーザ>アクセス権限>インラインポリシーの追加>JSONタブ`

```json:force_mfa_policy.json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice",
                "iam:CreateVirtualMFADevice",
                "iam:ListMFADevices",
                "iam:GetUser",
                "iam:ChangePassword",
                "iam:DeleteVirtualMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::*:user/${aws:username}",
                "arn:aws:iam::*:mfa/*"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "iam:ListUsers",
                "iam:ListVirtualMFADevices",
                "iam:GetAccountPasswordPolicy"
            ],
            "Resource": "*"
        },
        {
            "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"
                }
            }
        }
    ]
}
```

次に、このテストユーザでログインしてみてください。とりあえず、Lambdaでも触ってみましょうか。

`Lambda>関数`
<img width="618" alt="スクリーンショット 2019-12-23 6.59.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123008/c21307d3-961e-9f07-a31d-03343903c228.png">

アクセスがブロックされましたね。これは許可よりも明示的な拒否が優先されるというIAMの特性の為です(詳細は[こちら(公式ドキュメントに飛びます)](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_evaluation-logic.html))
次に、IAMユーザコンソールにアクセスしてみてください。テストユーザ名を選択し、MFAの設定を行ってみましょう。MFAの設定は許可されている筈です。

`IAM>ユーザー>テストユーザ>認証情報>MFAデバイスの割り当て>管理>仮想MFAデバイス`
エラーが出ますが、気にせず進みます。
<img width="1000" alt="IAM_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123008/14579b99-b1f1-13e3-7106-035cfdf0a0c0.png">
作成したテストユーザの概要でもエラーが出ますが、MFAの設定は出来ますので、MFAを設定しましょう。
<img width="1287" alt="IAM_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123008/ef572364-47b6-8068-5df0-3fb3e8ee0494.png">
<img width="861" alt="IAM_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123008/d68ab2ce-5f66-e4a4-a6f2-65c6cae978d5.png">
ちなみに、他のユーザのMFAを設定しようとすると、以下のようなエラーが出力されます。これは、自分のMFAのみ設定出来るようにポリシーで制限している為です。
<img width="695" alt="IAM_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123008/99dcda1b-b545-3ccf-0c5f-eb3fd69a7007.png">

設定出来ましたか？　それでは一度ログアウトし、再ログインしてください。ではもう一度Lambdaを触ってみましょう。
無事に出来ましたね。
これは、MFAを設定したかどうかではなく、"MFAを使ってログインしたかどうか"を判定している為です。

<img width="436" alt="関数_-_Lambda.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123008/6e8a3029-d445-aa7b-4ccb-930a9f047357.png">

## MFA強制ポリシーとCLI
　やりましたね！　このポリシーでグループを作り、全員を追加すればもう安心です！
……あれ？　どこからか悲鳴が聞こえてきました。CLIが叩けない？？？

```
$ aws s3 ls --profile mfa_test
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
```

このポリシーを適用すると、CLIを叩くときにもMFAを使わないといけなくなってしまいます。なので、トークンを取得し、それをつけてCLIを叩かないといけないので、気をつけてください。
試しにインラインポリシーで設定したMFA強制ポリシーを削除してみましょう。
無事にバケット一覧が出力されましたね。

なので、このMFA必須ポリシーを使用するときは、コンソールログインとCLI用のアカウントを分けるか、CLIを叩くときにトークンを取得し使用する必要がありますので気をつけてください。

## CLIを叩くときにトークンを取得し使用する方法も教えてください:baby:
　要望があったので公式ドキュメントのリンクを貼っておきます(手抜き)
https://aws.amazon.com/jp/premiumsupport/knowledge-center/authenticate-mfa-cli/

## 参考
当記事を書くにあたって参考にさせていただきました。ありがとうございます。
http://blog.serverworks.co.jp/tech/2019/04/02/mysecuritycredentials/
https://qiita.com/n-ishida/items/8198da745a957e8ebdaa
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/tutorial_users-self-manage-mfa-and-creds.html#tutorial_mfa_step1