DE
Discuss your challenge
All insights

Cloud Security

Conditional Access for grown tenants

Why ad-hoc Conditional Access policies stop scaling, and the persona-based framework we now deploy instead, published as open source.

Conditional Access grows policy by policy in most tenants we take over. Every individual rule usually made sense at the time it was created. Two years and four admins later, nobody can tell you why a specific exclusion exists, whether it’s still needed, or what breaks if it’s removed. In our experience, that pattern shows up the same way almost every time: dozens of policies with no consistent naming, no clear owner, and exclusions nobody can explain anymore.

That’s not a Conditional Access problem. It’s a governance problem that Conditional Access happens to make visible. We’ve done this enough times now that we ended up formalising it into a framework, and we’ve published it as open source: CDT Conditional Access Framework on GitHub, currently at release 26H2.

Understand before you touch anything

Before changing a single policy, document what’s actually there: existing policies, exclusions, break-glass accounts, authentication methods and the applications each policy affects. In our experience, the configuration itself is rarely the hard part. The hard part is reconstructing why an exception was added in the first place, because that context is usually in someone’s memory and not in the tenant.

Three stages, not one flat list of rules

What usually happens without a framework is that every new requirement becomes its own one-off policy, targeted at whichever identity needed it that week. Six months in, you have a pile of rules with overlapping scope and no clear order of evaluation to reason about. The structure we now deploy separates that into three stages:

Global Foundation
        ↓
Persona Protection
        ↓
Advanced Protection

Global Foundation is the minimum tenant-wide protection that applies before anything persona-specific: bootstrap MFA, blocking legacy authentication, blocking device code flow, blocking unsupported platforms, blocking untrusted locations, protecting management portals and security-information registration.

MFA itself isn’t the differentiator anymore. Almost every tenant we take over already has it turned on somewhere. What actually separates a mature environment from a fragile one is whether that requirement is consistent and phishing-resistant where it counts, or just present.

Persona Protection only exists where identities genuinely behave differently. Admins need stronger, phishing-resistant authentication, not the same MFA prompt a standard internal user gets. A guest account needs a different session model than an employee. Use Global when the requirement is the same for everyone. Use a persona only when the requirement is actually different. Duplicating the same control across five personas because it feels thorough adds maintenance burden without a real security gain in most cases. The exception is a regulated customer whose auditor wants to see a control scoped to a named persona explicitly, which comes up more often than you’d expect. Outside of that, we steer away from it.

Advanced Protection covers high-impact controls that need operational maturity before they’re safe to turn on: hard-delete protection, authentication context, strict location enforcement, elevated insider-risk controls. These come last, once Foundation and Persona are stable and validated.

A naming convention that survives staff turnover

Every policy follows the same pattern:

<CANumber>-<Persona>-<PolicyType>-<App>-<Platform>-<GrantControl>-<OptionalDescription>

For example:

CA100-Admins-IdentityProtection-AnyApps-AnyPlatform-MFA-PhishingResistant

The persona determines the number range: CA000 to CA099 is Global, CA100 to CA199 is Admins, CA200 to CA299 is Internals, CA300 to CA399 is Externals, CA400 to CA499 is GuestUsers, and it continues through Agents, ServiceAccounts, WorkloadIdentities and ServiceProviders. Within a persona, the last two digits follow a capability order: x00 for authentication, x01 for device, x02 for network, x03 for mobile, x04 for session, x05 for browser, x06 for data, x50 for Advanced Protection.

This sounds like a lot of ceremony until you’re the third administrator to inherit the tenant. At that point, a policy named CA204-Internals-AttackSurfaceReduction-AllApps-AllPlatforms-Block-UntrustedLocations tells you exactly what it does and why it exists, without opening it. The name replaces tribal knowledge that otherwise leaves with whoever set it up.

Report-only is a working mode, not a delay

Report-only doesn’t replace a decision, it produces the data you need to make one safely. We evaluate sign-in logs across user groups, applications, device platforms and failure patterns before anything moves to enforced. One detail that catches people out: the default sign-in log retention is 30 days, which isn’t long enough to validate a Foundation rollout properly. Get it piping into a Log Analytics workspace before the report-only period starts, not once someone asks for three months of history you don’t have. The deployment sequence we follow is consistent across customers:

  1. Define at least two emergency-access accounts and document every deployment exclusion.
  2. Deploy Global Foundation in report-only mode.
  3. Validate against real sign-in data: affected users, applications, authentication flows, platforms.
  4. Enable bootstrap Global MFA as the tenant-wide floor.
  5. Deploy and validate persona-specific MFA and protection policies.
  6. Roll out persona policies in controlled stages, not all at once.
  7. Disable Global MFA only once equivalent persona-level MFA coverage is confirmed, not before.
  8. Introduce Advanced Protection according to the customer’s actual operational maturity.
  9. Review periodically, and document every exception when it’s created, not months later.

The biggest challenge in this process is almost never technical. It’s the discipline to keep policies in report-only long enough to trust the data, and to only disable Global MFA once persona coverage genuinely replaces it.

What every policy needs, regardless of framework

  • A clear purpose and a defined identity scope.
  • A documented application and platform scope. SpecificApps should never stay an undefined placeholder in production.
  • A known licensing requirement. Most of the framework runs on Entra ID P1. User-risk and sign-in-risk conditions specifically need P2, and it’s worth checking that before a policy gets designed around a signal the tenant isn’t licensed to evaluate.
  • An owner and a review date.
  • Documented exclusions, with the reason they exist.
  • A tested rollback path.

Naming, scope and exclusions have to be understandable to an administrator who wasn’t in the room when the policy was created, because eventually one won’t be.

Anchor it in operations, not a one-time project

The migration itself is rarely the difficult part. What’s difficult is keeping the model accurate as applications, identities and devices keep changing underneath it. Policies need an owner and a recurring review, or the security model drifts without anyone noticing until an incident forces the question.

The goal was never the highest possible number of policies. It’s a small, understandable system that reduces risk and stays operable by whoever’s on call at 2am, not just by the person who originally built it.

About the author

Spiros Karampinis

Founder & Lead Cloud Consultant · 17+ years of experience

Cloud strategy, business transformation and clear decisions for Microsoft cloud programmes.

What should change in your Microsoft environment?

In 30 minutes, we'll clarify together:

  • Clarify the current situation and objective
  • Structure possible solution paths
  • Define the most sensible next step

30 minutes · Microsoft Teams · No obligation

Spiros Karampinis
Spiros KarampinisFounder & Lead Cloud Consultant
FIRST CONVERSATION

Book a 30-minute first conversation

Choose a convenient time for a no-obligation conversation.

Control the analytics and third-party features used by this website here. We do not use marketing cookies.

NecessaryAlways active

Stores your theme and cookie choices and temporary language navigation. These functions contain no tracking.

Analytics

Allows Microsoft Clarity to collect pseudonymous usage data such as page views, clicks, scrolling behaviour and session recordings. This helps us identify usability issues and improve the website.

External services

Allows Microsoft Bookings and easyDMARC's Mailflow Guard. These providers may use cookies or browser storage. Alternatively, a service loads only when you explicitly open it.