Technical Blog

What The Entra Fudge?! Tenant Restrictions v1 Doesn't Mean What You Think It Means

· min read
What The Entra Fudge?! Tenant Restrictions v1 Doesn't Mean What You Think It Means

I had one of those moments recently where you read a piece of documentation, stop, read it again, then immediately start wondering how many organisations have implemented a security control without quite implementing the security control they think they have.

This time the culprit is Tenant Restrictions v1.

If you’ve worked with Microsoft 365 for any length of time, the high-level purpose of Tenant Restrictions is probably familiar enough: stop users on your corporate network authenticating to Microsoft tenants that you don’t trust. A proxy or Secure Web Gateway intercepts the relevant authentication traffic, injects some headers, Microsoft Entra sees those headers and applies the restriction. It’s been around for years, it is widely deployed, and at first glance there isn’t much about it that looks particularly exciting.

Except there is a fairly important wrinkle if your definition of “unapproved Microsoft identity” includes Microsoft consumer accounts.

And I suspect that wrinkle is very easy to miss.

Welcome to another instalment of What The Entra Fudge?!

The bit everyone knows

The normal Tenant Restrictions v1 implementation uses the Restrict-Access-To-Tenants header. Your proxy intercepts requests to the Microsoft Entra authentication endpoints and injects something along these lines:

Restrict-Access-To-Tenants: <permitted-tenant-list>
Restrict-Access-Context: <your-directory-id>

Microsoft documents the relevant authentication domains as including:

login.microsoftonline.com
login.microsoft.com
login.windows.net

The important bit is the first header, which tells Microsoft Entra which tenants the user is allowed to access. So if somebody sitting on your corporate network tries to authenticate to an Entra tenant that isn’t on the permitted list, the authentication flow can be blocked.

That’s the version of Tenant Restrictions most people have in their heads, and I suspect it is also how a lot of implementations get tested. Configure the proxy, try to sign in to another Entra tenant, get blocked, declare victory.

Perfectly reasonable.

Unfortunately, Microsoft consumer accounts don’t quite play by the same rules.

If you want Tenant Restrictions v1 to block consumer Microsoft accounts, Microsoft documents a second mechanism. The proxy must inject:

sec-Restrict-Tenant-Access-Policy: restrict-msa

But not into the same traffic. That header needs to be injected into requests going to:

login.live.com

So despite “Tenant Restrictions” looking like one control at the architecture level, the v1 implementation is actually dealing with two different authentication surfaces using two different headers.

flowchart TB U[User on managed network] --> P[Corporate Proxy / SWG] P -->|TLS inspect + inject| E[Microsoft Entra sign-in endpoints] P -->|TLS inspect + inject| L[login.live.com] E --> H1["Restrict-Access-To-Tenants:<br/>allowed tenant list"] L --> H2["sec-Restrict-Tenant-Access-Policy:<br/>restrict-msa"] H1 --> W[Restrict work / school tenants] H2 --> C[Restrict Microsoft consumer accounts] W --> R1[Unapproved Entra tenants blocked] C --> R2[MSA sign-in blocked]

That distinction matters because the most obvious validation test for Tenant Restrictions v1 only exercises the first branch.

You can have a completely valid Restrict-Access-To-Tenants implementation, test it against another Entra tenant, see exactly the denial you expected and still have proved absolutely nothing about whether a user can authenticate with an Outlook.com or other Microsoft consumer account.

That’s the part that made me go: oh.

How I think we end up here

Imagine a fairly normal enterprise deployment. Somebody has a requirement to stop users accessing external Microsoft tenants from the corporate network. The identity team and network team configure Tenant Restrictions v1 on the proxy, TLS inspection is enabled for the required Microsoft authentication endpoints, the headers are injected and an engineer tests the control with an account in another organisation’s tenant.

The sign-in is blocked.

Excellent. The change works.

The ticket gets closed, the architecture document gets updated and at some point the shorthand description becomes something like “Tenant Restrictions prevents access to non-corporate Microsoft identities.”

That last sentence is where the trouble begins, because it quietly expands the control objective beyond what was actually tested.

Nothing is broken at this point. There isn’t a bypass. Microsoft hasn’t failed to honour the header. The implementation can be doing exactly what it was configured to do. The problem is that “we have Tenant Restrictions” has become a statement about a security outcome rather than a statement about a product feature.

And those aren’t the same thing.

flowchart LR A[Deploy TRv1] --> B[Test another Entra tenant] B --> C{Blocked?} C -->|Yes| D[Control marked effective] D --> E["Assumption expands:<br/>non-corporate Microsoft identities are blocked"] E --> F[MSA path never tested] F --> G["login.live.com remains usable<br/>if restrict-msa was never configured"]

I don’t think this is particularly far-fetched either. In fact, I’d be more surprised if a significant number of long-lived TRv1 deployments hadn’t ended up with some version of this assumption baked into their control language over time.

Security controls have a nasty habit of becoming progressively more abstract as they move away from the people who implemented them. The engineer knows there is a proxy rule and some headers. The architect sees a box labelled “Tenant Restrictions”. The risk register sees “External tenant access restricted”. Eventually somebody asks whether personal Microsoft accounts are blocked and the answer becomes “yes, because Tenant Restrictions”.

Maybe.

But show me the second header.

The MSA-shaped gap

To make the difference concrete, assume your proxy correctly injects the v1 tenant restriction headers into Entra authentication traffic:

Restrict-Access-To-Tenants: contoso.com
Restrict-Access-Context: <contoso-tenant-id>

You test using:

user@fabrikam.com

Fabrikam isn’t permitted, the authentication is denied and everything looks healthy.

Now try:

somebody@outlook.com

If your proxy isn’t also injecting:

sec-Restrict-Tenant-Access-Policy: restrict-msa

into the login.live.com flow, you’ve moved onto a different enforcement path.

The successful Fabrikam test hasn’t failed. It simply never tested this.

sequenceDiagram participant U as User participant P as Corporate Proxy participant E as Microsoft Entra participant L as login.live.com U->>P: Sign in with external Entra account P->>E: Request + Restrict-Access-To-Tenants E-->>U: Blocked Note over U,E: Tenant restriction test passes U->>P: Sign in with Microsoft consumer account P->>L: Authentication request Note over P,L: No restrict-msa header L-->>U: Consumer authentication path continues Note over U,L: Same network, different control path

Which is why I wouldn’t ask an organisation running Tenant Restrictions v1 whether Tenant Restrictions is “working”. I’d ask two separate questions: can I authenticate to an unapproved Entra tenant, and can I authenticate using a Microsoft consumer account?

Those tests sound almost identical when you’re talking about the control in a meeting. Underneath, they are not.

Because apparently that still wasn’t complicated enough

There is another wrinkle in the v1 documentation around consumer authentication.

Microsoft describes passthrough scenarios where Azure and Office.com applications use Microsoft Entra ID to sign consumer users in within a consumer context. For those flows Microsoft documents a special passthrough tenant:

f8cdef31-a31e-4b4a-93e4-5f571e91255a

The Restrict-Access-To-Tenants allowlist can therefore affect some consumer authentication flows as well, depending on the path being taken.

So even the neat mental split of “Entra equals one header, MSA equals the other header” is an approximation. The real question is always where the authentication is actually happening and which enforcement mechanism sees it.

flowchart TB U[Microsoft identity sign-in] --> Q{Which authentication path?} Q -->|Normal Entra tenant| E[Entra sign-in endpoints] Q -->|Direct consumer sign-in| M[login.live.com] Q -->|Consumer via Entra passthrough| P[Special passthrough tenant] E --> EH["Restrict-Access-To-Tenants"] M --> MH["sec-Restrict-Tenant-Access-Policy: restrict-msa"] P --> PH["Restrict-Access-To-Tenants"] EH --> O1[Entra tenant restriction] MH --> O2[Direct MSA restriction] PH --> O3[Passthrough consumer handling]

This is why I keep coming back to a fairly boring principle in identity security: authentication systems are graphs, not boxes.

We like drawing boxes because boxes make architecture diagrams readable. “Tenant Restrictions” fits nicely inside one. Unfortunately, controls don’t inherit our diagramming conventions. Applying enforcement at one authentication node doesn’t make it magically appear at another one just because both nodes belong to Microsoft.

Tenant Restrictions v2 makes more sense

One of the interesting things about looking at this through the current documentation is that Tenant Restrictions v2 is a much cleaner model.

With v2, the policy itself lives server-side in Microsoft Entra cross-tenant access settings and the proxy sends a policy signal rather than carrying the v1 tenant allowlist in the request. The header looks like:

sec-Restrict-Tenant-Access-Policy: <DirectoryID>:<policyGUID>

Microsoft documents injecting that signal into the relevant sign-in domains, including:

login.live.com
login.microsoft.com
login.microsoftonline.com
login.windows.net

More importantly for this particular rabbit hole, Microsoft consumer accounts can be represented explicitly in the v2 policy using the Microsoft Account tenant ID:

9188040d-6c67-4c5b-b112-36a304b66dad

So instead of “remember this completely separate magic value for MSA traffic”, the consumer identity boundary becomes part of the server-side Tenant Restrictions policy.

flowchart LR U[User] --> P[Corporate Proxy] P --> S["TRv2 policy signal<br/>DirectoryID : PolicyGUID"] S --> E[Microsoft sign-in endpoints] E --> CP[Server-side Tenant Restrictions v2 policy] CP --> T1[External Entra organisations] CP --> T2["Microsoft Account tenant<br/>9188040d-6c67-4c5b-b112-36a304b66dad"] T1 --> D1[Allow / Block] T2 --> D2[Allow / Block]

That doesn’t make v2 magic. Microsoft still documents boundaries and exceptions. Consumer OneDrive at onedrive.live.com, for example, is an unconverged legacy path that doesn’t support Tenant Restrictions v2 enforcement, so Microsoft recommends blocking that URL at the proxy where required.

Which is actually a useful reminder not to make exactly the same mistake again and mentally translate “we migrated to v2” into “all Microsoft consumer access is now solved forever”.

The lesson isn’t “v1 bad, v2 good”.

The lesson is: know where the control is evaluated and test the thing you actually care about.

What I’d check if I found TRv1 in an environment

If I inherited a Tenant Restrictions v1 deployment tomorrow, the first thing I would want to see isn’t the Entra configuration or a diagram saying Tenant Restrictions is enabled. I’d want the proxy configuration.

For the Entra side, I’d verify that the expected Restrict-Access-To-Tenants and Restrict-Access-Context headers are being inserted into the documented authentication traffic, then I’d test with an identity from a tenant that is deliberately not permitted.

After that I’d go looking specifically for login.live.com and the following header:

sec-Restrict-Tenant-Access-Policy: restrict-msa

Then I’d test it with an actual Microsoft consumer account.

I’d also want to understand whether passthrough consumer authentication is relevant in the environment, whether there are any routes around the proxy enforcement point, and whether TLS inspection has been scoped correctly. Microsoft explicitly warns against blindly intercepting every subdomain under *.login.microsoftonline.com, because some device registration and certificate-based authentication traffic needs different treatment.

None of that is especially glamorous. There isn’t a CVE. There isn’t a clever token trick. It’s just the deeply unfashionable business of checking that the mechanism underneath the control statement actually produces the control outcome.

And that is kind of the point.

“We have Tenant Restrictions” is not evidence

This is the bit that goes beyond Tenant Restrictions.

Security teams do this constantly:

We have Conditional Access.

We have EDR.

We have DLP.

We have Tenant Restrictions.

Those statements tell me what technology exists. They don’t tell me what behaviour has actually become impossible.

A security control is ultimately the restriction you can demonstrate, not the product feature you can point at. If the intended outcome is “users cannot authenticate with non-corporate Microsoft identities from this network”, then that is what should be tested. Test an external Entra tenant. Test an MSA. Test the paths the applications actually use. Try to find the place where your architectural shorthand stops matching reality.

Because otherwise the abstraction itself starts becoming the evidence.

flowchart LR A["Architecture says:<br/>Tenant Restrictions"] --> B[Assumptions] B --> C[Header injection] B --> D[Endpoint coverage] B --> E[Identity types] B --> F[Authentication flows] C --> G[Observed security outcome] D --> G E --> G F --> G G --> H{Actually tested?} H -->|Yes| I[Evidence] H -->|No| J[Hope]

So if you’re running Tenant Restrictions v1, I think there is one very simple question worth asking:

Show me the proxy rule that injects sec-Restrict-Tenant-Access-Policy: restrict-msa into login.live.com.

If it’s there, excellent. Show me the test as well and we’re done.

If you’ve got Restrict-Access-To-Tenants configured, external Entra tenants are being blocked, everybody believes personal Microsoft accounts are covered too, but nobody can find that second rule…

Well.

What The Entra Fudge?!


References

Microsoft documentation referenced in this article:

comments powered by Disqus