多要素認証(MFA)するまで使えません!なIAMユーザを作成してみた

IAMユーザに対し、MFAを利用していないと利用できる権限に制限がかかる仕組みを仕込んでみました。
2020.02.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

IAMユーザを利用者へ引き渡す際に「絶対に多要素認証(MFA)の設定を入れてくださいね!!」と伝えても、
そのユーザが本当にMFAを有効化してくれたのか、その確認や催促に手間がかかるときがあります。

そんな手間を省くため、引き渡すIAMユーザには予め
MFAを利用していないと権限に制限がかかる仕組みを仕込んでおくことができます。

概要

IAMユーザに以下の権限を付与すれば完了です。

(1) MFAを設定・有効化するための権限
(2) MFAを利用していない場合、(1)以外すべてのアクションを拒否する権限
(3) 本来許可したい権限

(2)の設定では、IAMポリシーのContdition要素を使ってMFA利用有無による条件分岐を設定します。

(3)で許可された権限であっても、
MFAを利用していない場合は(2)による明示的な拒否設定が上回り、利用することができなくなる仕組みです。

ポリシーの評価論理 - AWS Identity and Access Management
アカウント内でのリクエストの許可または拒否の決定
・ ポリシー内の明示的な拒否は、すべての許可に優先します。

やってみる

(1) MFAを設定・有効化するための権限
(2) MFAを利用していない場合、(1)以外すべてのアクションを拒否する権限

今回は、上記2つの設定をまとめた1つのIAMポリシーを作ります。

(3) MFAを利用している場合許可したい権限

に関しては、今回は仮にAWS管理ポリシーである AmazonS3FullAccess とします。

実際のポリシー

(1) MFAを設定・有効化するための権限
(2) MFAを利用していない場合、(1)以外すべてのアクションを拒否する権限

IAM: IAM ユーザーに MFA デバイスの自己管理を許可する - AWS Identity and Access Management

上記ドキュメントを参考に編集を加えてシンプル化 & 権限を少々限定的にしたものがこちらです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowIndividualUserToManageTheirOwnMFA",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice",
                "iam:ListMFADevices"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/${aws:username}",
                "arn:aws:iam::*:user/${aws:username}"
            ]
        },
        {
            "Sid": "BlockMostAccessUnlessSignedInWithMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice",
                "iam:ListMFADevices"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }
    ]
}

解説

(1) MFAを設定・有効化するための権限

        {
            "Sid": "AllowIndividualUserToManageTheirOwnMFA",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice",
                "iam:ListMFADevices"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/${aws:username}",
                "arn:aws:iam::*:user/${aws:username}"
            ]
        },

自分自身のMFAデバイスを管理するために必要なポリシーです。
登録だけではなく削除やリスト参照なども入ってます。

(2) MFAを利用していない場合、(1)以外すべてのアクションを拒否する権限

        {
            "Sid": "BlockMostAccessUnlessSignedInWithMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice",
                "iam:ListMFADevices"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }

IAMポリシーのCondition要素を使い、
MFAを用いたサインインをしていない場合は(1)で設定したアクション以外は明示的に拒否する設定です。

やってみる

mfa-control という名前で、先述のIAMポリシーをつくります。

本来付与したいポリシー(今回は AmazonS3FullAccess)と一緒にIAMユーザへアタッチします。

IAMユーザ利用者から見た挙動

MFA未設定時の動作

先程作成したユーザ[mfa-test-user]でログインしてみました。

ユーザはAmazonS3FullAccessの権限も持っていますが、
ログインした直後でMFA未設定の状態では、S3の情報も何も見ることができません。

MFA設定

ではMFAの設定です。 画面右上のIAMユーザ名をクリックし、メニューから「マイセキュリティ資格情報」を選択します。

いろいろな権限が絞られていますが、
多要素認証(MFA)欄の「MFAデバイスの割り当て」は選択できる状態になっています。

ここから普段どおりMFAデバイスを登録しましょう。

MFA設定後の動作

一度ログアウトしてからMFAを使って再ログインすると、
本来の権限でコンソールを操作することができるようになりました!

注意事項(CLIによる操作)

CLIでの操作も同様にMFAを利用していない場合は権限が制限されますが、
AWS CLIではMFAを使ったIAMユーザの認証を行うためにひと手間必要になります。

(以下、CLI実行時のプロファイル名はmfa-test-userとしています)

MFAを使わずに拒否される状態

$ aws s3 ls --profile mfa-test-user

An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied

IAMユーザがAWS CLIでMFAを用いるためには、
$ aws sts get-session-token コマンドを使ってMFA認証済みの一時クレデンシャルを発行した上で
その一時クレデンシャル情報を利用して各種操作を行う必要があります。

一時クレデンシャルの発行

※ オプションで有効期限を指定しない場合、デフォルトは12時間です
※ クレデンシャルにはダミー用の適当な文字列を入れています

$ aws sts get-session-token --serial-number <MFAデバイスのARN> --token-code <6桁のMFA用トークン> --duration-seconds <有効期間> --profile mfa-test-user
{
    "Credentials": {
        "AccessKeyId": "hogehogehogehoge",
        "SecretAccessKey": "fugafugafugafuga",
        "SessionToken": "aaaaaaaaaaaaaaaa.........aaaaaaaaaaaa",
        "Expiration": "2020-02-29T00:39:59Z"
    }
}

一時クレデンシャルの登録・AWS CLIの操作

環境変数に設定する場合

$ export AWS_ACCESS_KEY_ID=hogehogehogehoge
$ export AWS_SECRET_ACCESS_KEY=fugafugafugafuga
$ export AWS_SESSION_TOKEN=aaaaaaaaaaaaaaaa.........aaaaaaaaaaaa

$ aws s3 ls
2018-07-07 15:51:33 <SAMPLEBUCKET1>
2018-07-07 15:51:33 <SAMPLEBUCKET2>

AWS CLIのconfigファイルに設定する場合

$ cat ~/.aws/credentials
[mfa-test-user]
aws_access_key_id = hogehogehogehoge
aws_secret_access_key = fugafugafugafuga
aws_session_token = aaaaaaaaaaaaaaaa.........aaaaaaaaaaaa

$ aws s3 ls --profile mfa-test-user
2018-07-07 15:51:33 <SAMPLEBUCKET1>
2018-07-07 15:51:33 <SAMPLEBUCKET2>

このように一手間必要になるためご注意ください。

まとめ

IAMユーザに対し、MFAを利用していないと利用できる権限に制限がかかる仕組みを仕込んでみました。
この記事がみなさまのよりセキュアなIAM運用の一助となれば幸いです。

将来的には、このような設定を入れずとも初回ログイン時にMFA登録画面に遷移するような設定ができるようになればとても嬉しいなと思っています!