DEV Community

Kiell Tampubolon
Kiell Tampubolon

Posted on

We thought we had location-based MFA. We had something else entirely

We thought we had location-based MFA. We had something else entirely

Our CTO asked a simple question: when someone travels and signs in from outside our home country, do we prompt for MFA? Everyone's gut answer was yes. Users do get prompted when they travel. Case closed, right?

I decided to actually verify it. What I found changed the answer from "yes" to "yes, but not for the reason anyone thinks," and the whole audit turned into a small migration project. Here's the walkthrough, including the wrong turns, in case you need to run the same check on your tenant.

Where this configuration actually lives

My first instinct was Intune, since that's where our endpoint security lives. Wrong place. Intune handles device compliance. The "prompt MFA based on where you sign in from" logic lives in Microsoft Entra ID, under Conditional Access. Intune only feeds into it as a signal (the "require compliant device" grant control).

So the audit checklist looks like this:

  1. Conditional Access → Named locations: is there a location defined for your trusted country or IPs?
  2. Conditional Access → Policies: is there a policy that requires MFA when the sign-in location is outside those trusted locations?
  3. Sign-in logs: does reality match the config?

What we found

Named locations: one stale IP range from two years ago, not referenced by any policy. No trusted country, no office IPs.

Policies: 18 policies total. Only 3 enabled, all device-related (block unmanaged devices, MAM). Zero location-based policies. Not even a disabled one.

So the honest answer to the CTO was: no, we never configured travel MFA. And yet users were definitely getting MFA prompts when travelling. Something else was doing it. Hold that thought.

Entra also showed us its own receipts. Under Policies there's a Security Alerts section that analyzes your last 7 days of sign-ins. Ours said 72% of sign-ins were out of scope of any Conditional Access policy, and a few hundred sign-ins were still using legacy authentication. If you've never looked at this panel, look. It's free ammunition for whatever security proposal you're trying to get approved.

Building the policy

Management wanted trusted locations defined by IP ranges (office egress + VPN egress) rather than by country. That's the stricter and, I'd argue, better option. Country-based trust means anyone inside the country skips MFA, including an attacker on a VPN exit node in your city. IP-based trust means the corporate network is the boundary: on VPN, no prompt; off VPN, prompt. Wherever you physically are.

Step 1: find your real egress IP

Don't ask around or trust documentation. Test it:

  1. Connect the corporate VPN, open ifconfig.me, note the IP.
  2. Sign in to any Microsoft 365 portal, then open Entra → Sign-in logs and check the IP address recorded on that sign-in.
  3. If the two IPs match, your M365 traffic goes through the VPN tunnel and the VPN egress IP is usable as a trusted location.

Step 2 matters more than it looks. A lot of VPN setups use split tunneling and exclude Microsoft 365 traffic from the tunnel (Microsoft themselves recommend this for performance). In that case Entra sees the user's local ISP address, your VPN-based trusted location never matches, and the policy will prompt everyone everywhere. Better to find out in a ten-minute test than after rollout. Ours matched, so we were fine.

Also check your logs for IPv6 sign-ins. If clients sometimes authenticate over IPv6, an IPv4-only trusted range silently fails to match those.

Step 2: named location

Conditional Access → Named locations → IP ranges location (not Countries location, I clicked the wrong one first and you can't convert between types, only delete and recreate):

  • Add your office and VPN egress ranges in CIDR (/32 for single IPs)
  • Tick Mark as trusted location

Step 3: the policy

  • Users: start with just yourself. Then a pilot group. Then everyone. One policy, widen the scope each phase. Don't create three policies, future-you will hate cleaning them up.
  • Target resources: All resources for the monitoring phase. You want complete data.
  • Network: Include Any location, Exclude your trusted IP location.
  • Grant: Require multifactor authentication.
  • State: Report-only.

Report-only evaluates the policy on every sign-in and records what would have happened, without prompting anyone. Each sign-in event gets a Report-only tab showing "Failure" (would have been prompted) or "Not applied" (excluded or out of scope). After a week or two you know exactly how many prompts per day enforcement will generate, and which accounts would be affected. That's the data you bring to the meeting where someone has to say "turn it on."

One gotcha while testing: check the result on a sign-in to a resource your policy actually covers. I initially scoped the policy to the Office 365 app group, then tested against the Azure portal and wondered why the policy didn't show up in the evaluation. It wasn't broken. The resource just wasn't in scope.

The plot twist: who was prompting all along

While reading sign-in logs I noticed something odd. Sign-ins showed "Multifactor authentication" as the authentication requirement even when every Conditional Access policy on the event said Not applied. MFA was being required by nothing visible in CA.

There's only one thing that does that: legacy per-user MFA, the old Enabled/Enforced toggle buried in the per-user MFA portal, predating Conditional Access. Someone had switched it on for users years ago. It prompts for MFA everywhere, with a "remember this device for X days" option, which is exactly why users only noticed prompts when travelling: new browser, new device, hotel computer. It felt location-based. It never was.

This matters beyond trivia:

  • Per-user MFA ignores trusted locations entirely. Our shiny new exclusion did nothing while it was active, which confused my first round of testing.
  • Microsoft is deprecating per-user MFA and wants everyone on Conditional Access.
  • The migration order is critical: enforce the CA policy first, then disable per-user MFA in batches. Do it in the other order and you've created a window with no MFA at all.

So the audit's final answer to the CTO: yes, users get MFA prompts when travelling, but from a deprecated mechanism that prompts everywhere and can't honor trusted networks. The new CA policy is both the fix and the migration path.

Other things the audit shook loose

Once you start reading policies carefully, you find things:

  • A "block unmanaged devices" policy whose grant logic was actually "require compliant device OR app protection policy, require one." That's not a block, that's an either/or, and the policy name lies about it. Probably intentional for BYOD mobile. Worth confirming rather than assuming.
  • A Microsoft-managed policy ("MFA for admins accessing admin portals") sitting in report-only for over two years, with a note in the fine print: leave it in report-only and Microsoft will enable it for you. Enforcement is coming whether you schedule it or not. Schedule it.
  • Several abandoned test policies from old projects. Off, report-only, names like Group2, Group3, Group4. Every tenant has these. Delete or document them.

The checklist version

If you want to run this same audit on your tenant, in order:

  1. Conditional Access → Named locations: anything defined? Trusted? Referenced by a policy?
  2. Policies: filter by State = On. Read the grant logic on each one. AND vs OR matters.
  3. Pick a user who travelled recently, open their sign-in, read the Conditional Access tab and the Authentication requirement column. If MFA is required but no policy applied it, you have per-user MFA lurking.
  4. Check the Security Alerts panel for out-of-scope and legacy auth numbers.
  5. Verify your VPN egress IP against actual sign-in log entries before trusting it in a policy.
  6. Build the location policy in report-only, scoped to yourself first, and widen from there.

The config took an afternoon. Understanding what was already happening in the tenant took longer, and was worth more.

Top comments (2)

Collapse
 
merbayerp profile image
Mustafa ERBAY

I’ve lost count of how many times an audit started with “we already have that configured” and ended with “apparently we don’t.” 😅
Sign-in logs usually tell a very different story than documentation.

Collapse
 
kielltampubolon profile image
Kiell Tampubolon

Spot on, Mustafa. The difference between 'what we thought we had' and 'what the logs actually showed' is the real takeaway here. Legacy MFA masking as location-based security is a classic trap.