Conditional Access policies require authentication from a managed device for all users and applications
Microsoft Entra Conditional Access evaluates whether an enabled policy targeting all users and all applications includes grant controls that require a managed device (hybrid domain-joined) with multifactor authentication during sign-in.
Risk
Sign-ins from unmanaged devices erode confidentiality and integrity: compromised hosts can steal tokens, hijack sessions, and exfiltrate data. With leaked credentials, attackers bypass endpoint controls, gain persistent access, and move laterally to alter resources.
Run this check with Prowler
Run in Prowler Cloudprowler m365 --checks entra_managed_device_required_for_authenticationRecommendation
Enforce Conditional Access to allow only managed devices (Entra hybrid joined or Intune-compliant) and require MFA, aligning with Zero Trust and least privilege. Apply to all users and apps, limit exclusions to break-glass accounts, and regularly review device compliance to prevent access from unknown endpoints.
Remediation
CLI
New-MgIdentityConditionalAccessPolicy -DisplayName "<example_resource_name>" -State "enabled" -Conditions @{ Users=@{ IncludeUsers=@("All") }; Applications=@{ IncludeApplications=@("All") } } -GrantControls @{ Operator="OR"; BuiltInControls=@("mfa","domainJoinedDevice") }Terraform
resource "azuread_conditional_access_policy" "example" {
display_name = "<example_resource_name>"
state = "enabled" # Critical: must be enabled (not report-only) to enforce
conditions {
users {
include_users = ["All"] # Critical: target all users
}
applications {
include_applications = ["All"] # Critical: target all cloud apps
}
}
grant_controls {
operator = "OR" # Critical: require one of the selected controls
built_in_controls = ["mfa", "domainJoinedDevice"] # Critical: MFA or Microsoft Entra hybrid joined device
}
}Other
Check Code
from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.entra.entra_client import entra_client
from prowler.providers.m365.services.entra.entra_service import (
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
GrantControlOperator,
)
class entra_managed_device_required_for_authentication(Check):
"""Check if Conditional Access policies enforce managed device requirement for authentication.
This check ensures that Conditional Access policies are in place to enforce managed device requirement for authentication.
"""
def execute(self) -> list[CheckReportM365]:
"""Execute the check to ensure that Conditional Access policies enforce managed device requirement for authentication.
Returns:
list[CheckReportM365]: A list containing the results of the check.
"""
findings = []
report = CheckReportM365(
metadata=self.metadata(),
resource={},
resource_name="Conditional Access Policies",
resource_id="conditionalAccessPolicies",
)
report.status = "FAIL"
report.status_extended = (
"No Conditional Access Policy requires a managed device for authentication."
)
for policy in entra_client.conditional_access_policies.values():
if policy.state == ConditionalAccessPolicyState.DISABLED:
continue
if "All" not in policy.conditions.user_conditions.included_users:
continue
if (
"All"
not in policy.conditions.application_conditions.included_applications
):
continue
if (
ConditionalAccessGrantControl.DOMAIN_JOINED_DEVICE
not in policy.grant_controls.built_in_controls
or ConditionalAccessGrantControl.MFA
not in policy.grant_controls.built_in_controls
):
continue
if policy.grant_controls.operator == GrantControlOperator.OR:
report = CheckReportM365(
metadata=self.metadata(),
resource=policy,
resource_name=policy.display_name,
resource_id=policy.id,
)
if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING:
report.status = "FAIL"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' reports the requirement of a managed device for authentication but does not enforce it."
else:
report.status = "PASS"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' does require a managed device for authentication."
break
findings.append(report)
return findings