Skip to content

How do I enforce MFA authentication for IAM users that use the AWS Management Console and the AWS CLI?

2 minute read
1

I created a multi-factor authentication (MFA) condition policy to restrict access to AWS services for AWS Identity and Access Management (IAM) users. The policy works with the AWS Management Console, but not with the AWS Command Line Interface (AWS CLI).

Short description

The following example IAM policy requires IAM users to use MFA to access specific AWS services:

{
  "Sid": "BlockMostAccessUnlessSignedInWithMFA",
  "Effect": "Deny",
  "NotAction": [
    "iam:CreateVirtualMFADevice",
    "iam:DeleteVirtualMFADevice",
    "iam:ListVirtualMFADevices",
    "iam:EnableMFADevice",
    "iam:ResyncMFADevice",
    "iam:GetUser",
    "iam:GetLoginProfile",
    "iam:ListAccountAliases",
    "iam:ListUsers",
    "iam:ListSSHPublicKeys",
    "iam:ListAccessKeys",
    "iam:ListServiceSpecificCredentials",
    "iam:ListMFADevices",
    "iam:GetAccountSummary",
    "sts:GetSessionToken"
  ],
  "Resource": "*",
  "Condition": {
    "BoolIfExists": {
      "aws:MultiFactorAuthPresent": "false"
    }
  }
}

In the preceding policy, IAM users that use the AWS Management Console are prompted to enter MFA authentication credentials to access AWS services. However, IAM users that use the AWS CLI aren't prompted to enter MFA authentication credentials to access AWS services.

Resolution

Note: If you receive errors when you run AWS CLI commands, then see Troubleshoot AWS CLI errors. Also, make sure that you're using the most recent AWS CLI version.

Because the aws:MultiFactorAuthPresent key doesn't exist in long-term credentials requests, the key doesn't deny access to the requests. If the key in the policy isn't with the Boolean condition operator, then the values don't match.

IAM users that use the AWS Management Console generate temporary credentials and allow access only when they use MFA.

To enforce MFA authentication with the AWS CLI, add the IfExists condition operator to check if the MultiFactorAuthPresent key is in the request. The Boolean condition lets you restrict access with a key value that's set to true or false. If the MultiFactorAuthPresent key isn't in the request, then IfExists evaluates the condition element as true.

Example IAM policy:

{
    "Sid": "DenyAllExceptListedIfNoMFA",
    "Effect": "Deny",
    "NotAction": [
        "iam:CreateVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:GetUser",
        "iam:GetLoginProfile",
        "iam:GetMFADevice",
        "iam:ListMFADevices",
        "iam:ListVirtualMFADevices",
        "iam:ResyncMFADevice",
        "sts:GetSessionToken"
    ],
    "Resource": "*",
    "Condition": {
        "BoolIfExists": {
            "aws:MultiFactorAuthPresent": "false"
        }
    }
}

Note: IAM users that use the AWS CLI with long-term credentials are denied access and must use MFA to authenticate. Make sure to use an MFA token to authenticate your CLI session.

Related information

How do I require users from other AWS accounts to use MFA to access my Amazon S3 buckets?

Using multi-factor authentication

Assign MFA devices in the AWS CLI or AWS API

4 Comments

It is simple not works while working with SCP. Only if you attach it directly to a user, or a userGroup where the user part of this group.

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
EXPERT

replied 2 years ago

G'Day Author,

I have tried that SCP verbatim: no it does not work as is, but finally did, modulo a little adjustment in the SCP.

  1. Remove "aws:ViaAWSService": "false"
  2. Add "iam:GetUser",
  3. Add "iam:GetLoginProfile",
  4. Use ${aws:username} to prevent inter-staff tinkering

Rationale behind: "aws:ViaAWSService": "false" may prevent you from setting up MFA even though all other conditions are met, because setting up an MFA, at some point through the Wizard, is delegated to an AWS Service.

Tip I advise you to start with a canary release, you may want to add a canary user-specific condition: "Condition": { "StringEquals": { "aws:username": "unit-test-user1" },

Remember your "unit test user 1" will still need an actual policy. You may just add an AWS managed role from the "Job" category.

Find below excerpts from my working version, that did the job: Sorry I can't copy the complete JSON, as there is a length cap here.

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

replied 9 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR

replied 9 months ago