AWS Organizations の SCP で MFA を組織の全 IAM ユーザに強制する

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

SRE2課 佐竹です。
「SCPの継承」に引き続き、AWS Organizations のお話です。

はじめに

先日、以下のブログ記事を記載しました。こちらに引き続き AWS Organizations について記載します。

blog.serverworks.co.jp

今回は AWS Organizations と MFA に関してとなります。また本記事は、以下のブログの理解を前提として記載していますため、こちらを先にご一読の上、お読み頂けますと幸いです。

blog.serverworks.co.jp

組織レベルで IAM User に MFA を強制したい

先に紹介しましたブログでは「IAM ユーザに MFA 設定を強制する」にあたり各 IAM ユーザに IAM ポリシーをアタッチするか、もしくは既に作成済(MFA強制設定済)の IAM グループに所属させる運用を行う必要があります。正直なところこれは手間です。

この手間を削減したく、 AWS Organizations を利用してAWSアカウント単位でまるごと IAM User に MFA を強制したいと考えました。実際に作成した SCP (サービスコントロールポリシー)を本ブログにて紹介いたします。

IAM User に MFA を強制する SCP の例

  • ForceMFA-for-MySecurityCredentials
{
    "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": "*"
        },
        {
            "Sid": "AllowManageOwnAccessKeys",
            "Effect": "Allow",
            "Action": [
                "iam:CreateAccessKey",
                "iam:DeleteAccessKey",
                "iam:ListAccessKeys",
                "iam:UpdateAccessKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowManageOwnSigningCertificates",
            "Effect": "Allow",
            "Action": [
                "iam:DeleteSigningCertificate",
                "iam:ListSigningCertificates",
                "iam:UpdateSigningCertificate",
                "iam:UploadSigningCertificate"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowManageOwnSSHPublicKeys",
            "Effect": "Allow",
            "Action": [
                "iam:DeleteSSHPublicKey",
                "iam:GetSSHPublicKey",
                "iam:ListSSHPublicKeys",
                "iam:UpdateSSHPublicKey",
                "iam:UploadSSHPublicKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowManageOwnGitCredentials",
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceSpecificCredential",
                "iam:DeleteServiceSpecificCredential",
                "iam:ListServiceSpecificCredentials",
                "iam:ResetServiceSpecificCredential",
                "iam:UpdateServiceSpecificCredential"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowManageOwnVirtualMFADevice",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowManageOwnUserMFA",
            "Effect": "Allow",
            "Action": [
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:ListMFADevices",
                "iam:ResyncMFADevice"
            ],
            "Resource": "*"
        },
        {
            "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"
                },
                "StringLike": {
                    "aws:PrincipalArn": [
                        "arn:aws:iam::*:user/*"
                    ]
                }
            }
        }
    ]
}

※本 SCP の名称は自由にご変更ください

上記 SCP の補足説明

本 SCP の権限設計は、先に紹介しております「IAMユーザにMFA設定を強制するにあたりiam:ListUsersが必須では無くなった話」で紹介しました IAM ポリシーをベースとしており、そのほとんどの箇所が同設定となっています。

ですが、以下の点が変更点になります。

"Effect": "Allow" では "Resource": "*" のみ記載が可能

1つ目は SCP の構文としてどうしても書けないポイントの修正です。

AWS 公式ドキュメントの 「SCP 構文 #Resource 要素」に以下の記載があります。

Effect 要素に Allow の値があるステートメントでは、SCP の Resource 要素の「*」のみを指定することができます。個々のリソースの Amazon リソースネーム (ARN) を指定することはできません。

これはつまり、前回のブログで記載していた以下の箇所はそのままだと構文エラーになるということです。

 "Resource": "arn:aws:iam::*:user/${aws:username}"

本項目は "Resource": "*" に修正せざるを得ませんため、該当箇所の修正は全てで必須となります。なお、本修正による影響は特にありません。

理由ですが、SCP は「それをアタッチしたAWSアカウントにおけるアクセス許可の上限」を設定するものであるためで、SCP 自体によりアクセス許可が設定されることはないからです。これは OU においてデフォルトの「FullAWSAccess」でアクセスを許可していることが問題にならないのと同様です。

参考情報となりますが、記載したSCP が構文エラーの場合には以下のエラーメッセージが表示されます。

The provided policy document does not meet the requirements of the specified policy type.

影響範囲を IAM ユーザのみとするよう明示的に記載

以下の Condition を追加することで影響を IAM ユーザに絞っています。

                "StringLike": {
                    "aws:PrincipalArn": [
                        "arn:aws:iam::*:user/*"

IAM の管理運用において、MFA の強制ポリシーを IAM ユーザ及び IAM グループ以外にアタッチするシーンは基本的に無いと考えられ実際にその通り運用しますが、これを IAM ロールにアタッチすることは可能です。

もしそのような設定を行ったと仮定すると、意図しない動作を起こすことは十分に考えられますため、IAM ロールに影響を与える状況は避けなければなりません。この懸念点を鑑み、IAM ユーザのみに SCP の影響を限定しています。

検証

この SCP をエンティティに適用し、実際に想定通りに動作するか検証しました。

以下は、先に記載した SCP をAWSアカウントへ適用後に、新規で作成した test IAM ユーザでマネジメントコンソールにログインして IAM の管理画面を開いた状態の画面キャプチャです。なお、 test IAM ユーザには AWS Managed Policy の「Administrator」のみがアタッチされています。

f:id:swx-satake:20200831205232p:plain

画像の通りですが、「Administrator」がアタッチされているにも関わらずエラーが多数発生しており IAM に関する動作は不可能です。ここまでは想定通りです。

MFA を設定すればこれが解消されるかどうか確認します。

MFA を設定する

iam:ListUsers が付与されていないため My Security Credentials (セキュリティ認証情報)より MFA の設定を行います。以下の通りエラーは発生するものの、MFA の設定は可能です。

f:id:swx-satake:20200831205648p:plain

「MFAデバイスの割り当て」を押下して MFA を設定していきます。

f:id:swx-satake:20200831205840p:plain:w450

上図を経て、test ユーザでの MFA 設定を完了しました。

MFA が設定できた後は、マネジメントコンソールより一度サインアウトしてサインインしなおします。

MFA 設定後の動作確認

ログインしなおすと、先ほどエラーとなっていた IAM のコンソールからエラーが出なくなりました。

f:id:swx-satake:20200831210030p:plain

当初の想定通り MFA は SCP で強制され、IAM ユーザは MFA 設定後に与えられた権限(今回は Administrator)を利用可能となりました。

まとめ

f:id:swx-satake:20200818185726p:plain:w200

今回は IAM ユーザにおける MFA の強制(MFA が設定されていない状態では、極限られた動作しか実行できない)を AWS Organizations の SCP で実装する方法とその検証結果について記載しました。

本 SCP があれば毎回 IAM ユーザを払い出す度にそれぞれのユーザに設定していた ForceMFA の IAM ポリシーをアタッチする定型作業が1つ減ります。運用は「積み重ね」ですので、少し楽になるだけでも全体で見ると大きな工数削減になります。この SCP が皆様の工数削減に少しでも役立てば幸いです。

2020年10月13日追記

本運用に関連して、念のため以下の点を注記させてください。

AWS Organizations の SCP の継承について」で記載した通りなのですが、以下の図の通り「全ての階層で明示的な許可」がない限り利用したい権限は許可されません。

f:id:swx-satake:20200818181501p:plain

つまり、SCP でMFA を強制する権限を付与したからといって "Effect": "Allow" のアクションが IAM User にも付与されるわけではありません。つまり、結局は IAM User にも合わせて本設定と同等かそれ以上の Allow を割り当てる必要はあります。この点を忘れると、IAM User が MFA を設定できなくなったり、パスワードを変更できなくなったりしてしまうので注意してください。SCP はあくまでもガードレールの役割です。

ではまたお会いしましょう。

佐竹 陽一 (Yoichi Satake) エンジニアブログの記事一覧はコチラ

マネージドサービス部所属。AWS資格全冠。2010年1月からAWSを利用してきています。2021-2022 AWS Ambassadors/2023-2024 Japan AWS Top Engineers/2020-2024 All Certifications Engineers。AWSのコスト削減、最適化を得意としています。