Skip to content

Entra Conditional Access Audit & Gap Analysis

CLOUD PERIMETER SIGNINLOGS & GRAPH API Standard: Zero Trust Architecture

In a cloud-native organization, Microsoft Entra Conditional Access (CA) is the intelligent policy engine that replaces traditional firewalls. If an attacker bypasses CA, they gain access to Microsoft 365, SharePoint, and Azure workloads.


🕳️ Master Conditional Access Blindspots Matrix

Section titled “🕳️ Master Conditional Access Blindspots Matrix”
Blindspot VectorRisk & Exploitation MethodHardening Recommendation
IPv6 Named Location GapsCA policies configure IPv4 ranges but omit IPv6, allowing attackers to route through IPv6 proxies to appear “on-network”Ensure all trusted named locations include full dual-stack IPv4 and IPv6 CIDR blocks
Legacy Authentication ProtocolsIMAP, POP3, SMTP, and older PowerShell endpoints cannot enforce MFA challengesConfigure a dedicated CA policy blocking client apps: Exchange ActiveSync clients and Other clients
Device Registration ExclusionDevice join/registration endpoints (urn:user:registerdevice) excluded from MFARequire MFA for all device enrollment and compliance registration
Guest & External Account ExemptionsPartner or B2B guest accounts excluded from baseline controls, allowing single-factor entryEnforce cross-tenant access settings and require external users to satisfy MFA
Overbroad Exclusion GroupsAdministrative or break-glass groups contain stale or test user accountsAudit exclusion group memberships weekly via automated PowerShell

🔎 Troubleshooting KQL: Why Did a Sign-in Bypass MFA?

Section titled “🔎 Troubleshooting KQL: Why Did a Sign-in Bypass MFA?”

When triaging a risky sign-in alert, use this KQL query to inspect the exact evaluation result for every applied policy:

SigninLogs
| where TimeGenerated > ago(24h)
| where UserPrincipalName =~ "victim.user@company.com"
| mv-expand ConditionalAccessPolicies
| extend
PolicyName = tostring(ConditionalAccessPolicies.displayName),
PolicyResult = tostring(ConditionalAccessPolicies.result),
EnforcedGrantControls = tostring(ConditionalAccessPolicies.enforcedGrantControls),
EnforcedSessionControls = tostring(ConditionalAccessPolicies.enforcedSessionControls)
| project TimeGenerated, UserPrincipalName, IPAddress, Location, AppDisplayName,
ClientAppUsed, PolicyName, PolicyResult, EnforcedGrantControls
| where PolicyResult in ("notApplied", "failure", "success")
| order by TimeGenerated desc

Hunting Sign-ins Missing Strong Authentication

Section titled “Hunting Sign-ins Missing Strong Authentication”
SigninLogs
| where TimeGenerated > ago(7d)
| where ResultType == 0 // Successful logon
| where AuthenticationRequirement =~ "singleFactorAuthentication"
| where AppDisplayName in ("Office 365 Exchange Online", "Microsoft Teams", "Azure Portal")
| summarize Count = count(), UniqueUsers = dcount(UserPrincipalName), SampleUsers = make_set(UserPrincipalName, 5) by AppDisplayName, ClientAppUsed, IPAddress
| order by Count desc

⚡ PowerShell: Rapid Conditional Access Inventory

Section titled “⚡ PowerShell: Rapid Conditional Access Inventory”

Run this script to export all Conditional Access policies, their current enforcement state, and targeted cloud apps:

Terminal window
# Connect to Microsoft Graph
# Connect-MgGraph -Scopes "Policy.Read.All"
$policies = Get-MgIdentityConditionalAccessPolicy
$report = foreach ($p in $policies) {
[PSCustomObject]@{
DisplayName = $p.DisplayName
State = $p.State
UsersIncluded = ($p.Conditions.Users.IncludeUsers -join ", ")
UsersExcluded = ($p.Conditions.Users.ExcludeUsers -join ", ")
GroupsExcluded = ($p.Conditions.Users.ExcludeGroups -join ", ")
AppsIncluded = ($p.Conditions.Applications.IncludeApplications -join ", ")
GrantControls = ($p.GrantControls.BuiltInControls -join ", ")
SessionControls = ($p.SessionControls | Out-String).Trim()
}
}
$report | Format-Table -AutoSize
# Export to CSV: $report | Export-Csv -Path "C:\Forensics\CA_Policy_Audit.csv" -NoTypeInformation