IAM User Hardware MFA Enabled
Overview
This check verifies that IAM users have hardware-based multi-factor authentication (MFA) enabled. Hardware MFA devices include physical security keys (FIDO2/U2F) and hardware TOTP tokens. These are more secure than virtual authenticator apps or SMS-based MFA.
Risk
Without hardware MFA, your accounts are vulnerable to:
- Phishing attacks that can intercept codes from virtual authenticator apps
- SIM-swap attacks that compromise SMS-based verification
- Credential theft where passwords alone grant full access
A compromised IAM user account can lead to data breaches, unauthorized resource access, and privilege escalation throughout your AWS environment.
Severity: High
Remediation Steps
Prerequisites
You need:
- AWS Console access with IAM administrative permissions
- A hardware MFA device (FIDO2 security key like YubiKey, or a hardware TOTP token)
Supported hardware MFA devices
AWS supports two types of hardware MFA:
FIDO2 Security Keys (Recommended)
- YubiKey 5 Series
- Feitian ePass FIDO
- Other FIDO2-certified security keys
Hardware TOTP Tokens
- Gemalto tokens
- Other time-based one-time password hardware devices
FIDO2 keys are preferred because they are phishing-resistant - they verify the website domain before responding.
AWS Console Method
- Sign in to the AWS Console
- Go to IAM (search for "IAM" in the top search bar)
- Click Users in the left sidebar
- Click on the username you want to secure
- Select the Security credentials tab
- Scroll to Multi-factor authentication (MFA)
- If a virtual MFA device is already assigned, click Remove to deactivate it first
- Click Assign MFA device
- Enter a friendly device name (e.g., "MyYubiKey")
- Select either:
- Security key for FIDO2 devices (YubiKey, etc.)
- Hardware TOTP token for physical code generators
- Follow the on-screen prompts:
- For security keys: Insert the key and touch it when prompted
- For TOTP tokens: Enter the serial number and two consecutive codes
- Click Add MFA
AWS CLI (optional)
List current MFA devices for a user:
aws iam list-mfa-devices \
--user-name <username> \
--region us-east-1
Check for virtual MFA devices in your account:
aws iam list-virtual-mfa-devices \
--assignment-status Assigned \
--region us-east-1
Deactivate an existing MFA device (if replacing):
aws iam deactivate-mfa-device \
--user-name <username> \
--serial-number <mfa-device-arn> \
--region us-east-1
Enable a hardware TOTP MFA device:
aws iam enable-mfa-device \
--user-name <username> \
--serial-number <hardware-token-serial-number> \
--authentication-code1 <code1> \
--authentication-code2 <code2> \
--region us-east-1
Replace:
<username>with the IAM user's name<mfa-device-arn>with the ARN of the device to remove<hardware-token-serial-number>with the serial number printed on your hardware token<code1>and<code2>with two consecutive 6-digit codes from the device
Note: FIDO2 security keys must be registered through the AWS Console - they cannot be enabled via CLI.
CloudFormation (optional)
CloudFormation cannot directly assign MFA devices to IAM users. MFA device registration requires interactive user input (touching a security key or entering codes from a token).
However, you can enforce MFA requirements through IAM policies. Here is an example policy that denies most actions unless MFA is present:
AWSTemplateFormatVersion: '2010-09-09'
Description: IAM policy requiring MFA for sensitive actions
Resources:
RequireMFAPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: RequireHardwareMFA
Description: Denies access to sensitive actions without MFA
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowViewAccountInfo
Effect: Allow
Action:
- iam:GetAccountPasswordPolicy
- iam:ListVirtualMFADevices
- iam:ListMFADevices
Resource: '*'
- Sid: AllowManageOwnMFA
Effect: Allow
Action:
- iam:CreateVirtualMFADevice
- iam:DeleteVirtualMFADevice
- iam:EnableMFADevice
- iam:ResyncMFADevice
Resource:
- !Sub 'arn:aws:iam::${AWS::AccountId}:mfa/${!aws:username}'
- !Sub 'arn:aws:iam::${AWS::AccountId}:user/${!aws:username}'
- 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'
Deploy with:
aws cloudformation deploy \
--template-file require-mfa-policy.yaml \
--stack-name require-mfa-policy \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1
Terraform (optional)
Like CloudFormation, Terraform cannot directly assign MFA devices. You can enforce MFA requirements through policy:
# MFA enforcement policy
resource "aws_iam_policy" "require_mfa" {
name = "RequireHardwareMFA"
description = "Denies access to sensitive actions without MFA"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowViewAccountInfo"
Effect = "Allow"
Action = [
"iam:GetAccountPasswordPolicy",
"iam:ListVirtualMFADevices",
"iam:ListMFADevices"
]
Resource = "*"
},
{
Sid = "AllowManageOwnMFA"
Effect = "Allow"
Action = [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ResyncMFADevice"
]
Resource = [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:mfa/$${aws:username}",
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/$${aws:username}"
]
},
{
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"
}
}
}
]
})
}
data "aws_caller_identity" "current" {}
# Attach to a user or group
resource "aws_iam_user_policy_attachment" "require_mfa" {
user = "<username>"
policy_arn = aws_iam_policy.require_mfa.arn
}
Verification
After assigning the hardware MFA device:
- In the IAM Console, go to Users > select the user > Security credentials
- Under Multi-factor authentication (MFA), verify the device shows as assigned
- The device type should indicate "Hardware" or "Security key" (not "Virtual")
CLI verification
aws iam list-mfa-devices \
--user-name <username> \
--region us-east-1
The response should show a device with a serial number that does NOT start with arn:aws:iam::. Virtual MFA devices have ARN-style serial numbers, while hardware devices have physical serial numbers.
Example hardware MFA response:
{
"MFADevices": [
{
"UserName": "alice",
"SerialNumber": "GAHT12345678",
"EnableDate": "2024-01-15T10:30:00Z"
}
]
}
Example virtual MFA response (what you do NOT want):
{
"MFADevices": [
{
"UserName": "alice",
"SerialNumber": "arn:aws:iam::123456789012:mfa/alice",
"EnableDate": "2024-01-15T10:30:00Z"
}
]
}
Additional Resources
- Enabling a Hardware MFA Device (Console)
- Using Multi-Factor Authentication in AWS
- FIDO Security Key MFA
- IAM Best Practices
Notes
- FIDO2 security keys are the most secure option - they are phishing-resistant because they verify the website domain before responding
- Hardware TOTP tokens require entering two consecutive codes during setup to synchronize timing
- If replacing an existing virtual MFA device, the user may temporarily lose access until the hardware device is registered - coordinate the transition
- For programmatic access (CLI/SDK), users must call
sts:GetSessionTokenwith their MFA code to obtain temporary credentials - Consider enforcing hardware MFA organization-wide using AWS Organizations Service Control Policies (SCPs)