Review MFA requirements for IAM user access

Verify that MFA is actually required for sensitive human access to AWS.

Description

Allowing sensitive AWS operations with human credentials alone can increase the impact of password or key exposure. Apply MFA to the required login and API flows, checking the authentication method and the complete effective policy set.

Registering an MFA device does not enforce MFA on every API call. Long-term access keys lack aws:MultiFactorAuthPresent, so use supported MFA temporary-credential flows. For federated access, review the external IdP’s MFA policy too.

Potential impact

  • Exposed credentials can allow data access or sensitive resource changes.
  • Incorrect conditions can permit requests with missing MFA context or interrupt required automation.

Remediation

  • Require MFA for sensitive human operations and test requests with and without it. Separate automation into least-privilege workload roles.
  • Allow with BoolIfExists set to true also permits requests where the key is absent. Review conditions that actually require MFA together with grants from other policies.

Examples

Provide the existing user and actual role specified by var.target_role_arn. These excerpts cover a role-assumption Allow; target trust and other permissions are separate.

Before

hcl
resource "aws_iam_user_policy" "example" {
  name = "terraform-user"
  user = aws_iam_user.example.name

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Resource": "${var.target_role_arn}",
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

After

hcl
resource "aws_iam_user_policy" "example" {
  name = "terraform-user"
  user = aws_iam_user.example.name

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Resource": "${var.target_role_arn}",
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}
EOF
}

Explanation:

  • Before: This statement can permit role assumption without MFA.
  • After: This Allow applies only when the MFA value is true. It does not automatically protect all account sign-ins and other API permissions.

References