IAMユーザにMFA設定を強制するにあたりiam:ListUsersが必須では無くなった話

記事タイトルとURLをコピーする

CS課佐竹です。

はじめに

皆様、IAMユーザにMFAを強制されているでしょうか?
MFA とは Multi-Factor Authentication の略称で、日本では「多要素認証」や「2段階認証」と呼ばれています。このMFAを弊社ではお客様環境での作業にあたり、全員が 仮想 MFA デバイス を必須として作業をしています。
そして、MFA の設定を終えていないIAM Userは、ごく限られた動作(MFA デバイスの設定追加)しかできないよう制限がかけられています。この制限下において、過去はiam:ListUserの付与が必須となっておりましたが、現在はこれが不要になりましたというお話をします。

仮想 MFA デバイス、U2Fセキュリティキー

ちょっとしたご紹介ですが、仮想MFAのデバイスとしてスマホを利用する場合、Google AuthenticatorやAuthyというアプリが有名です。他には、本エンジニアブログでも紹介されておりますYubikeyもMFAデバイスとして利用することが最近では増えてきています。

2019年1月までのMFA強制 IAM Policy のベストプラクティス

古くは2015年6月に書かれた以下のAWSの公式ブログに記述があります。

AWS IAMユーザーの多要素認証管理を委任する方法

ここで「Force_MFA」という言葉が登場しております。ここでは 「Force_MFA」ポリシーでは、MFAデバイスを使用してログインしていない場合、「iam:*」以外のものへのアクセスを明示的に拒否します」 と記載があるように、制御が緩いものの「MFAデバイスの強制」がうたわれております。その後さらに制御は厳格になり、以下のIAM Policyが公式ドキュメントでも提供されています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAllUsersToListAccounts",
            "Effect": "Allow",
            "Action": [
                "iam:ListAccountAliases",
                "iam:ListUsers",
                "iam:ListVirtualMFADevices",
                "iam:GetAccountPasswordPolicy",
                "iam:GetAccountSummary"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowIndividualUserToSeeAndManageOnlyTheirOwnAccountInformation",
            "Effect": "Allow",
            "Action": [
                "iam:ChangePassword",
                "iam:CreateAccessKey",
                "iam:CreateLoginProfile",
                "iam:DeleteAccessKey",
                "iam:DeleteLoginProfile",
                "iam:GetLoginProfile",
                "iam:ListAccessKeys",
                "iam:UpdateAccessKey",
                "iam:UpdateLoginProfile",
                "iam:ListSigningCertificates",
                "iam:DeleteSigningCertificate",
                "iam:UpdateSigningCertificate",
                "iam:UploadSigningCertificate",
                "iam:ListSSHPublicKeys",
                "iam:GetSSHPublicKey",
                "iam:DeleteSSHPublicKey",
                "iam:UpdateSSHPublicKey",
                "iam:UploadSSHPublicKey"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowIndividualUserToViewAndManageTheirOwnMFA",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:EnableMFADevice",
                "iam:ListMFADevices",
                "iam:ResyncMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/${aws:username}",
                "arn:aws:iam::*:user/${aws:username}"
            ]
        },
        {
            "Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",
            "Effect": "Allow",
            "Action": [
                "iam:DeactivateMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/${aws:username}",
                "arn:aws:iam::*:user/${aws:username}"
            ],
            "Condition": {
                "Bool": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        },
        {
            "Sid": "BlockMostAccessUnlessSignedInWithMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:ListVirtualMFADevices",
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice",
                "iam:ListAccountAliases",
                "iam:ListUsers",
                "iam:ListSSHPublicKeys",
                "iam:ListAccessKeys",
                "iam:ListServiceSpecificCredentials",
                "iam:ListMFADevices",
                "iam:GetAccountSummary",
                "sts:GetSessionToken"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }
    ]
}

ここで注目して頂きたいのが、最下部にある "BlockMostAccessUnlessSignedInWithMFA" の箇所です。この箇所に記載されているNotAction部分が、MFAを設定していないIAM Userが操作することができる、限られたアクションが記載されています。この中で最も問題となるのが "iam:ListUsers" です。

"iam:ListUsers"が問題になるシーン

これがあるとどんな問題が起きるでしょうか?想像すると簡単なことなのですが、このアクションが存在すると、他のIAM UserのListが丸見えになってしまいます。つまり、MFAを設定させるというベストプラクティスを守る結果、iam:ListUsers権限により、IAM Userの名前が、各ユーザに全て見えてしまうという別のセキュリティリスクが出てしまいます。
そしてIAM UserのNameは一意に特定するためにメールアドレスを利用されることが多い状況です。ベンダー様もIAM Userが払い出される場合、IAM Userのリストには、複数のベンダー様のメールアドレスも同時にリストになっています。それを、MFAの設定のために一度全て見せないといけない、というのがこのポリシーの最大の問題点でした。 想像してみてください。MFAを設定させようとすると、他のベンダーと自社のユーザのメールアドレスが一旦丸見えになる、これは少々恐ろしい状況です。

実際の設定画面を確認する

先に書いたIAM Policyを設定した状況で、どのような操作をユーザがすることになるのかマネジメントコンソールから確認してみます。

現在、「IAMTestUser1_Old」というIAM Userでログインしています。こちらには古いIAM Policyがアタッチされており、"iam:ListUsers" が利用可能なため、IAMユーザが全て閲覧可能になっています。この後、自分のUser名をクリックして操作を進めます。

開いた後「Security Credentials」のタブから「Assigned MFA device」の「Manage」ボタンを押下します。

後は上記の画面から、仮想 MFA デバイスの設定に進みます。上記の通り、過去のIAM PolicyではMFAの設定箇所にたどり着くまでに、「全てのIAM Userの一覧を表示する」⇒「そこから自分のIAM Userを選択する」という流れが必須でした。

現在のMFA強制 IAM Policy のベストプラクティス

最新のIAM Policyですが、こちらの公式ドキュメントで提供されています。ですが2019年4月1日現在、一部ポリシーとして不足しているアクションがあるため、今回はそれを追加し、以下を現時点でのベストプラクティス IAM Policyとして活用しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowViewAccountInfo",
            "Effect": "Allow",
            "Action": [
                "iam:GetAccountPasswordPolicy",
                "iam:GetAccountSummary",
                "iam:ListVirtualMFADevices"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowManageOwnPasswords",
            "Effect": "Allow",
            "Action": [
                "iam:ChangePassword",
                "iam:GetUser",
                "iam:CreateLoginProfile",
                "iam:DeleteLoginProfile",
                "iam:GetLoginProfile",
                "iam:UpdateLoginProfile"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnAccessKeys",
            "Effect": "Allow",
            "Action": [
                "iam:CreateAccessKey",
                "iam:DeleteAccessKey",
                "iam:ListAccessKeys",
                "iam:UpdateAccessKey"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnSigningCertificates",
            "Effect": "Allow",
            "Action": [
                "iam:DeleteSigningCertificate",
                "iam:ListSigningCertificates",
                "iam:UpdateSigningCertificate",
                "iam:UploadSigningCertificate"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnSSHPublicKeys",
            "Effect": "Allow",
            "Action": [
                "iam:DeleteSSHPublicKey",
                "iam:GetSSHPublicKey",
                "iam:ListSSHPublicKeys",
                "iam:UpdateSSHPublicKey",
                "iam:UploadSSHPublicKey"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnGitCredentials",
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceSpecificCredential",
                "iam:DeleteServiceSpecificCredential",
                "iam:ListServiceSpecificCredentials",
                "iam:ResetServiceSpecificCredential",
                "iam:UpdateServiceSpecificCredential"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnVirtualMFADevice",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice"
            ],
            "Resource": "arn:aws:iam::*:mfa/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnUserMFA",
            "Effect": "Allow",
            "Action": [
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:ListMFADevices",
                "iam:ResyncMFADevice"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "DenyAllExceptListedIfNoMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:EnableMFADevice",
                "iam:ChangePassword",
                "iam:GetUser",
                "iam:CreateLoginProfile",
                "iam:DeleteLoginProfile",
                "iam:GetLoginProfile",
                "iam:UpdateLoginProfile",
                "iam:ListMFADevices",
                "iam:ListVirtualMFADevices",
                "iam:ResyncMFADevice",
                "iam:DeleteVirtualMFADevice",
                "sts:GetSessionToken"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }
    ]
}

 

新しく増えた My Security Credentials (セキュリティ認証情報) ページ

以前までMFAの設定においてIAMのUserをリストする権限が必要であったのは、自分自身のIAM Userを選択し、User個別の画面にたどり着くために必要でした。現在は、その代わりとして My Security Credentials (セキュリティ認証情報) というページが用意されています。こちらのリリースは2019年1月24日でしたが、リンク先のニュースページでは一体何を言っているのかイマイチわからなかったため気付くのが遅れました。このニュースリリースから、My Security Credentialsは提供が開始されています。
そしてこれにより、IAM Userのリスト権限は不要となりました。以下、実際の操作をご紹介します。

実際の設定画面を確認する

今回は、Policyを新しくしたユーザである「IAMTestUser2_New」でログインしています。まずは先ほどと同じようにIAMのユーザをリストしてみましょう。上画像の通り必要な権限が付与されていないため、リストは不可能となっておりエラーメッセージが表示されます。エラーメッセージの中の赤枠の通り、"iam:ListUsers"は付与されていないためです。

コンソール右上にあるナビゲーションバーにおいて自分のユーザー名を選択し、その中から [My Security Credentials (セキュリティ認証情報)] を選択します。なお以下のリンクからでもジャンプ可能です。
https://console.aws.amazon.com/iam/home?region=ap-northeast-1#security_credential

[My Security Credentials (セキュリティ認証情報)] を選択すると上画像のページにジャンプします。この画面からMFA デバイスがアサインできるようになっています。

後は先ほどと同じで、仮想 MFA デバイスを選択して設定を継続してください。

DenyAllExceptListedIfNoMFA に iam:DeleteVirtualMFADevice が必要な理由

仮想 MFA デバイスの設定画面では、QRコードを生成するボタンを押下する操作があります。このQRコードを生成するあたりで一度MFAの登録を停止し、再度設定しようとすると、上記のエラー画面が発生します。
これは、AWSの裏側で一度QRコードを作成したタイミングで仮想 MFA デバイスは作成されてしまっており、MFAの設定が完了していない場合でも、次回設定時には iam:DeleteVirtualMFADevice がないと設定ができないという状況に陥ってしまうためです。それを鑑みて、上記のポリシーには iam:DeleteVirtualMFADevice を付与しています。

DenyAllExceptListedIfNoMFA に追加した他のActionについての説明

"iam:ChangePassword", "iam:CreateLoginProfile", "iam:DeleteLoginProfile", "iam:GetLoginProfile", "iam:UpdateLoginProfile" については、ログイン後即時パスワード変更を求められる場合に、MFAを設定するよりも先にパスワード変更をしなければなりません。そのようなシーンを鑑みて付与しました。

注意点

一度 MFA を設定したら、直ちに一度マネジメントコンソールからログアウトし、再度ログインしてください。その時に MFA の入力を求められるのか必ず確認をしましょう。また、一度ログアウトしてログインしなおさない限り、 MFA を利用したログインと見なされませんので、初回にMFAを設定するために利用したログインセッションは「サインアウト」して一度閉じてください。MFA を設定したらすぐに全ての権限が開放されるような動きにはならない点には注意が必要です。

まとめ

IAM のコンソールに新しく My Security Credentials というページが増えたため、今までMFAを強制する時に必須であった "iam:ListUsers" は不要になりました!この仕様に困っていらした方は、すぐさまIAM Policyを見直していただき、 "iam:ListUsers" のないPolicyに上書きしてしまいましょう。
なお、先に書いた「MFA強制 IAM Policy」につきましては、お客様の利用シーンにおいては他に必要なActionがあったり、減らす必要のあるActionがあったりするでしょう。例えば、AWSのドキュメントには記載がありますが  "AllowManageOwnAccessKeys" に記載がある "iam:CreateAccessKey" は本当に必要でしょうか?
また、いきなり本番環境の IAM Policy を上書きするのではなくしっかりとテストをし、さらに運用面等も鑑みて変更を実施頂けますと幸いです。例えば、第3者に提供する「MFA設定手順書」を書き直す必要があるかもしれませんね(心当たりがあります)。

以上になります。ではまたお会いしましょう。

佐竹 陽一 (Yoichi Satake) 記事一覧はコチラ

SRE2課所属。AWS資格12冠。2010年1月からAWSを利用してきました。
AWSのコスト削減、最適化を得意としています。