Back to blog
AWSBest PracticesCloud SecurityIdentity & AccessOperations & Compliance

IAM User Has No MFA: Why It Matters and How to Fix It

Learn why AWS IAM users without MFA are a top breach risk, how to enable MFA via console and CLI, and how to enforce it with IAM policy and CI/CD gates.

TL;DR

This check flags any IAM user who can sign in to the AWS console with a password but has no MFA device attached. A leaked or guessed password is then all an attacker needs to get in. Fix it by enabling a virtual or hardware MFA device for every console user and enforcing MFA with an IAM policy.

Passwords leak. They get reused across sites, phished, committed to Git repos, and dumped in breach databases. When an IAM user has console access but no second factor, that single leaked password is a direct path into your AWS account. This check exists to catch that gap before someone else does.


What this check detects

The user_mfa check looks at every IAM user in your account and reports any user that meets both of these conditions:

  • The user has a console login profile, meaning a password is set and they can sign in at the AWS Management Console.
  • The user has zero MFA devices registered (virtual, hardware, or U2F/passkey).

Users without a console password are not flagged, since they cannot perform an interactive sign-in and therefore have nothing for MFA to protect at the console. The risk surface here is specifically the human login path.

Note: MFA on the console is separate from MFA on programmatic API calls. A user can have a virtual MFA device for console sign-in while still using long-lived access keys for the CLI. This check only concerns the console login profile, but the broader lesson about avoiding long-lived credentials still applies.


Why it matters

An IAM user password is a single secret. If it is the only thing standing between an attacker and your environment, you are one phishing email or one credential-stuffing run away from a breach. AWS itself reports that the overwhelming majority of account compromises it investigates involve credentials with no MFA.

Here is how this plays out in practice:

  • Credential reuse: An engineer uses the same password for AWS that they used on a site that got breached. The password ends up in a public dump and gets tried against your console.
  • Phishing: A convincing fake sign-in page captures the password. Without MFA, the attacker logs in immediately.
  • Privilege escalation: The compromised user has broad permissions, or enough permissions to create new users, attach policies, or assume more powerful roles. From there the blast radius grows fast.
  • Cryptomining and resource abuse: A common end goal is spinning up expensive GPU or compute instances for mining, leaving you with a five or six figure bill.

MFA breaks this chain. Even with a valid password, the attacker cannot complete a sign-in without the second factor, which they do not have.

Warning: The root user is the most dangerous account of all and is not covered by this check, which only inspects IAM users. Make sure the root user has MFA enabled and that you have a separate check or manual control for it. A compromised root account cannot be contained by IAM policies.


How to fix it

You have two practical paths: enable MFA for an existing user, or, if the user does not actually need console access, remove the login profile entirely.

Option 1: Enable a virtual MFA device (console)

This is the most common fix and works with any authenticator app such as Authy, Google Authenticator, or 1Password.

  1. Sign in to the AWS console as the affected user (or have them do it).
  2. Go to IAM > Users, select the user, and open the Security credentials tab.
  3. Under Multi-factor authentication (MFA), choose Assign MFA device.
  4. Pick Authenticator app (or a passkey/hardware key if you have one).
  5. Scan the QR code with the authenticator app, then enter two consecutive codes to confirm.

Option 2: Enable a virtual MFA device (CLI)

The CLI flow has three steps: create the device, then sync it with two codes from the authenticator app.

# 1. Create the virtual MFA device and save the QR/seed
aws iam create-virtual-mfa-device \
  --virtual-mfa-device-name jane.doe \
  --outfile /tmp/jane-qr.png \
  --bootstrap-method QRCodePNG

# 2. Scan /tmp/jane-qr.png with an authenticator app, then enable it
# Replace the ARN and the two codes with real values
aws iam enable-mfa-device \
  --user-name jane.doe \
  --serial-number arn:aws:iam::123456789012:mfa/jane.doe \
  --authentication-code-1 123456 \
  --authentication-code-2 789012

Danger: The QR/seed file written by --outfile contains the MFA secret. Anyone with that file can generate valid codes. Delete it as soon as the device is enrolled: shred -u /tmp/jane-qr.png (or securely delete it on your platform). Never commit it or leave it on a shared host.

Option 3: Remove console access if it is not needed

If the user only needs programmatic access, the cleanest fix is to delete the login profile so there is no console path to protect at all.

Danger: This permanently removes the user's ability to sign in to the console. Confirm with the user or owning team first. If they later need console access, an admin must recreate the login profile and they will need to reset their password.

aws iam delete-login-profile --user-name service-account-batch

How to prevent it from happening again

Fixing one user is fine. Stopping the next one from ever existing is better. The strongest control is an IAM policy that denies almost everything until the user has authenticated with MFA. Even if someone creates a console user and forgets MFA, that user can do nothing useful until they enroll a device.

Enforce MFA with a policy

Attach this policy (directly or via a group) to your human users. It allows users to manage their own MFA device but blocks everything else until MFA is present in the session.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowManageOwnMFA",
      "Effect": "Allow",
      "Action": [
        "iam:CreateVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:ListMFADevices",
        "iam:ResyncMFADevice"
      ],
      "Resource": [
        "arn:aws:iam::*:mfa/${aws:username}",
        "arn:aws:iam::*:user/${aws:username}"
      ]
    },
    {
      "Sid": "DenyAllExceptUnlessMFA",
      "Effect": "Deny",
      "NotAction": [
        "iam:CreateVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:ListMFADevices",
        "iam:ResyncMFADevice",
        "iam:GetUser",
        "iam:ChangePassword",
        "sts:GetSessionToken"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}

Catch it in CI/CD with policy-as-code

If you provision IAM users through Terraform, block login profiles that ship without an accompanying MFA expectation. Here is an Open Policy Agent (Conftest) rule that fails a plan when an aws_iam_user_login_profile is created:

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_iam_user_login_profile"
  resource.change.actions[_] == "create"
  msg := sprintf("IAM user %q gets console access. Confirm MFA enforcement policy is attached.", [resource.change.after.user])
}

Tip: Rather than provisioning IAM users at all, use AWS IAM Identity Center (formerly SSO) with your existing identity provider. MFA is enforced centrally, credentials are short-lived, and you avoid managing per-user passwords entirely. For most teams this removes the whole category of problem this check looks for.

Monitor continuously

Run this check on a schedule so a user created out-of-band gets flagged within hours, not at the next audit. Lensix evaluates user_mfa across your accounts on every scan, so new console users without MFA surface automatically.


Best practices

  • MFA for every human, no exceptions. Treat console access without MFA as a misconfiguration, not a temporary state.
  • Prefer phishing-resistant factors. Hardware security keys and passkeys (FIDO2/WebAuthn) beat TOTP apps because they cannot be relayed through a fake sign-in page.
  • Move humans to IAM Identity Center. Centralized, federated access with short-lived credentials is more secure and easier to manage than standalone IAM users.
  • Avoid long-lived access keys. If a user needs programmatic access, prefer roles and temporary credentials over static keys.
  • Lock down and MFA-protect the root user. It sits outside IAM policy controls, so it needs its own hardware MFA and should be used almost never.
  • Review the credential report regularly. Run aws iam generate-credential-report and check the mfa_active and password_enabled columns to spot gaps in bulk.

The check is simple, but it guards one of the most exploited weaknesses in cloud accounts. A password with no second factor is not a minor finding. It is the front door left unlocked. Enable MFA, enforce it with policy, and verify it on every scan.