Back to Checks
m365

Conditional Access policies require authentication from a managed device for all users and applications

entra_managed_device_required_for_authentication
Service: entraSeverity: high
OfficialBuilt-inVerified
Categories:identity-accesse3
Resource Type:NotDefined

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 Cloud
Run
prowler m365 --checks entra_managed_device_required_for_authentication

Recommendation

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

1In Microsoft Entra admin center, go to Entra ID > Security > Conditional Access > Policies
2Select New policy
3Users: Include > All users
4Target resources: Include > All cloud apps
5Grant: Select Grant access, check Require multifactor authentication and Require Microsoft Entra hybrid joined device, then choose Require one of the selected controls
6Enable policy: On
7Create to save

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