Back to Checks
m365

Users in administrative roles require multifactor authentication via a Conditional Access policy for all applications

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

Microsoft Entra Conditional Access policies that enforce multifactor authentication for users in administrative roles across all resources.

The assessment identifies at least one active policy that targets admin roles (or all users), includes all applications, and grants access only when Require multifactor authentication is satisfied.

Prowler logoProwlerprowler-provider-m365

Risk

Without enforced MFA on privileged accounts, stolen or phished passwords can grant admin access, enabling tenant takeover. Attackers may exfiltrate data, change configurations, consent malicious apps, and disable protections, impacting confidentiality, integrity, and availability.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler m365 --checks entra_admin_users_mfa_enabled

Recommendation

Require MFA for all administrative roles with Conditional Access scoped to All cloud apps to avoid gaps. Prefer phishing-resistant methods (FIDO2, passkeys, Authenticator). Apply least privilege, limit exclusions, protect break-glass accounts, monitor sign-ins, and verify policies actively enforce, not just report.

Remediation

CLI

az rest --method post --url https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies --body '{"displayName":"Require MFA for all users","state":"enabled","conditions":{"users":{"includeUsers":["All"]},"applications":{"includeApplications":["All"]}},"grantControls":{"operator":"OR","builtInControls":["mfa"]}}'

Terraform

resource "azuread_conditional_access_policy" "<example_resource_name>" {
  display_name = "Require MFA for all users"
  state        = "enabled" # Critical: policy must be enabled to enforce

  conditions {
    users {
      include_users = ["All"] # Critical: applies to all users, covering all admin roles
    }
    applications {
      included_applications = ["All"] # Critical: targets all cloud apps/resources
    }
  }

  grant_controls {
    built_in_controls = ["mfa"] # Critical: require multifactor authentication
    operator          = "OR"
  }
}

Other

1Sign in to Microsoft Entra admin center > Entra ID > Protection > Conditional Access > Policies > New policy
2Users: Include > All users
3Target resources: Include > All cloud apps (All resources)
4Grant: Grant access > Require multifactor authentication > Select
5Enable policy: On > Create

Check Code

from typing import List

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 (
    AdminRoles,
    ConditionalAccessGrantControl,
    ConditionalAccessPolicyState,
)


class entra_admin_users_mfa_enabled(Check):
    """
    Ensure multifactor authentication is enabled for all users in administrative roles.

    This check verifies that at least one Conditional Access Policy in Microsoft Entra, which is in an enabled state,
    applies to administrative roles and enforces multifactor authentication (MFA). Enforcing MFA for privileged accounts
    is critical to reduce the risk of unauthorized access through compromised credentials.

    The check fails if no enabled policy is found that requires MFA for any administrative role.
    """

    def execute(self) -> List[CheckReportM365]:
        """
        Execute the admin MFA requirement check for administrative roles.

        Iterates over the Conditional Access Policies retrieved from the Entra client and generates a report
        indicating whether MFA is enforced for users in administrative roles.

        Returns:
            List[CheckReportM365]: A list containing a single report with the result 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 requiring MFA for administrative roles was found."

        for policy in entra_client.conditional_access_policies.values():
            if policy.state == ConditionalAccessPolicyState.DISABLED:
                continue

            if not ({admin_role.value for admin_role in AdminRoles}).issubset(
                set(policy.conditions.user_conditions.included_roles)
            ):
                if "All" not in policy.conditions.user_conditions.included_users:
                    continue

            if (
                "All"
                not in policy.conditions.application_conditions.included_applications
            ):
                continue

            if (
                ConditionalAccessGrantControl.MFA
                in policy.grant_controls.built_in_controls
            ):
                report = CheckReportM365(
                    metadata=self.metadata(),
                    resource=entra_client.conditional_access_policies,
                    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}' only reports MFA for administrative roles but does not enforce it."
                else:
                    report.status = "PASS"
                    report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces MFA for administrative roles."
                    break

        findings.append(report)
        return findings