In this section
MSA3.3 The Baseline Policy Set
You understand the CA evaluation engine (MSA3.1) and the design methodology (MSA3.2). You know the default-allow model means any sign-in that matches no policy gets no controls. You know the four-layer architecture uses a baseline to close this gap. This sub builds Layer 1: the minimum policies that every M365 tenant needs regardless of size, industry, or licensing. These policies target all users and all apps. They establish the security floor that no sign-in can fall below. Every subsequent policy in Layers 2–4 adds requirements on top of this baseline.
Without a baseline, your CA framework has a floor made of glass. Every sign-in that doesn't match a specific Layer 2–4 policy falls through to the default-allow: no MFA, no risk evaluation, no legacy block. The baseline is five policies that ensure: no legacy protocol bypasses MFA, every sign-in requires at least standard MFA, high-risk sign-ins are blocked regardless of other controls, Azure management requires MFA, and MFA registration itself is protected. These five policies take 30 minutes to deploy and close the most dangerous coverage gaps in any tenant. Every policy in this sub uses the naming convention from MSA3.2, targets the break-glass exclusion group, and starts in report-only mode.
Estimated time: 45 minutes.
The five baseline policies
Every baseline policy follows the same pattern: target All users, exclude break-glass, target All apps (or a specific action), and enforce one control. The policies are simple by design, baseline policies should be understandable at a glance. Complexity belongs in Layer 2–4.
Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess","Policy.Read.All"
# Get break-glass group ID
$bgGroup = Get-MgGroup -Filter "displayName eq 'SG-CA-Exclude-BreakGlass'"
if (-not $bgGroup) {
Write-Host "⚠ Break-glass group not found. Create it before deploying baseline policies."
Write-Host " Every baseline policy excludes this group, without it, you risk locking"
Write-Host " yourself out of the tenant."
return
}
$bgId = $bgGroup.Id
# Get authentication strength IDs
$strengths = (Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/authenticationStrength/policies?`$filter=policyType eq 'builtIn'" `
-OutputType PSObject).value
$mfaStrengthId = ($strengths | Where-Object { $_.displayName -eq "Multifactor authentication" }).id
$phishResistId = ($strengths | Where-Object { $_.displayName -eq "Phishing-resistant MFA" }).id
Write-Host "Break-glass group: $bgId"
Write-Host "MFA strength ID: $mfaStrengthId"
Write-Host "Phishing-resistant ID: $phishResistId"Baseline 1. Block legacy authentication
Why this is first and why it's the most important baseline policy: Legacy authentication protocols (SMTP AUTH, POP3, IMAP4, EAS with basic auth) are the back door in your CA framework. These protocols authenticate with username + password in a single request-response. There is no mechanism in the protocol to inject an MFA challenge, an authentication strength requirement, a device compliance check, or a risk evaluation. A CA policy that requires phishing-resistant MFA for all users accessing all apps is completely irrelevant for a sign-in via SMTP AUTH: the legacy protocol never encounters the CA evaluation for MFA because the legacy client app type condition is separate from the MFA grant condition.
This means the legacy auth block is the architectural prerequisite for every other baseline policy. If legacy auth isn't blocked, an attacker with stolen credentials can authenticate via SMTP AUTH, POP3, or IMAP4 and bypass your MFA requirement, your authentication strength requirement, your device compliance requirement, and your risk evaluation: all of them. The 14-day report-only assessment from MSA2.5 identifies dependencies. After assessment, this policy must be the first to move to enforced.
You may already have this from MSA2.11's lab. If so, verify it's still configured correctly:
$b1 = @{
displayName = "CA-All-BlockLegacyAuth-AllApps"
state = "enabledForReportingButNotEnforced"
conditions = @{
users = @{
includeUsers = @("All")
excludeGroups = @($bgId)
}
applications = @{ includeApplications = @("All") }
clientAppTypes = @("exchangeActiveSync", "other")
}
grantControls = @{
builtInControls = @("block")
operator = "OR"
}
} | ConvertTo-Json -Depth 5
$existing = (Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-OutputType PSObject).value |
Where-Object { $_.displayName -eq "CA-All-BlockLegacyAuth-AllApps" }
if ($existing) {
Write-Host "✓ CA-All-BlockLegacyAuth-AllApps exists ($($existing.state))"
if ($existing.state -eq "enabled") {
Write-Host " ✓ ENFORCED, legacy auth is blocked for all users"
} else {
Write-Host " ◐ Report-only, legacy auth is logged but NOT blocked"
Write-Host " Action: review CA Insights for 14 days, then enforce"
}
} else {
Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-Body $b1
Write-Host "✓ Created: CA-All-BlockLegacyAuth-AllApps (report-only)"
}The exception handling for Baseline 1: If the report-only assessment reveals dependencies (printers, scripts, LOB applications), don't delay enforcement indefinitely. Create a narrowly scoped exception using a named location (the printer's IP) and a dedicated service account, document it with the residual risk template from MSA2.5, and enforce the block for all other traffic. MSA3.10 covers exception management in detail.
Baseline 2. Require MFA for all users, all apps
Why this exists: This is the coverage floor. Every sign-in that doesn't match a more specific Layer 2–4 policy still matches this policy and requires at least standard MFA. Without this policy, any user not covered by a more specific policy authenticates with password only: the weakest possible authentication. The baseline MFA policy transforms CA from opt-in (only users in targeted groups get MFA) to opt-out (everyone gets MFA unless explicitly excluded).
$b2 = @{
displayName = "CA-All-RequireMFA-AllApps"
state = "enabledForReportingButNotEnforced"
conditions = @{
users = @{
includeUsers = @("All")
excludeGroups = @($bgId)
}
applications = @{ includeApplications = @("All") }
}
grantControls = @{
authenticationStrength = @{ id = $mfaStrengthId }
operator = "OR"
}
} | ConvertTo-Json -Depth 5
$existing = (Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-OutputType PSObject).value |
Where-Object { $_.displayName -eq "CA-All-RequireMFA-AllApps" }
if ($existing) {
Write-Host "✓ CA-All-RequireMFA-AllApps already exists ($($existing.state))"
} else {
Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-Body $b2
Write-Host "✓ Created: CA-All-RequireMFA-AllApps (report-only)"
}Why authentication strength instead of "Require MFA": This policy uses the built-in "Multifactor authentication" strength, which is functionally equivalent to the legacy "Require multifactor authentication" grant control. The difference is architectural: authentication strength is the grant control that supports future upgrades. When your passkey readiness exceeds 80% (Phase 3 of the passwordless roadmap), you modify this policy's authenticationStrength.id from the standard MFA strength to the phishing-resistant strength. The policy target, the exclusions, the conditions: all stay the same. Only the strength ID changes. If you'd used the legacy "Require MFA" control, you'd need to recreate the policy because "Require MFA" and "Require authentication strength" are mutually exclusive in the same policy.
This is the policy lifecycle advantage of building on authentication strength from day one: every baseline policy is upgrade-ready without structural changes.
Entra Admin Center
Protection → Conditional Access → + New policy
Name: CA-All-RequireMFA-AllApps
Users: All users, Exclude: SG-CA-Exclude-BreakGlass
Cloud apps: All cloud apps
Grant: Require authentication strength → select Multifactor authentication (not "Require multifactor authentication", they're different controls)
Enable policy: Report-only
Baseline 3. Block high-risk sign-ins
Why this exists: Identity Protection assigns a risk level to every sign-in based on real-time signals: impossible travel, unfamiliar sign-in properties, anomalous token properties, suspicious browser behavior. A high-risk sign-in is one where Identity Protection has strong evidence that the authentication is not legitimate. Blocking high-risk sign-ins prevents the most obvious compromises, stolen credentials used from an unfamiliar location, token replay from a different country, or anomalous sign-in patterns that match known attack campaigns.
$b3 = @{
displayName = "CA-All-BlockHighRisk-AllApps"
state = "enabledForReportingButNotEnforced"
conditions = @{
users = @{
includeUsers = @("All")
excludeGroups = @($bgId)
}
applications = @{ includeApplications = @("All") }
signInRiskLevels = @("high")
}
grantControls = @{
builtInControls = @("block")
operator = "OR"
}
} | ConvertTo-Json -Depth 5
Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-Body $b3
Write-Host "✓ Created: CA-All-BlockHighRisk-AllApps (report-only)"The risk-level design decision: This policy blocks high risk only, not medium or low. Medium-risk sign-ins are common during legitimate travel, VPN use, or from new devices, blocking them creates excessive friction. The Layer 2 tiered policy (MSA3.4) handles medium-risk by requiring re-authentication with a stronger method rather than blocking. High-risk sign-ins have sufficient evidence to justify a hard block.
Licensing requirement: Sign-in risk evaluation requires Entra ID P2 (included in E5, available as an add-on for E3). Without P2, the signInRiskLevels condition is unavailable and this policy can't be created. If your tenant doesn't have P2, skip this policy and note it as a residual risk in the architecture package.
Security on a Budget. E3 vs E5
Risk-based CA policies require Entra ID P2 (E5 or P2 add-on). E3 tenants can create baselines 1, 2, 4, and 5 but not baseline 3 (high-risk block). Without risk-based policies, compromised credential sign-ins aren't automatically blocked, they pass through the baseline MFA policy. If the attacker has the user's password and can satisfy MFA (e.g., through AiTM), they get access. Entra ID P2 costs $9/user/month as a standalone add-on. For an 810-user organization, that's $6,913/month, significant. The E5 bundle includes P2 and is often more cost-effective than stacking add-ons. MSA3.13 calculates the organization's specific licensing trade-off.
Baseline 4. Require MFA for Azure management
Why this is separate from Baseline 2: On the surface, Baseline 2 (MFA for all users, all apps) already covers Azure management. An admin accessing the Azure portal matches Baseline 2 and must complete MFA. So why create a separate policy?
Three architectural reasons.
First: future-proofing for strength upgrades. When you upgrade Baseline 2's authentication strength from standard MFA to phishing-resistant (Phase 3 of the roadmap), you may need Azure management to remain at standard MFA temporarily. Some automation tools, service accounts, or scripts that access Azure Resource Manager via modern auth may not support phishing-resistant methods. Having a separate Azure management policy gives you independent control over the strength requirement for this high-value resource class.
Second: Microsoft's own enforcement. Microsoft has been rolling out mandatory MFA enforcement for Azure portal access since 2024, with completion through 2026. This enforcement applies regardless of your CA policies, it's a platform-level control. Having your own CA policy for Azure management ensures you control the enforcement parameters (which strength, which exclusions, what session controls) rather than relying on Microsoft's defaults. Your policy may be more restrictive than Microsoft's, which is the correct posture.
Third: explicit documentation and auditability. When an auditor asks "how is Azure management access protected?", pointing to a named policy (CA-All-RequireMFA-AzureMgmt) is cleaner than explaining "it's implicitly covered by our all-apps baseline." Explicit policies are easier to audit, easier to verify, and harder to accidentally weaken.
$b4 = @{
displayName = "CA-All-RequireMFA-AzureMgmt"
state = "enabledForReportingButNotEnforced"
conditions = @{
users = @{
includeUsers = @("All")
excludeGroups = @($bgId)
}
applications = @{
includeApplications = @(
"797f4846-ba00-4fd7-ba43-dac1f8f63013" # Azure portal
)
}
}
grantControls = @{
authenticationStrength = @{ id = $mfaStrengthId }
operator = "OR"
}
} | ConvertTo-Json -Depth 5
Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-Body $b4
Write-Host "✓ Created: CA-All-RequireMFA-AzureMgmt (report-only)"Entra Admin Center
Instead of targeting the Azure portal app ID specifically, you can target the Windows Azure Service Management API (
797f4846-ba00-4fd7-ba43-dac1f8f63013) which covers the Azure portal, Azure CLI, Azure PowerShell, and Azure mobile app. This provides broader coverage for all Azure management surfaces, not just the web portal. In the portal: Cloud apps → Select apps → search "Windows Azure Service Management."Baseline 5. Protect security info registration
Why this exists: MSA2.8 documented the SSPR security gap. An attacker who compromises a password (through SSPR reset, credential theft, or password spray) can navigate to My Security Info and register a new MFA method, including a passkey, on the compromised account. Without this policy, the registration action requires no additional verification beyond the current session. The attacker who just reset the password has a valid session and can register any method they want.
This policy requires phishing-resistant MFA before allowing MFA method registration. The attacker can't register a new passkey because registering requires a passkey they don't have. The attack chain from MSA2.8 breaks at step 6 (register new method) instead of proceeding to step 8 (sign in as the user).
$b5 = @{
displayName = "CA-All-RequirePhishResistMFA-SecurityInfo"
state = "enabledForReportingButNotEnforced"
conditions = @{
users = @{
includeUsers = @("All")
excludeGroups = @($bgId)
}
userActions = @{
includeUserActions = @("urn:user:registersecurityinfo")
}
}
grantControls = @{
authenticationStrength = @{ id = $phishResistId }
operator = "OR"
}
} | ConvertTo-Json -Depth 5
Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-Body $b5
Write-Host "✓ Created: CA-All-RequirePhishResistMFA-SecurityInfo (report-only)"The bootstrap problem and its solution:
This policy creates a dependency: you need a phishing-resistant method to register a phishing-resistant method. For users who already have a passkey or FIDO2 key, the policy works perfectly, they authenticate with their existing passkey to register a second one. For new users or users who haven't registered a passkey yet, the policy creates a catch-22: they can't register a passkey because registering requires a passkey they don't have.
The solution is Temporary Access Pass (TAP), configured in MSA2.3 and MSA2.11. The bootstrap flow:
- Admin issues a TAP to the new user (60-minute, one-time-use).
- User signs in with the TAP (enters the TAP value instead of a password).
- User navigates to My Security Info → Add sign-in method → Passkey.
- This CA policy evaluates: does the current session satisfy phishing-resistant MFA?
- TAP satisfies the MFA requirement (TAP is treated as a multi-factor credential). Whether TAP satisfies phishing-resistant strength depends on the strength configuration, by default, TAP may not satisfy phishing-resistant. If it doesn't, the admin can temporarily set this policy to standard MFA strength during the registration window, then upgrade to phishing-resistant after registration completes.
- User registers their passkey successfully.
- For future method registrations, the user authenticates with their passkey (satisfies phishing-resistant).
The deployment sequence for Baseline 5: Deploy in report-only during the passkey registration phase (MSA2.4 Phase 2). The report-only period shows how many users would be blocked by this policy, these are users who need passkey registration before the policy can be enforced. When passkey readiness exceeds 50%, switch to enforced and use TAP for any remaining users who need to bootstrap their first passkey.
Entra Admin Center
Protection → Conditional Access → + New policy
Name: CA-All-RequirePhishResistMFA-SecurityInfo
Users: All users, Exclude: SG-CA-Exclude-BreakGlass
User actions (not Cloud apps): select Register security information
Grant: Require authentication strength → Phishing-resistant MFA
Enable policy: Report-only
Note: This policy targets a user action, not a cloud app. In the portal, switch from "Cloud apps" to "User actions" in the Target resources section.
Verifying the complete baseline
$policies = (Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
-OutputType PSObject).value
$baseline = $policies | Where-Object { $_.displayName -match "^CA-All-" }
Write-Host "=== BASELINE VERIFICATION ==="
Write-Host "Total baseline policies: $($baseline.Count)"
Write-Host ""
$expected = @(
"CA-All-BlockLegacyAuth-AllApps",
"CA-All-RequireMFA-AllApps",
"CA-All-BlockHighRisk-AllApps",
"CA-All-RequireMFA-AzureMgmt",
"CA-All-RequirePhishResistMFA-SecurityInfo"
)
foreach ($name in $expected) {
$found = $baseline | Where-Object { $_.displayName -eq $name }
if ($found) {
Write-Host " ✓ $name ($($found.state))"
} else {
Write-Host " ⚠ MISSING: $name"
}
}
Write-Host ""
$enforced = ($baseline | Where-Object { $_.state -eq "enabled" }).Count
$reportOnly = ($baseline | Where-Object { $_.state -eq "enabledForReportingButNotEnforced" }).Count
Write-Host "Enforced: $enforced | Report-only: $reportOnly"
if ($reportOnly -gt 0) {
Write-Host " $reportOnly policies still in report-only."
Write-Host " Review CA Insights to assess impact, then enforce sequentially."
Write-Host " Enforce in this order: legacy block → MFA for all → high-risk block"
Write-Host " → Azure mgmt → security info protection"
}The enforcement sequence matters: Enforce the legacy auth block first, it has the narrowest impact (only legacy clients are affected) and it's the prerequisite for every other policy. Then enforce MFA for all (the broadest impact: every user without MFA is prompted). Then the high-risk block (requires P2, low volume of affected sign-ins). Then Azure management. Finally, the security info registration policy (enforce only after passkey registration is complete for the targeted population).
Enforcement staging timeline
The baseline policies don't all go live on the same day. Each has a different impact radius and a different dependency chain. This timeline sequences the enforcement to minimize disruption while closing gaps as quickly as possible.
WEEK ACTION IMPACT PREREQUISITE
------ ------------------------------------ -------------------------------- -------------------------
1-2 B1: Block legacy auth Legacy clients blocked. 14-day report-only complete.
→ report-only → enforced Printers/scripts in exception Dependencies documented.
group.
3 B2: Require MFA for all Users without MFA prompted on B1 enforced (legacy auth
→ report-only → enforced next sign-in. Helpdesk spike can't bypass the MFA req).
for 1-2 weeks as stragglers MFA registration at 90%+.
register.
4 B4: Require MFA for Azure mgmt Minimal additional impact. B2 B2 enforced (already
→ enforced already requires MFA for all covered by all-apps MFA).
apps. This policy is explicit
coverage for Azure.
5 B3: Block high-risk sign-ins Low volume. Identity Protection Entra ID P2 license.
→ report-only → enforced flags few sign-ins as high-risk B2 enforced (MFA is the
in most tenants. Review primary defense; risk-
report-only results for based block is the
false positives. secondary).
6-12 B5: Protect security info reg Users must have phishing- Passkey registration at
→ report-only → enforced resistant method BEFORE they 50%+ (enough users have
(after Phase 2 passkey rollout) can register new methods. a passkey to satisfy the
Deploy after majority of users requirement). TAP
have completed passkey available for bootstrap.
registration.The timeline is elastic. Week 1 might take 3 weeks if legacy auth dependencies need more assessment. Week 6-12 might be month 6 if passkey registration is slow. The sequence is fixed. B1 before B2, B2 before B3, passkey readiness before B5. The sequence ensures each policy is effective before the next is enforced, and the most impactful policies (legacy block, MFA for all) are enforced first.
After deploying your baseline policies, track each one through the enforcement lifecycle. Legacy auth block should reach enforcement first (after the assessment identifies legitimate legacy sources). MFA for all users is next (most users should already have MFA registered from MSA2). Risk-based and Azure management policies may stay in report-only longer until you have confidence in the signal quality.
Anti-Pattern
The tenant has 12 CA policies but no baseline. Five target specific groups for specific apps. Three target admin roles. Two target guest users. Two are disabled. No policy targets "all users + all apps." Result: 127 users (in no targeted group) authenticate with password only. The 127 users include 3 service desk analysts, 8 new hires not yet added to groups, and 116 users who were removed from groups during a restructure. None of them have MFA enforced. The baseline policy takes 5 minutes to create and closes the gap for all 127 immediately.
Before moving on, verify your understanding: Run the baseline verification query. Do all five baseline policies exist? Which are report-only and which are enforced? If any are missing, explain why they're missing and what risk this creates. Explain why the legacy auth block (Baseline 1) must be enforced before the MFA baseline (Baseline 2). What happens if you enforce MFA first but don't block legacy auth?
Reusable script: the commands from this sub assembled for operational use:
Document the baseline policy set in 03-conditional-access/baseline-policies.md. Include: each policy's name, state, grant control, authentication strength ID, exclusion group, and the enforcement sequence with dates. This document is referenced by MSA3.11 (compliance evidence: the baseline policies are the primary controls that auditors verify) and MSA3.13 (the organization's complete framework uses the baseline as Layer 1).