How to enforce MFA for IAM users
Topic: Accounts access
Summary
Require multi-factor authentication for IAM users signing in to the console or calling sensitive APIs. Use an IAM policy condition that allows actions only when MFA is present, and assign MFA devices to every human user.
Intent: How-to
Quick answer
- Attach an IAM policy that Denies sensitive actions (e.g. change password, create access keys) when the request is not authenticated with MFA (Condition aws:MultiFactorAuthPresent = false).
- Ensure every human IAM user has a virtual or hardware MFA device assigned in Security credentials; block console sign-in until MFA is set if your policy requires it.
- For CLI, users must use temporary credentials from STS after signing in with MFA (e.g. get-session-token with MFA) so that API calls include MFA context; long-lived keys do not carry MFA.
Prerequisites
Steps
-
Create an MFA-required policy
Write a policy that Denies sensitive IAM and account actions when aws:MultiFactorAuthPresent is false; attach it to users or to a group so all human users are subject to it.
-
Assign MFA to every human user
In IAM → Users → each user → Security credentials, assign a virtual or hardware MFA device; optionally use a custom password policy or process to block first sign-in until MFA is set.
-
Enforce MFA for console and high-risk actions
Ensure the MFA condition applies to console sign-in (via federation or IAM) and to high-risk actions (e.g. iam:*, ec2:Delete*, s3:DeleteBucket); allow read-only or low-risk actions without MFA if acceptable.
-
Document CLI flow with MFA
For programmatic access with MFA, document using get-session-token with MFA serial and code to obtain short-lived credentials; long-lived keys cannot satisfy aws:MultiFactorAuthPresent.
Summary
You will enforce MFA for IAM users by attaching a policy that denies sensitive actions when MFA is not present, assigning MFA to every human user, and documenting the CLI flow for temporary credentials with MFA. Use this to meet compliance and reduce risk from stolen passwords or keys.
Prerequisites
- IAM users already created (see How to create an IAM user with least privilege).
- You have IAM permission to attach policies and manage user MFA (iam:AttachUserPolicy, iam:CreateVirtualMFADevice, iam:EnableMFADevice, or equivalent).
Steps
Step 1: Create an MFA-required policy
Create a customer-managed policy that denies sensitive actions when the request is not MFA-authenticated. Example: deny IAM changes and other high-risk actions without MFA.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": [
"iam:CreateAccessKey",
"iam:DeleteAccessKey",
"iam:ChangePassword",
"iam:UpdateUser",
"iam:AttachUserPolicy",
"iam:DetachUserPolicy"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}
}
}
]
}
Attach this policy to the user or to a group that contains all human IAM users. Broaden the Action list as needed (e.g. include ec2:, s3:Delete) for your risk model.
Step 2: Assign MFA to every human user
- Console: IAM → Users → select user → Security credentials → Assign MFA device. Choose virtual or hardware MFA and complete enrollment.
- Process: Require MFA before granting access to production; optionally set a custom password policy that forces password change on first sign-in and remind users to set MFA immediately.
You cannot assign MFA via CLI without the user’s cooperation (they must provide the current MFA code). Use the console or automation that invokes the user’s session.
Step 3: Enforce MFA for console and high-risk actions
- Console sign-in: When users sign in as IAM user, AWS does not enforce MFA by default. Your Deny policy with
aws:MultiFactorAuthPresentapplies to API calls; after console sign-in with password, the console uses temporary credentials that include MFA if the user completed MFA at sign-in. Ensure users are prompted for MFA at console login (account setting or custom sign-in flow). - High-risk actions: Expand the Deny policy’s Action list to cover all sensitive operations (e.g. iam:, ec2:Delete, s3:DeleteBucket, rds:DeleteDBInstance). Allow read-only or low-risk actions without MFA if your policy permits.
Step 4: Document CLI flow with MFA
For CLI users who need to call APIs that require MFA:
- User signs in to console with password + MFA (or uses a script that cannot do interactive MFA).
- User calls
GetSessionTokenwith MFA device ARN and current code to get short-lived credentials. - User sets AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN from the response and runs CLI commands; those calls satisfy
aws:MultiFactorAuthPresent.
Example:
aws sts get-session-token --serial-number arn:aws:iam::123456789012:mfa/user --token-code 123456
Document this in your internal runbook. Long-lived access keys do not carry MFA; for automation that cannot use MFA, use IAM roles (e.g. EC2 instance role, Lambda execution role) instead of user keys.
Verification
- Deny policy is attached to all human IAM users (directly or via group).
- Each human user has MFA assigned in Security credentials.
- Test: sign in without MFA and attempt a denied action (e.g. iam:CreateAccessKey) — should be Denied. With MFA, same action should be Allowed if permitted by other policies.
Troubleshooting
User cannot do anything after policy attach — If the Deny policy is too broad, users may be denied even with MFA (e.g. typo in condition). Use Policy simulator with the user ARN and MFA present = true to verify. Ensure the condition is BoolIfExists so users without MFA in the request (e.g. long-lived key) are denied, but console MFA sign-in is allowed.
CLI always denied — Long-lived keys never have aws:MultiFactorAuthPresent true. Users must call GetSessionToken with MFA and use the returned temporary credentials for CLI when MFA is required.
MFA device lost — Use account recovery (root or admin) to allow the user to sign in and assign a new MFA device; avoid removing the MFA requirement policy as a workaround.