Safeguard
Cloud Security

How to configure Azure AD Conditional Access policies

A step-by-step guide to configure Azure AD conditional access policies safely — MFA enforcement, device compliance, report-only piloting, and troubleshooting tips.

Karan Patel
Cloud Security Engineer
7 min read

Conditional Access is the policy engine that decides, in real time, whether a sign-in to Microsoft 365, Azure, or any Azure AD-integrated app should be allowed, blocked, or challenged for additional proof. For most organizations, the gap isn't awareness — it's execution. Teams either leave Security Defaults on and get an all-or-nothing MFA experience, or they try to configure Azure AD conditional access from scratch and end up with overlapping rules, an accidental lockout, or gaps that leave service accounts and legacy protocols exposed. This guide walks through a safe, repeatable azure conditional access setup: from auditing your current baseline, through building layered policies with report-only testing, to verifying enforcement without breaking access for your help desk, your break-glass accounts, or your CI/CD pipelines. By the end, you'll have a production-ready policy set and a checklist for keeping it that way as your tenant grows.

Step 1: Audit Your Current State and Disable Security Defaults (If Needed)

Before you write a single policy, find out what's already enforcing controls in your tenant. Many tenants — especially newer ones — have Azure AD security defaults turned on automatically. Security Defaults give you free baseline protection (MFA for all users, blocking legacy authentication) but they're a blunt instrument: no exceptions, no risk-based logic, no way to scope by app or group.

Check the current state:

Connect-MgGraph -Scopes "Policy.Read.All"
Get-MgPolicyIdentitySecurityDefaultEnforcementPolicy | Select-Object IsEnabled

If IsEnabled returns true and you intend to replace it with granular Conditional Access, disable it only after you have at least one equivalent Conditional Access policy live (see Step 3) — never disable Security Defaults with nothing in place behind it:

Update-MgPolicyIdentitySecurityDefaultEnforcementPolicy -IsEnabled:$false

Also inventory existing Conditional Access policies so you don't duplicate or conflict with them:

Get-MgIdentityConditionalAccessPolicy | Select-Object DisplayName, State

Step 2: Create Break-Glass Accounts and Named Locations

Every Conditional Access rollout needs an escape hatch. Create at least two cloud-only emergency access accounts excluded from every policy, with long, randomly generated passwords stored in a physical safe or a secrets vault outside Azure AD itself. Monitor sign-ins to these accounts with alerting — they should never be used except during an actual lockout.

Next, define named locations for trusted IP ranges (corporate offices, VPN egress points) in Azure AD > Security > Conditional Access > Named locations, or via Graph:

New-MgIdentityConditionalAccessNamedLocation -DisplayName "Corporate HQ" `
  -AdditionalProperties @{
    "@odata.type" = "#microsoft.graph.ipNamedLocation"
    isTrusted = $true
    ipRanges = @(@{ "@odata.type" = "#microsoft.graph.iPv4CidrRange"; cidrAddress = "203.0.113.0/24" })
  }

Named locations let you require stronger controls for logins from unrecognized networks while easing friction for trusted ones — a core building block of any mature azure conditional access setup.

Step 3: Configure Azure AD Conditional Access Policies for MFA

This is the core of the exercise. Start with the highest-impact, lowest-risk policy: requiring MFA for all users outside your break-glass group when they access cloud apps.

In the portal: Azure AD > Security > Conditional Access > New policy.

  • Name: CA001-Require-MFA-AllUsers
  • Users: All users; exclude the break-glass accounts and emergency access group
  • Cloud apps: All cloud apps (or scope to specific high-value apps initially)
  • Conditions: Optionally exclude your trusted named location to reduce prompts for office-based staff
  • Grant: Require multifactor authentication
  • Enable policy: Report-only (for now — see Step 5)

The equivalent via Microsoft Graph PowerShell, which is useful for version-controlling policy as code:

$params = @{
  displayName = "CA001-Require-MFA-AllUsers"
  state = "enabledForReportingButNotEnforced"
  conditions = @{
    users = @{ includeUsers = @("All"); excludeGroups = @("<break-glass-group-id>") }
    applications = @{ includeApplications = @("All") }
  }
  grantControls = @{
    operator = "OR"
    builtInControls = @("mfa")
  }
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $params

This is your mfa conditional access policy baseline. Layer additional policies on top rather than overloading one rule: a separate policy to block legacy authentication protocols, another to require compliant or hybrid-joined devices for admin roles, and another to enforce sign-in frequency for privileged sessions.

Step 4: Add Risk-Based and Device Compliance Controls

Once baseline MFA is stable, add conditions that respond to signal, not just identity:

  • User risk / sign-in risk (requires Azure AD Premium P2 and Identity Protection): require password change on high user risk, require MFA on medium or higher sign-in risk.
  • Device compliance: require Intune-compliant or hybrid Azure AD joined devices for access to sensitive apps.
  • Session controls: use Conditional Access App Control (via Microsoft Defender for Cloud Apps) to restrict downloads or enforce read-only sessions from unmanaged devices.

Example policy targeting admin roles specifically:

$adminParams = @{
  displayName = "CA010-Require-CompliantDevice-Admins"
  state = "enabled"
  conditions = @{
    users = @{ includeRoles = @("62e90394-69f5-4237-9190-012177145e10") } # Global Administrator
    applications = @{ includeApplications = @("All") }
  }
  grantControls = @{ operator = "OR"; builtInControls = @("compliantDevice", "mfa") }
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $adminParams

Privileged roles should always carry stricter requirements than the general population — this is where most breaches involving stolen admin credentials get stopped.

Step 5: Pilot in Report-Only Mode Before Enforcing

Never flip a new policy straight to "On" in production. Set state to enabledForReportingButNotEnforced and let it run for 3–7 days against a pilot group of 20–50 users spanning different roles, devices, and locations. Review outcomes in Azure AD > Security > Conditional Access > Insights and Reporting, or query sign-in logs directly:

Get-MgAuditLogSignIn -Filter "conditionalAccessStatus eq 'success'" -Top 50 |
  Select-Object UserPrincipalName, AppDisplayName, ConditionalAccessStatus

Look specifically for failure and notApplied results that don't match your expectations — these usually point to scoping mistakes (wrong group membership, an excluded app that should be included, or a named location with an incorrect CIDR range).

Step 6: Enable Policies and Roll Out in Waves

After a clean report-only period, switch the policy to enabled for the pilot group first, then expand in waves — by department, then tenant-wide — over one to two weeks. Keep a rollback plan: know exactly which policy to disable and how fast you can do it if a wave causes unexpected lockouts. Document each policy's purpose, scope, and owner in a change log; this becomes essential during audits and incident reviews.

Troubleshooting and Verification

  • Users report constant MFA prompts: Check sign-in frequency settings and whether "Remember MFA on trusted devices" is disabled tenant-wide, or whether multiple overlapping policies are each independently triggering a challenge.
  • A user is unexpectedly blocked: Pull their sign-in log entry and check the conditionalAccessPolicies detail to see exactly which policy applied and which grant control failed. The Graph API returns this in the appliedConditionalAccessPolicies field.
  • Legacy authentication still succeeds: Confirm the blocking policy targets Other clients under client app conditions, and confirm no service account is still using basic auth via IMAP/POP/SMTP, which bypasses modern auth flows entirely.
  • Break-glass account triggers a policy: Double-check exclusion lists on every policy — group-based exclusion is more maintainable than listing individual UPNs, since exclusions are easy to forget when policies are added later.
  • Security Defaults re-enables unexpectedly: This can happen if a tenant is reset to defaults after certain licensing changes; re-verify with Get-MgPolicyIdentitySecurityDefaultEnforcementPolicy after any tenant-level licensing modification.
  • Conflicting policies: Use the "What If" tool in Conditional Access (Azure AD > Security > Conditional Access > What If) to simulate a specific user, app, and location combination and see exactly which policies would apply before you ship a change.

How Safeguard Helps

Conditional Access policies are only as strong as the identity and pipeline hygiene behind them, and misconfigurations tend to surface far from the Azure AD admin console — in a CI/CD service principal that bypasses MFA by design, a build agent with standing access to production secrets, or a dependency pulled in without any identity-aware gate. Safeguard continuously maps how identities, tokens, and non-human accounts move through your software supply chain, flagging service principals and automation identities that should be brought under Conditional Access scope but currently aren't. Instead of treating conditional access as an Azure AD-only project, teams using Safeguard get visibility into where identity controls and pipeline security intersect — catching risky exceptions, stale exclusions, and unmonitored service accounts before they become the gap an attacker finds first. Pair a well-architected azure conditional access setup with that broader supply chain visibility, and you close off both the human and machine identity paths attackers rely on.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.