My Azure AD Conditional Access Policy Design Baseline is updated at least twice every year, always containing lessons learned from the field. It is based on my recommendations of how Conditional Access should be deployed to create a strong zero trust security posture.
Note that all organisations are different and you might need to adjust the baseline to fit your specific needs. My goal is to provide inspiration and a great starting point for your own Conditional Access design.
Current baseline version: | 12 |
Release date: | 2023-01-25 |
There are two methods of deployment:
Option 1: Manual Deployment
Download the Excel version of the baseline and manually create each Conditional Access policy in the Azure portal.

Option 2: Automatic Deployment
Version 7 of this baseline was the first version with DCToolbox automation support. This means that you can now automatically deploy this baseline from the JSON template at the end of this blog post (or export or create your own JSON templates).
Please see this article for details of Conditional Access automation with DCToolbox: How to Manage Conditional Access as Code – The Ultimate Guide
To automatically install the baseline, follow the instructions in the article above, copy the JSON template at the bottom of this blog post, search and replace IDs of Azure AD groups, named locations, etc, save the file, and point Import-DCConditionalAccessPolicyDesign to your new JSON file.
Search and replace the following text in your JSON file:
REPLACE WITH EXCLUDE GROUP ID
REPLACE WITH SERVICE ACCOUNT GROUP ID
REPLACE WITH SERVICE ACCOUNT TRUSTED NAMED LOCATION ID
REPLACE WITH ALLOWED COUNTRIES NAMED LOCATION ID
REPLACE WITH TERMS OF USE ID
Tips: PowerShell snippet to get Named Location and Terms of Use ID’s:
# Connect to Microsoft Graph with delegated credentials.
$Parameters = @{
ClientID = ''
ClientSecret = ''
}
$AccessToken = Connect-DCMsGraphAsDelegated @Parameters
# GET Named Locations.
$Parameters = @{
AccessToken = $AccessToken
GraphMethod = 'GET'
GraphUri = 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/namedLocations'
}
Invoke-DCMsGraphQuery @Parameters
# GET Terms of Use.
$Parameters = @{
AccessToken = $AccessToken
GraphMethod = 'GET'
GraphUri = 'https://graph.microsoft.com/v1.0/identityGovernance/termsOfUse/agreements'
}
Invoke-DCMsGraphQuery @Parameters
Baseline Policies Explained
This is a short explanation of each policy in the baseline.
BLOCK – Legacy Authentication
This global policy blocks all connections from insecure legacy protocols like ActiveSync, IMAP, PO3, etc. Blocking legacy authentication, together with MFA, is one of the most important security improvements your can do in the cloud.
BLOCK – Unsupported Device Platforms
Block unsupported platforms like Windows Phone, Linux, and other OS variants. Note: Device platform detection is a best effort security signal based on the user agent string and can be spoofed. Always combine this with additional signals like MFA and/or device authentication.
BLOCK – High-Risk Sign-Ins
This global policy blocks all high-risk authentications detected by Azure AD Identity Protection. This is called risk-based Conditional Access. Note that this policy requires Azure AD Premium P2 for all targeted users.
BLOCK – High-Risk Users
Same as above but looks at the user risk level instead of the sign-in risk level. For example, many medium risk sign-ins can result in a high-risk user.
BLOCK – Countries not Allowed
This global policy blocks all connections from countries not in the Allowed countries whitelist. You should only allow countries where you expect your users to sign in from. This is not a real security solution since attackers will easily bypass this with a proxy service, however, this effectively blocks a lot of the automated noise in the cloud.
BLOCK – Service Accounts (Trusted Locations Excluded)
Block service accounts (real Azure AD user accounts used by services) from untrusted IP addresses. Service accounts can only connect from allowed IP addresses, but without MFA requirement. Only use service accounts as a last resort!
BLOCK – Explicitly Blocked Cloud Apps
This policy can be used to explicitly block certain cloud apps across the organisation. This is handy if you want to permanently block certain apps, or temporary block unwanted apps, for example, if there is a known critical security flaw.
BLOCK – Guest Access (Allowed Apps Excluded)
Block guests from using all apps, except excluded ones (default policy allows Office 365, My Apps, and Azure Information Protection only).
GRANT – Terms of Use
This global policy forces Terms of Use, like an acceptable use policy or NDA, on all users. Users must read and agree to this policy the first time they sign in before they’re granted access.
GRANT – MFA for All Users
Protects all user authentications with MFA. This policy applies to both internal users and guest users on all devices and clients. Intune enrollment is excluded since MFA is not supported during enrollment of fully managed devices.
GRANT – Mobile Apps and Desktop Clients
Requires mobile apps and desktop clients to be Intune (or 3rd party MDM) compliant. BYOD is blocked.
GRANT – Mobile Device Access Requirements
Requires apps to be protected by Intune App Protection Policies (MAM) on iOS and Android. This blocks third-party app store apps and encrypts org data on mobile devices. Note that we’re still blocking BYOD with “GRANT – Mobile Apps and Desktop Clients“.
GRANT – Browsers
Requires browser clients to be Intune (or 3rd party MDM) compliant. BYOD is blocked. Guest accounts can be excluded if you don’t trust their home tenant compliance state.
SESSION – Admin Persistence
This policy disables token persistence for all accounts with admin roles assigned. It also sets the sign-in frequency to 9 hours. This is to protect against Primary Refresh Token stealing attacks by keeping such tokens few and short-lived. Always use separate cloud-only accounts for admin role assignments.
Summary
This baseline will work for many organisations out of the box but it can also serve as a starting point for a modified version. Some organisations might require different policys for differens departments and if that’s the case it is easy to just create multiple copies of the required policies and filter on group membership.
Please follow me here, on LinkedIn and on Twitter!
The JSON baseline template:
[
{
"displayName": "BLOCK - Legacy Authentication",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"exchangeActiveSync",
"other"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u0027e2f725b1-c378-42ac-b19a-7c441d685026\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "BLOCK - Unsupported Device Platforms",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
},
"platforms": {
"includePlatforms": [
"all"
],
"excludePlatforms": [
"android",
"iOS",
"windows",
"macOS"
]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u002730c8d0f1-1517-4b92-8c49-5e993cbc0b02\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "BLOCK - High-Risk Sign-Ins",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [
"high"
],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u0027e09
a99a5-0159-402f-b270-25eccf705812\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "BLOCK - High-Risk Users",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [
"high"
],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u0027dc400625-a48e-4938-b581-8c3b9987158d\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "BLOCK - Countries not Allowed",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
},
"locations": {
"includeLocations": [
"All"
],
"excludeLocations": [
"REPLACE WITH ALLOWED COUNTRIES NAMED LOCATION ID"
]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u0027f3a73bf3-6ce1-46a0-999a-41ff55bb0eca\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "BLOCK - Service Accounts (Trusted Locations Excluded)",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [],
"excludeUsers": [],
"includeGroups": [
"REPLACE WITH SERVICE ACCOUNT GROUP ID"
],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
},
"locations": {
"includeLocations": [
"All"
],
"excludeLocations": [
"REPLACE WITH SERVICE ACCOUNT TRUSTED NAMED LOCATION ID"
]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u0027c365a343-4a9c-4c6e-848f-d1eb4f43f860\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "BLOCK - Explicitly Blocked Cloud Apps",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"None"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u002790d6b614-790c-449d-b6e5-0a4e408c6d86\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "BLOCK - Guest Access (Allowed Apps Excluded)",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [
"00000012-0000-0000-c000-000000000000",
"2793995e-0a7d-40d7-bd35-6968ba142197",
"Office365"
],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"GuestsOrExternalUsers"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u002702d992c3-81f4-481d-af48-394bf1d1e9f6\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "GRANT - Terms of Use",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID",
"REPLACE WITH SERVICE ACCOUNT GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [],
"customAuthenticationFactors": [],
"termsOfUse": [
"REPLACE WITH TERMS OF USE ID"
],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u00271c1486b8-47fd-46ea-814b-53722e74af5f\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "GRANT - MFA for All Users",
"state": "enabled",
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [
"0000000a-0000-0000-c000-000000000000",
"d4ebce55-015a-49b5-a083-c84d1797ae8c"
],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID",
"REPLACE WITH SERVICE ACCOUNT GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"mfa"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u00277f02a27e-e851-4158-9279-0ac036f6b54a\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
},
"sessionControls": {
"disableResilienceDefaults": true,
"applicationEnforcedRestrictions": null,
"cloudAppSecurity": null,
"persistentBrowser": null,
"continuousAccessEvaluation": null,
"secureSignInSession": null,
"signInFrequency": {
"value": 30,
"type": "days",
"authenticationType": "primaryAndSecondaryAuthentication",
"frequencyInterval": "timeBased",
"isEnabled": true
}
}
},
{
"displayName": "GRANT - Mobile Apps and Desktop Clients",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"mobileAppsAndDesktopClients"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [
"cc15fd57-2c6c-4117-a88c-83b1d56b4bbe"
],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID",
"REPLACE WITH SERVICE ACCOUNT GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"compliantDevice"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u0027eeb941cf-0c3f-4fa6-af99-e0ae19fd4133\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "GRANT - Mobile Device Access Requirements",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"mobileAppsAndDesktopClients"
],
"servicePrincipalRiskLevels": [],
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [
"0000000a-0000-0000-c000-000000000000",
"d4ebce55-015a-49b5-a083-c84d1797ae8c"
],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID",
"REPLACE WITH SERVICE ACCOUNT GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
},
"platforms": {
"includePlatforms": [
"android",
"iOS"
],
"excludePlatforms": []
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"compliantApplication"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u002701e48e4e-a650-4596-860e-7bc430015040\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "GRANT - Browsers",
"state": "enabled",
"sessionControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"browser"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [
"All"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"compliantDevice"
],
"customAuthenticationFactors": [],
"termsOfUse": [],
"authenticationStrength@odata.context": "https://graph.microsoft.com/beta/$metadata#identity/conditionalAccess/policies(\u0027d7981dd6-aad4-4046-9103-c427ceb1546c\u0027)/grantControls/authenticationStrength/$entity","authenticationStrength": null
}
},
{
"displayName": "SESSION - Admin Persistence",
"state": "enabled",
"grantControls": null,
"conditions": {
"userRiskLevels": [],
"signInRiskLevels": [],
"clientAppTypes": [
"all"
],
"servicePrincipalRiskLevels": [],
"platforms": null,
"locations": null,
"times": null,
"deviceStates": null,
"devices": null,
"clientApplications": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": [],
"includeAuthenticationContextClassReferences": []
},
"users": {
"includeUsers": [],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [
"REPLACE WITH EXCLUDE GROUP ID"
],
"includeRoles": [
"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3",
"0526716b-113d-4c15-b2c8-68e3c22b9f80",
"158c047a-c907-4556-b7ef-446551a6b5f7",
"17315797-102d-40b4-93e0-432062caca18",
"e6d1a23a-da11-4be4-9570-befc86d067a7",
"b1be1c3e-b65d-4f19-8427-f6fa0d97feb9",
"62e90394-69f5-4237-9190-012177145e10",
"8ac3fc64-6eca-42ea-9e69-59f4c7b60eb2",
"7be44c8a-adaf-4e2a-84d6-ab2649e08a13",
"e8611ab8-c189-46e8-94e1-60213ab1f814",
"194ae4cb-b126-40b2-bd5b-6091b380977d"
],
"excludeRoles": [],
"includeGuestsOrExternalUsers": null,
"excludeGuestsOrExternalUsers": null
}
},
"sessionControls": {
"disableResilienceDefaults": false,
"applicationEnforcedRestrictions": null,
"cloudAppSecurity": null,
"continuousAccessEvaluation": null,
"secureSignInSession": null,
"signInFrequency": {
"value": 9,
"type": "hours",
"authenticationType": "primaryAndSecondaryAuthentication",
"frequencyInterval": "timeBased",
"isEnabled": true
},
"persistentBrowser": {
"mode": "never",
"isEnabled": true
}
}
}
]
Good read Daniel! Thx!
For your service account policy why are you including trusted locations and not just all locations? Also for the service accounts that we are including should that be all service accounts or just ones that are accessing things in Azure?
I’m using “Trusted locations” because “All locations” might include “Untrusted locations” that I might use to block certain scenarios. I believe this is a flexible and clear design.
The service accounts should only be the ones that authenticate with Azure AD. The service might be in the cloud or on-prem but the authentication happens in Azure AD and Conditional Access is used.
On Service Accounts (Trusted Locations Excluded) shouldn’t be Include Any location and Exclude Selected locations (or maybe All trusted locations)?
GRANT – MFA for All Users force even All guest and external users to install Microsoft Authenticator app, which is not an issue, but you should mention it.
When testing the policy “Block – Service Accounts..” using the What If tool, a user in the service accounts group is:
– Granted access if the account uses Modern Auth and is in an untrusted location.
– Blocked access if the account is in the “office” location and uses legacy authentication (via the policy Block – Legacy Auth…)
Can you confirm the above statements are correct when using this policy?
Service accounts will typically use basic authentication, so the policy to block legacy auth will invalidate the use of this policy in this scenario – Unless this policy is not designed for this purpose?
This is an excellent resource that we are starting to implement in our organisation, we just need a little clarification on this policy.
We are attempting to secure accounts for scanners and other devices located in an office.
These accounts can only use basic auth and are only allowed to authenticate from specific locations.
Can this policy achieve the goal of the above scenario?
Thank you for the feedback!
Thank you! The BLOCK – Service Accounts policy blocks all authentications for the group with included service accounts, that comes from an IP adress not listed in the allowed service accounts trusted locations. The idea is that service accounts are bad and should not be able to sign-in, but we need a couple of them and they are only allowed to sign-in from a predefined set of IP-addresses. They should also be carefully monitored since they are excluded from MFA enforcement.
Thanks for a great article!
We also like to block unlicensed users with a dynamic group, admin accounts excluded.
What’s your take on that?
Thank you! It’s an interesting idea but I’m afraid you’re not allowed to do that. Only Azure AD Premium licensed users can benefit from Conditional Access.
You are totally right about that! Never even thought about the license part..
Would you also provide admin accounts with a AADP license for this same purpose?
Yes, always buy AADP2 licenses to admin accounts so you can implement Just-In-Time-Access and Just-Enough-Administration with Azure AD PIM. This is a very important part of a zero trust mindset.
Thanks a lot for the inside Daniel. Will follow your blog from now on 🙂
Thank you Guus!
Hi Daniel, great guide. Truely a great starting point.
I have two questions though.
1. Block all access from unmanaged devices
I would need an additional block Policy if I wanted to block all acccess from private devices, right?
I believe access from a private PC with browser or even Teams would work with this policy set (with MFA though). Is this correct? How would you achieve blocking all access from non-compliant devices? You stated in the intro that we can not filter on Access Controls 🙂
In a network firewall I would add ”ANY ANY DROP” after all those policies, but how can I achieve this with AAD CA?
2. allow OWA / OotW for a group (this is very special I believe, so feel free to skip ;-))
Although we want to block everything from unmanaged devices, I need ONE exception. Outlook on the web should work for a special user group. Nothing else. While making the exception should be easy, I wonder how one can configure to BLOCK Outlook, Teams, … but allow OotW. There is no Cloud app for that, and Exchange Online includes a lot more.
Thank you!
1: Yes you are correct, browser will work. If you want to block unmanaged devices with browser also you can add Require compliant device to the browser policy in my baseline. The rest is already taken care of in the design.
2: if you only want to allow Outlook on the web you can achieve this by blocking Desktop apps and only allow Browser. Then you block the other scenario for the same group.
Hi Daniel, thank you for this fantastic resource. We’ve used this to build our first CA framework and we’re quite happy with the results. At this point we are opening up our tenant to guest access and we’re running into an odd problem.
The CA baseline policies of:
1: BLOCK – Guess Access (Allowed Apps Excluded)
and
2: GRANT – MFA for All Users
For us this results in invited guests being blocked access to the ”Microsoft Invitation Acceptance Portal” and, according to the AAD sign-in logs, it’s the BLOCK – Guest Access policy that is being triggered. Guests receive a ”You don’t have access to this” message where the App name is the above.
What’s even more strange is if they close and re-open the invitation link it opens just fine and then they are prompted to complete the MFA registration. Everything works fine afterwards. We’ve had a colleague recreate the same scenario with just the above 2 policies in another tenant. And, unfortunately, no such ”Microsoft Invitation Acceptance Portal” app exists in CA to be able to exclude it from the BLOCK policy… Wonderful! Have you run into this before / any suggestions or ideas? Thanks in advance!
Glad to hear it comes to use 😊 Have you excluded the My Access app from the guest policy? I added that to my baseline yesterday.
Yes we did 🙂 Got all excited that *this* was the secret sauce that would make it work for us. Alas, it did not 😦
I am seeing guest invites and the ”BLOCK – Guess Access (Allowed Apps Excluded)” rule blocking access with ”Microsoft App Access Panel” App being denied even with ”My Apps” on the Allowed list. This recent post provides some further information – https://techcommunity.microsoft.com/t5/azure-active-directory-identity/conditional-access-policies-guest-access-and-the-quot-microsoft/m-p/2779133/thread-id/6762
Thanks for commenting! Yes, My Apps with guest accounts is a hazel. The guest access still works but it’s very confusing for the guests when they first sign-in. I’m looking into solutions without tampering with security.
I don’t want to use black-listing of apps since the whole reason for the policy is to make sure that Guests even can’t try to open federated apps like SAP and Service Now for example. We want to build multiple layers of security, not just to trust the authorisation in the app itself.
Thanks for the confirmation of the issue. Also, thank you very much for a great blog post and a great tool with DCToolbox.I think it will become an essential part of my workflows.
Glad to hear it comes to use. Thanks! 😊
Daniel this was super helpful, thank you! We are preparing to deploy M365 E5 to our user base and are wanting to take a pretty conservative approach. During the new user registration period we only want users to access the myaccount.microsoft.com from trusted locations to prevent opportunities for brute force, until staff can get MFA setup. Is there a CA that would block access to the user registration portal from non trusted locations?
Thank you! Please have a look at this article explaining how to protect MFA registration with Conditional Access:
https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-policy-registration
Hey, Daniel. Thanks for the amazing article. Your Excel baseline template and Export-DCConditionalAccessPolicyDesign cmdlet do not include deviceFilter option which has replaced includeDeviceStates, excludeDeviceStates, includeDevices, excludeDevices. However, your JSON baseline template includes the deprecated options includeDeviceStates, excludeDeviceStates, includeDevices, excludeDevices.
Another grateful thanks comment from me – after stumbling upon your post/site we now have a half decent understanding of CA along with a starter framework that we are tweaking for our environment and requirements.
Question around SCCM/Intune managed devices (via Cloud Attach configured in SCCM) – do you know of a way to pick these devices and Grant access? The devices show as ‘Managed’ in the sign-in logs, but not as ‘Compliant’ because the Compliance is handled by SCCM (for now).
Is it possible to import multiple individual json files via the import/export function instead of all in one single JSON file?
Hey Daniel, Thanks for this Content.. i implemented Conditional Access on our Tenant. Now i have an issue with the guest accounts. When somebody try to acceppt my invitation, he went into an error. in the aad logs i see the reason is the “BLOCK – Guest Access (Allowed Apps Excluded)
“: Microsoft App Access Panel can not exclude the Conditional Access Policy (cannot find this application with name or id)
i think maybe it works with a custom invitation process where i redirect to a site on sharepoint as example..
maybe you found already a better solution?
thanks
This is amazing work, has anyone found an easy way to get the id’s corresponding to these values:
Replace with service account trusted named location
Replace with allowed countries named location id
Replace with terms of use id
I’ve been doing this by creating a policy that has them in, subsequently exporting the policies and checking the json export. Just wondering whether there’s an easier way.
Yes, preview features are daunting to include since Microsoft is making changes to the API on the flyt. I will include it in the future.
Yes, you can use the -PrefixFilter parameter of the CMDlets. “Only import (and delete) the policys with this prefix in the JSON file.”
Yes, the best way is to implment a custom process. Microsoft does not provide a way to approve the default guest landing page. You can specify another landing page, like Teams with Microsoft Graph.
Yes:
# Connect to Microsoft Graph with delegated credentials.
$Parameters = @{
ClientID = ”
ClientSecret = ”
}
$AccessToken = Connect-DCMsGraphAsDelegated @Parameters
# GET Named Locations.
$Parameters = @{
AccessToken = $AccessToken
GraphMethod = ‘GET’
GraphUri = ‘https://graph.microsoft.com/v1.0/identity/conditionalAccess/namedLocations’
}
Invoke-DCMsGraphQuery @Parameters
# GET Terms of Use.
$Parameters = @{
AccessToken = $AccessToken
GraphMethod = ‘GET’
GraphUri = ‘https://graph.microsoft.com/v1.0/identityGovernance/termsOfUse/agreements’
}
Invoke-DCMsGraphQuery @Parameters