Enforce AWS MFA for IAM Users with a Deny-by-Default Policy (and Safe Exceptions)

Still have legacy IAM users? This guide shows how to enforce MFA with a simple explicit-deny policy that blocks all actions unless MFA is present—yet preserves just enough access to enroll devices or obtain temporary session tokens. We cover rollout options, SCP usage, exception patterns, monitoring, and common pitfalls.

Table of Contents

Multi‑factor authentication (MFA) is one of the highest‑ROI controls you can turn on in AWS. Yet many accounts still rely on legacy IAM users with long‑lived access keys, ad‑hoc exceptions, and inconsistent MFA setup. That combination increases the blast radius of key leakage and makes it harder to satisfy frameworks like CIS, SOC 2, and ISO 27001. If you’re not fully on IAM Identity Center (SSO) yet—or you have a handful of IAM users you can’t retire—enforcing MFA quickly and predictably is the next best step.

In this article we’ll share a copy‑pasteable explicit‑deny policy that blocks all actions unless MFA is present, while still allowing the minimal API calls needed to enroll MFA or bootstrap a short‑lived session token. We’ll cover when to use this approach, how to deploy it (user/group vs. organization‑wide via SCP), safer exception patterns (break‑glass and automation), and the common gotchas we see in real environments.

TL;DR: Attach a single explicit‑deny policy to IAM users or groups to block all access unless MFA is present—while still allowing the small set of API calls required to enroll MFA or obtain temporary session credentials. Test in staging, add a break‑glass path, and prefer IAM Identity Center (SSO) for new accounts.

The Policy

This statement explicitly denies all actions except those in NotAction when the request does not include MFA. Explicit denies always win, so this effectively forces MFA enrollment and MFA‑backed sessions for production access.


When to Use This Pattern

  • You still have legacy IAM users. If you haven’t fully migrated to AWS IAM Identity Center (SSO), this is a pragmatic control to raise your security baseline.
  • You want a quick, enforceable guardrail. It’s one policy you can attach at the user or group level (or via SCP at the OU/account level; see below).
  • You must satisfy compliance requirements. Many frameworks (CIS, SOC 2, ISO 27001) expect MFA on admin paths and programmatic access.

Prefer SSO for greenfield: For new environments, we recommend using AWS IAM Identity Center with MFA enforced. Use this deny policy primarily to harden remaining IAM users (long‑lived access keys, automation, or special cases).


How It Works (in Plain English)

  • On every API call, AWS evaluates policies. If aws:MultiFactorAuthPresent is false (no MFA), this policy kicks in and denies everything except:
    • Creating and enabling a virtual MFA device
    • Listing MFA devices (to discover/enroll)
    • Getting the user identity
    • Calling sts:GetSessionToken (to exchange MFA + long‑lived keys for short‑lived session creds)
  • Once the user either enrolls MFA (so they can call with MFA) or uses MFA with GetSessionToken, normal access resumes (subject to your standard allow policies).

✳️ BoolIfExists ensures the condition applies only when the context key is present. If a service call lacks the key, AWS treats it as non‑MFA and the deny still applies—exactly what we want.


Deployment Options

Option A — Attach to Users/Groups (fastest)

  1. Create a managed policy named Deny-Without-MFA with the JSON above.
  2. Attach it to high‑privilege groups first (e.g., Administrators).
  3. Roll out to remaining users in phases.

Option B — Organization‑wide via SCP (strongest)

  • Apply a Service Control Policy at the OU or account level to cover all identities in the account.
  • Important: Tune NotAction carefully for your environment, and ensure a break‑glass principal (see below) remains usable.

Safer Exception Patterns (Break‑Glass & Automation)

1) Break‑glass role (human emergency use)

  • Create a dedicated role, e.g., BreakGlassAdmin, with strong monitoring and a short session duration.
  • Exempt that role from the SCP by scoping the SCP to principals other than that role, or by placing the role in an OU not covered by the SCP. Use tight CloudTrail alerts.

2) Automation without human MFA

  • For machine roles, don’t use IAM users. Use IAM roles assumed by CI/CD or services. They won’t hit this policy because role assumption doesn’t use aws:MultiFactorAuthPresent.

3) Temporary exception group

  • Create a group MFA-Exempt-Temporary with a time‑boxed inline policy allowing essential reads while you onboard a vendor. Use an approval + expiration process.

Sample exception (narrow read‑only)

This works only if you do not attach the global deny to the same principal, because an explicit Deny always overrides Allow. Prefer using SCP scoping or separate principals for exceptions.


Step‑by‑Step: User Experience

  1. User signs in (console) or makes an API call (CLI/SDK) without MFA.
  2. Access is denied for most actions, but they can:
    • Create & enable a virtual MFA device
    • List devices and view their user details
    • Call sts:GetSessionToken with --serial-number and --token-code
  3. After enrolling, or after obtaining an MFA‑backed session token, their normal permissions apply.

CLI example (programmatic MFA):

Export the returned temporary credentials as env vars or a named profile and proceed.


Common Gotchas

  • Root user is out of scope. This policy doesn’t apply to the root user. Enforce MFA on root and store codes securely. Consider an SCP to block root API access entirely.
  • Console vs. CLI. For console, users enroll a (virtual) MFA device and sign in with MFA. For CLI, they typically use long‑lived keys plus sts:GetSessionToken with a current MFA code to obtain temporary session creds.
  • Hardware/virtual MFA types. Virtual TOTP apps (e.g., Authy, Google Authenticator) and FIDO U2F/WebAuthn (where supported) are fine. If you standardize, document the approved method.
  • Deny beats allow. If you attach this deny to a user, no allow policy can bypass it. Model exceptions with scope, not with more allows.
  • SSO users unaffected. IAM Identity Center users don’t use IAM users, so this policy won’t be evaluated for them. Enforce MFA in your identity provider.

Validation & Monitoring

  • Pre‑deployment dry run: Apply to a staging account or to a single low‑risk group and verify console + CLI flows.
  • CloudTrail: Alert on iam:CreateVirtualMFADevice, iam:EnableMFADevice, and failed AccessDenied bursts as indicators of rollout and misconfiguration.
  • Config Rules / Security Hub: Ensure you have checks for users without MFA and for active access keys.

Rollback Plan

  1. Detach the managed policy from the affected group/users (or disable the SCP) if you observe critical breakage.
  2. Keep the policy definition in version control with change history.
  3. Post‑mortem any access gaps and refine NotAction or exception scoping.

FAQ

Can I add more APIs to NotAction?
Yes—but be conservative. Every addition is another action available without MFA. In most cases, the set above is sufficient for enrollment and session bootstrap.

What about users who already have MFA?
They’ll continue working normally; calls with MFA context won’t hit the deny.

Should I just migrate to SSO?
Yes, long‑term. Use this policy as a bridge control while you deprecate IAM users.


Copy‑Paste: Managed Policy Template

 

Have a project or a problem?

Talk with a senior engineer for practical recommendations—no obligation.

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts

Categories

Get a free consultation from Reliable Penguin

Submit the form—or for immediate service call 866-649-7984.