In this section

MSA3.2 Policy Design Methodology

16 hours · Module 3
What you already know

You understand CA's evaluation engine (MSA3.1): 2-phase processing, 6 signal types, the resolution model where block overrides grant, and the default-allow behavior that creates silent coverage gaps. Now you need a design method. Without one, CA frameworks grow organically: a policy for this group, another for that app, a third for this exception, until nobody can explain what the framework does as a whole, whether it has gaps, or what will happen if a policy is changed. This sub introduces the systematic design methodology: persona-based policy architecture with a naming convention, a decision matrix, and a layered structure that's maintainable, auditable, and predictable.

Tenants with 20+ CA policies where nobody can explain the complete coverage are the norm, not the exception. The root cause: ad-hoc policy creation. An admin creates a policy for a helpdesk ticket ("the compliance team needs MFA for SharePoint"), then another for a different ticket ("block guest access to Azure portal"), then another ("exempt the CEO's iPad from device compliance"). Over 18 months, the framework becomes a collection of point solutions with overlapping conditions, conflicting controls, and gaps where no policy matches. The fix is designing the framework as a system before creating any individual policy, using a methodology that produces predictable, complete coverage. This sub teaches that methodology.

Estimated time: 50 minutes.

The problem with ad-hoc policy creation

Ad-hoc CA frameworks share three symptoms. The diagnostic below checks your tenant for each. If you find any, the design methodology in this sub is the remediation, don't try to fix individual policies without first designing the framework they should belong to.

Connect-MgGraph -Scopes "Policy.Read.All"

$policies = (Invoke-MgGraphRequest -Method GET `
  -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
  -OutputType PSObject).value

# Symptom 1: No naming convention
$hasConsistentNaming = ($policies | Where-Object {
  $_.displayName -match "^CA-"
}).Count
$hasInconsistentNaming = $policies.Count - $hasConsistentNaming

Write-Host "=== AD-HOC DESIGN SYMPTOMS ==="
Write-Host ""
Write-Host "Symptom 1. Naming convention:"
Write-Host "  Policies following 'CA-' convention: $hasConsistentNaming"
Write-Host "  Policies without convention: $hasInconsistentNaming"
if ($hasInconsistentNaming -gt 0) {
  Write-Host "  Names without convention:"
  $policies | Where-Object { $_.displayName -notmatch "^CA-" } |
    ForEach-Object { Write-Host "    '$($_.displayName)'" }
  Write-Host ""
  Write-Host "  Impact: policies named 'MFA Policy', 'New Policy (1)', or"
  Write-Host "  'Block - DO NOT DELETE' can't be understood from a list view."
  Write-Host "  When troubleshooting, you must click into each policy to"
  Write-Host "  understand what it does. With 20+ policies, this takes minutes"
  Write-Host "  per incident, minutes the attacker is inside the tenant."
}
Write-Host ""

# Symptom 2: Overlapping user scopes without clear layering
$allUsersPolicies = ($policies | Where-Object {
  $_.conditions.users.includeUsers -contains "All"
}).Count
$groupPolicies = ($policies | Where-Object {
  $_.conditions.users.includeGroups.Count -gt 0
}).Count
Write-Host "Symptom 2. User scope overlap potential:"
Write-Host "  Policies targeting All users: $allUsersPolicies"
Write-Host "  Policies targeting specific groups: $groupPolicies"
if ($allUsersPolicies -gt 0 -and $groupPolicies -gt 0) {
  Write-Host "  Both exist, users in targeted groups match BOTH the all-users"
  Write-Host "  policies and the group-specific policies. This is by design in"
  Write-Host "  the layered model (baseline + tiered), but without the layered"
  Write-Host "  model, it creates unpredictable interactions where admins don't"
  Write-Host "  know which controls accumulate."
}
Write-Host ""

# Symptom 3: Mixed grant controls (legacy MFA + auth strength)
$blockPolicies = ($policies | Where-Object {
  $_.grantControls.builtInControls -contains 'block'
}).Count
$strengthPolicies = ($policies | Where-Object {
  $_.grantControls.authenticationStrength
}).Count
$legacyMfaPolicies = ($policies | Where-Object {
  $_.grantControls.builtInControls -contains 'mfa' -and
  -not $_.grantControls.authenticationStrength
}).Count

Write-Host "Symptom 3. Grant control consistency:"
Write-Host "  Block policies: $blockPolicies"
Write-Host "  Authentication strength: $strengthPolicies"
Write-Host "  Legacy 'Require MFA': $legacyMfaPolicies"
if ($legacyMfaPolicies -gt 0 -and $strengthPolicies -gt 0) {
  Write-Host "  ⚠ Mixed: some policies use auth strength, some use legacy MFA."
  Write-Host "    The two controls are mutually exclusive in the same policy."
  Write-Host "    This inconsistency makes future upgrades harder, some policies"
  Write-Host "    can be upgraded by changing the strength ID, others must be"
  Write-Host "    recreated. Migrate all legacy policies to auth strength."
}

The What If tool, your primary design validation tool:

Before deploying any policy, use the What If tool to simulate how it will evaluate for a specific user, app, and device. The What If tool shows which policies match, which controls are required, and whether the user can satisfy them, without affecting any real sign-in.

Entra Admin Center

What If tool:
ProtectionConditional AccessWhat If
Select a user, an application, a device platform, and optionally a sign-in risk level and network location. Click What If. The tool shows every policy that would match this scenario and the combined controls that would be enforced. Use this before every enforcement decision to verify the expected behavior.

Reading your results: A well-designed framework has consistent naming (every policy starts with CA-), intentional user scoping (clear separation between all-users baseline and group-specific policies), and consistent grant controls (all using authentication strength, not a mix of legacy MFA and strength). If your tenant shows mixed symptoms, the design methodology in this sub is the remediation.

The naming convention

Every CA policy name must tell you, at a glance, who it targets, what it does, and what it protects. The naming convention is not optional, it's the primary maintenance tool. When you have 25 policies and a helpdesk ticket says "user can't access Exchange," you need to find the relevant policy instantly. When the security team reviews the CA framework quarterly, they need to understand coverage from the policy list alone without clicking into each policy.

CA-{Scope}-{Action}{Strength}-{Target}

Component    Purpose                            Values
---------    ------                             ------
CA-          Prefix: identifies Conditional     Always "CA-"
             Access policies (vs groups, apps)

{Scope}      WHO this policy targets            All | Admins | Guests | Externals |
                                                Workloads | {GroupName}

{Action}     WHAT the policy requires           Require | Block | Session

{Strength}   WHICH auth strength or control     PhishResistMFA | MFA | CompliantDevice |
             (omitted for Block policies)       ManagedApp | SIF4h | SIF8h

{Target}     WHERE it's enforced                AllApps | AdminPortals | M365Core |
                                                AzureMgmt | SecurityInfo | LegacyAuth |
                                                {AppName}

The convention encodes three dimensions of the MSA3.2 decision matrix: who (Scope corresponds to persona), what (Action + Strength corresponds to the control), and where (Target corresponds to the resource). When a policy name contains CA-Admins-RequirePhishResistMFA-AdminPortals, you know without opening the policy that it targets admin persona accounts, requires phishing-resistant authentication strength as the grant control, and applies to admin portal access.

Design principles behind the naming:

The CA- prefix ensures CA policies sort together in any list and are distinguishable from security groups, app registrations, and other Entra objects that may have similar names. Never name a CA policy without this prefix.

The Scope comes before the Action because the first question during troubleshooting is always "who is affected?", you filter by scope first, then look at what control was applied. CA-Admins-* immediately narrows your search to admin-targeted policies.

Block policies omit the Strength component because block doesn't have a strength, access is denied entirely. Session policies use the session control type as the strength (e.g., SIF4h for 4-hour sign-in frequency).

EXAMPLES:
CA-All-BlockLegacyAuth-AllApps                     Baseline: block all legacy auth
CA-All-RequireMFA-AllApps                          Baseline: MFA for everyone everywhere
CA-All-BlockHighRisk-AllApps                       Baseline: block high-risk sign-ins
CA-Admins-RequirePhishResistMFA-AdminPortals       Tier 1: phishing-resistant for admin portals
CA-Admins-RequireCompliantDevice-AllApps            Tier 1: compliant device for all admin access
CA-Admins-SessionSIF4h-AdminPortals                Session: 4-hour re-auth for admin portals
CA-All-RequirePhishResistMFA-M365Core              Tier 2: phishing-resistant for Exchange/SPO/Teams
CA-Guests-RequireMFA-AllApps                       Guest: MFA for all guest access
CA-Guests-BlockAccess-AdminPortals                 Guest: block guest admin portal access
CA-All-RequirePhishResistMFA-SecurityInfo           Baseline: protect security info registration
CA-Workloads-BlockUntrustedLocations-AllApps        Workload: block workload auth from untrusted IPs

The persona model, designing for populations, not individuals

CA policies target populations, not individual users. This is a design principle, not a technical limitation. You could create a CA policy for each user, but with 810 users, that's 810 policies, each requiring individual maintenance, each a potential misconfiguration. The persona model groups users by their risk profile and access requirements, then applies consistent controls to each group.

Why personas instead of per-user or per-department:

Per-user policies don't scale and can't be audited. Per-department policies create drift: the Finance department's controls diverge from Engineering's for no security reason, just because different admins configured them at different times. Per-role policies (targeting directory roles directly) work for admin tiers but can't express device state or location requirements.

Personas group users by security-relevant characteristics: what they can access (privilege level), how they access it (managed vs unmanaged device), and what threat profile they face (targeted vs commodity attacks). A person in the Finance department on a managed laptop has the same security profile as a person in Engineering on a managed laptop, they should get the same CA controls. A Global Admin has a entirely different threat profile from a standard user regardless of department, they need different controls.

The persona model produces 3–5 population groups that cover every user in the tenant. Each persona maps to a row in the decision matrix and a set of CA policies:

PERSONA          GROUP NAME                    WHY THIS PERSONA EXISTS
Privileged       SG-CA-Persona-Admins          Highest-value targets. Most access.
                                               Most damage if compromised. Need the
                                               strongest controls: phishing-resistant +
                                               compliant device + session restrictions +
                                               block from unmanaged devices.

Standard         (All users minus exclusions)  The workforce. Moderate risk. Broad access
                                               to M365 apps. Controls must balance security
                                               with productivity. Standard MFA baseline,
                                               upgrading to phishing-resistant as readiness
                                               increases.

Guest            (Guest users / external)      External identities. You don't control their
                                               device, their MFA methods, or their home
                                               tenant security. Limited controls: standard
                                               MFA (their home tenant may not support
                                               phishing-resistant), restricted sessions,
                                               no persistent browser.

Break-glass      SG-CA-Exclude-BreakGlass      Emergency access. Excluded from ALL CA
                                               policies. Protected by monitoring and
                                               physical security, not by CA controls.
                                               Must be excluded from every policy —
                                               if any policy matches break-glass,
                                               the emergency access mechanism breaks.

Exception        SG-CA-Exclude-{Reason}        Temporary exclusion for documented
                                               exceptions. Each exception group has a
                                               named reason, a review date, and a sunset
                                               date. MSA3.10 covers exception management.

How personas interact with the baseline: The baseline (MSA3.3) targets "All users", including all personas. The tiered policies (MSA3.4) add stronger controls for the Admin and Guest personas on top of the baseline. A Global Admin accessing Exchange Online matches both the baseline policy (MFA for all apps) and the admin tiered policy (phishing-resistant + compliant device). Both sets of controls apply: the admin satisfies the phishing-resistant requirement (which is stronger than standard MFA) and the compliant device requirement.

Creating the persona groups

The persona groups are security groups that you'll reference in every CA policy. Create them before any policy to ensure consistent targeting. Each group has a specific population rule, who goes in and who doesn't.

$personaGroups = @(
  @{
    Name = "SG-CA-Persona-Admins"
    Description = "Privileged admin persona, highest CA controls. Members: all accounts with admin directory roles (Global Admin, Security Admin, Exchange Admin, SharePoint Admin, etc.)."
  },
  @{
    Name = "SG-CA-Exclude-BreakGlass"
    Description = "Break-glass emergency access, excluded from ALL CA policies. Members: exactly 2 break-glass accounts. Never add regular admin accounts to this group."
  },
  @{
    Name = "SG-CA-Exclude-LegacyAuth"
    Description = "Temporary legacy auth exception, accounts that must use legacy protocols during migration. Each member documented with residual risk template. Quarterly review."
  },
  @{
    Name = "SG-CA-Exclude-DeviceCompliance"
    Description = "Temporary device compliance exception, users on devices not yet enrolled in Intune. Sunset when device enrollment completes."
  }
)

foreach ($pg in $personaGroups) {
  $existing = Get-MgGroup -Filter "displayName eq '$($pg.Name)'" -ErrorAction SilentlyContinue
  if ($existing) {
    $memberCount = (Get-MgGroupMember -GroupId $existing.Id -All).Count
    Write-Host "✓ $($pg.Name) exists — $memberCount members"
  } else {
    $new = New-MgGroup -DisplayName $pg.Name -Description $pg.Description `
      -MailEnabled:$false -MailNickname ($pg.Name -replace '[^a-zA-Z0-9]','') `
      -SecurityEnabled:$true
    Write-Host "✓ Created $($pg.Name)"
  }
}

Population rules, who goes in each group:

The Admin persona group should contain every account that holds a privileged directory role: Global Administrator, Security Administrator, Exchange Administrator, SharePoint Administrator, User Administrator, Helpdesk Administrator, Intune Administrator, and any other role that can modify tenant-wide configuration or access sensitive data. Use PIM-eligible role holders, not just active assignments: an account that can activate Global Admin should be in this group even when the role isn't active, because the CA policy must evaluate every sign-in from that account, not just the ones when the role is activated.

The Break-glass group contains exactly two accounts: no more, no fewer. These are the emergency access accounts from MSA1.12. Adding a third account or adding a regular admin account to this group weakens the emergency access mechanism and potentially bypasses CA controls for non-emergency accounts. Review membership monthly.

The Exception groups start empty. Members are added only when a documented exception is created (MSA3.10). Every member must have a corresponding residual risk entry in the architecture package with a named owner, a review date, and a sunset date.

Entra Admin Center

Verify persona groups:
IdentityGroupsAll groups → search "SG-CA"
Each group should appear with the correct description. Click each group → Members to verify membership. The Admin persona group should contain all privileged accounts. The Break-glass group should contain exactly 2 accounts. Exception groups should be empty unless documented exceptions exist.

The decision matrix, mapping personas to controls

The decision matrix is the core design tool. It maps every combination of persona, device state, and resource sensitivity to specific CA controls. The matrix is exhaustive: every cell must have a defined control. An empty cell is a coverage gap.

PERSONA     DEVICE STATE    RESOURCE            AUTH STRENGTH         DEVICE CONTROL     SESSION
---------   -------------   ------------------  -------------------   ----------------   --------
Admin       Compliant       Admin portals       Phishing-resistant    Required           SIF 4h
Admin       Compliant       All other apps      Phishing-resistant    Required           Default
Admin       Unmanaged       Admin portals       BLOCKED                                  
Admin       Unmanaged       All other apps      BLOCKED                                  

Standard    Compliant       Core M365           Phishing-resistant*   Preferred          Default
Standard    Compliant       All other apps      Standard MFA          Preferred          Default
Standard    Unmanaged       Core M365           Phishing-resistant*   App protection     SIF 8h
Standard    Unmanaged       All other apps      Standard MFA          App protection     SIF 8h

Guest       Any             All apps            Standard MFA          —                  No persist
Guest       Any             Admin portals       BLOCKED                                  

Break-glass Any             Any                 NO CA EVALUATION (excluded from all policies)

* Phase 3 of the passwordless roadmap, enforce when readiness > 80%

How to read the matrix: a worked scenario:

Scenario: the security architect (the security architect) signs in to the Azure portal from his company-issued, Intune-managed, compliant Windows laptop at the office.

  1. Who is Marcus? He's a member of SG-CA-Persona-Admins (Security Admin role). Persona = Admin.
  2. What device? Company laptop, Intune-managed, marked compliant. Device state = Compliant.
  3. What resource? Azure portal (797f4846-ba00-4fd7-ba43-dac1f8f63013). Resource = Admin portals.
  4. Find the row: Admin × Compliant × Admin portals → Auth Strength: Phishing-resistant, Device Control: Required, Session: SIF 4h.
  5. What policies match? The baseline (CA-All-RequireMFA-AllApps) + the admin tiered policy (CA-Admins-RequirePhishResistMFA-AdminPortals) + the admin device policy (CA-Admins-RequireCompliantDevice-AllApps) + the session policy (CA-Admins-SessionSIF4h-AdminPortals).
  6. Combined result: Marcus must authenticate with a phishing-resistant method (his FIDO2 key), from a compliant device (his managed laptop satisfies this), and will be re-prompted every 4 hours.

Now change one variable: Marcus signs in from his personal iPhone (unmanaged, not enrolled in Intune).

  1. Persona = Admin. Device = Unmanaged. Resource = Admin portals.
  2. Find the row: Admin × Unmanaged × Admin portals → BLOCKED.
  3. Marcus can't access the Azure portal from his personal phone. The policy blocks the sign-in regardless of how strong his authentication is. This is the architectural decision: admin portal access from unmanaged devices is not a risk the organization accepts.

Adapting the matrix to your environment: Fill in the matrix based on your Module 2 outputs. If your passkey readiness is below 50%, the "Phishing-resistant*" cells should say "Standard MFA" for now with a note they'll be upgraded in Phase 3. If you don't have Intune (no device compliance), remove the "Compliant" vs "Unmanaged" distinction for standard users: all their sign-ins follow the "Unmanaged" row. If you don't have E5 (no risk-based policies), note that the baseline high-risk block can't be deployed.

The four-layer architecture

The matrix translates into CA policies through four layers, each building on the previous:

Layer 1. Baseline (MSA3.3). Policies that apply to all users, all apps, with no exceptions except break-glass. These establish the minimum security floor: block legacy auth, require MFA for all, block high-risk sign-ins. Every sign-in hits at least these policies. The baseline closes the default-allow gap from MSA3.1.

Layer 2. Tiered access (MSA3.4). Policies that apply to specific personas accessing specific resources. Admin portal policies with phishing-resistant strength. Guest policies with standard MFA and session restrictions. These layer on top of the baseline: a user who is both in "All users" (baseline) and "Admin" (tiered) gets both sets of controls.

Layer 3. App-specific and device-specific (MSA3.5–3.6). Policies that apply additional controls for high-value applications (Exchange Online, SharePoint, Azure management) or based on device state (compliant device required, app protection for unmanaged). These are the most granular policies.

Layer 4. Exception and session (MSA3.7–3.10). Named location exceptions, emergency access, sign-in frequency, and documented exceptions. These modify the behavior of Layers 1–3 for specific scenarios.

Layer 4: Exception + Session  ─── named locations, break-glass, SIF, exceptions
Layer 3: App + Device         ─── Exchange, SharePoint, Azure, compliant device
Layer 2: Tiered Access        ─── admin portals, guest restrictions
Layer 1: Baseline             ─── block legacy, require MFA, block high risk
                              ═══════════════════════════════════════════════
                              DEFAULT ALLOW (no policy matches → no controls)

The baseline sits directly above the default-allow. Every sign-in that doesn't match a more specific policy at Layer 2–4 still matches the baseline at Layer 1. The framework has no coverage gaps because the baseline catches everything.

# Classify your existing policies by layer
Write-Host "=== POLICY LAYER CLASSIFICATION ==="
foreach ($p in $policies | Sort-Object displayName) {
  $layer = if ($p.conditions.clientAppTypes -contains 'other' -or
              $p.conditions.clientAppTypes -contains 'exchangeActiveSync') {
    "L1-Baseline (legacy block)"
  } elseif ($p.conditions.users.includeUsers -contains "All" -and
            $p.conditions.applications.includeApplications -contains "All" -and
            -not $p.conditions.users.includeGroups) {
    "L1-Baseline (all users, all apps)"
  } elseif ($p.conditions.users.includeGroups -or $p.conditions.users.includeRoles) {
    "L2-Tiered (specific population)"
  } elseif ($p.conditions.applications.includeApplications -and
            $p.conditions.applications.includeApplications -notcontains "All") {
    "L3-App-specific"
  } else {
    "L4-Exception/Session"
  }
  Write-Host "  [$layer] $($p.displayName) ($($p.state))"
}

Reading your results: If all your policies classify as L2 or L3 with no L1 policies, you have no baseline: the default-allow gap is open. If you have L1 policies but no L2, everyone gets the same controls regardless of risk level. A mature framework has policies at all four layers.

Fill in the decision matrix for your tenant: how many admins, standard users, guests, and break-glass accounts? What controls does each persona require? What is your planned policy count (typically 12-15 for a mature framework: 4 baseline + 4 tiered + 3 app-specific + exceptions)? What is your current state, how many policies exist and in what mode?

Anti-Pattern

Policy names like "MFA Policy," "New Policy (1)," "Block. DO NOT DELETE," and "Test. John." Nobody can explain the coverage. The security team wants to add a new requirement but is afraid to change anything because they don't understand the existing interactions. Every new requirement gets a new policy because modifying existing policies is too risky. The policy count grows to 30+, each a point solution, with overlapping conditions and conflicting controls. The fix: start with the naming convention and the decision matrix. Map every existing policy to a cell in the matrix. Identify the gaps. Consolidate overlapping policies. Name everything consistently. Then maintain the framework as a system, not a collection of individual policies.

Before moving on, verify your understanding: Run the ad-hoc design symptom check. Does your tenant have a consistent naming convention? Are grant controls consistent (all authentication strength, or a mix)? Create the persona groups. Verify each group exists and is correctly described. Which user accounts should be in the Admin persona group? Which accounts should be in the break-glass exclusion?


Reusable script: the commands from this sub assembled for operational use:

Copy your design framework to 03-conditional-access/ca-design-framework.md. Include: the naming convention, the persona definitions with group names, the completed decision matrix, the layer classification of existing policies, and the gap analysis (which matrix cells don't have a corresponding policy). This framework is the blueprint for MSA3.3–3.13: every policy designed in the remaining subs maps to a cell in this matrix.