← Back to Learn
mfasecuritypatterns

MFA enforcement patterns that actually work

There are three ways to require MFA in AWS IAM. Two of them are commonly recommended and only one of them works the way most people expect.


Requiring MFA sounds simple: add aws:MultiFactorAuthPresent to a Condition. The complication is that this key behaves differently across long-term credentials, federated sessions, and assume-role chains.

Pattern 1: Deny everything unless MFA

Attach this to the user (or group):

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

The carve-out is necessary so users can register an MFA device for the first time without already having one. BoolIfExists is necessary because aws:MultiFactorAuthPresent is absent for some session types — without IfExists, the condition would skip the Deny entirely for those sessions.

Pattern 2: Require MFA on assume-role

Put this in the role's trust policy:

{
  "Effect": "Allow",
  "Principal": { "AWS": "arn:aws:iam::123456789012:root" },
  "Action": "sts:AssumeRole",
  "Condition": {
    "Bool": { "aws:MultiFactorAuthPresent": "true" }
  }
}

The user can only assume this role if they authenticated with MFA when they got their session credentials. Because MFA presence is sticky on STS sessions, this also covers any subsequent re-assumes within the chain.

Pattern 3: Per-action MFA via aws:MultiFactorAuthAge

{
  "Effect": "Deny",
  "Action": "iam:DeleteRole",
  "Resource": "*",
  "Condition": {
    "NumericGreaterThanIfExists": {
      "aws:MultiFactorAuthAge": "3600"
    }
  }
}

This denies dangerous actions if MFA was authenticated more than an hour ago, forcing a fresh MFA prompt for sensitive operations. It's the IAM equivalent of "this action requires re-authentication."

The traps

Service-linked roles. SLRs are exempt from MFA conditions. AWS uses them for things like Auto Scaling — you can't (and shouldn't) require MFA on them.

Federated sessions. SAML and OIDC sessions may or may not surface MFA presence depending on how the IdP is configured. Test before assuming the condition fires.

The console. Console sessions count as MFA-authenticated if the user logged in with MFA. CLI sessions need aws sts get-session-token with --serial-number and --token-code to mark the session as MFA'd.

What I'd actually deploy

IAM Lens flags policies that mention iam:MultiFactorAuthPresent without IfExists — a common mistake that makes the policy silently ineffective for sessions where the key isn't set.


Try it yourself

Paste any IAM policy into IAM Lens to visualize permissions and catch risky patterns instantly.

Analyze a policy →