Entra ID user with VM access has multi-factor authentication enabled
Microsoft Entra users with Azure roles that grant VM sign-in or management access-such as Owner, Contributor, Virtual Machine * Login, and Virtual Machine Contributor-are evaluated for multi-factor authentication enrollment. The finding highlights accounts with VM access that lack more than one authentication factor.
Risk
Without MFA, accounts with VM access are vulnerable to phishing, password spraying, and credential stuffing. Compromise can enable remote VM login, abuse of the VM's managed identity, privilege escalation, and lateral movement-impacting confidentiality, integrity, and availability of workloads.
Run this check with Prowler
Run in Prowler Cloudprowler azure --checks entra_user_with_vm_access_has_mfaRecommendation
Enforce MFA for all identities that can sign in to or manage VMs via Conditional Access, preferring strong, phishing-resistant methods. Apply least privilege by removing broad roles (Owner, Contributor) when not required. Use PIM/JIT for admin access and monitor sign-in risk for continuous assurance.
Remediation
CLI
az rest --method post --url https://graph.microsoft.com/v1.0/users/<example_user_id>/authentication/phoneMethods --body '{"phoneNumber":"+10000000000","phoneType":"mobile"}'Other
Check Code
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.config import (
CONTRIBUTOR_ROLE_ID,
OWNER_ROLE_ID,
VIRTUAL_MACHINE_ADMINISTRATOR_LOGIN_ROLE_ID,
VIRTUAL_MACHINE_CONTRIBUTOR_ROLE_ID,
VIRTUAL_MACHINE_LOCAL_USER_LOGIN_ROLE_ID,
VIRTUAL_MACHINE_USER_LOGIN_ROLE_ID,
WINDOWS_ADMIN_CENTER_ADMINISTRATOR_LOGIN_ROLE_ID,
)
from prowler.providers.azure.services.entra.entra_client import entra_client
from prowler.providers.azure.services.iam.iam_client import iam_client
class entra_user_with_vm_access_has_mfa(Check):
def execute(self) -> Check_Report_Azure:
findings = []
already_reported = set()
for tenant_domain, users in entra_client.users.items():
if tenant_domain in entra_client.users_retrieval_errors:
report = Check_Report_Azure(metadata=self.metadata(), resource={})
report.subscription = f"Tenant: {tenant_domain}"
report.resource_name = tenant_domain
report.resource_id = entra_client.tenant_ids[0]
report.status = "MANUAL"
report.status_extended = (
f"Cannot evaluate MFA for the tenant's users with VM access for tenant {tenant_domain}: "
f"Microsoft Graph did not return the tenant's users "
f"({entra_client.users_retrieval_errors[tenant_domain]}). "
f"Retry the scan or review the tenant's users manually."
)
findings.append(report)
continue
for user in users.values():
for (
subscription_id,
role_assigns,
) in iam_client.role_assignments.items():
subscription_name = entra_client.subscriptions.get(
subscription_id, subscription_id
)
if (user.id, subscription_id) in already_reported:
continue
for assignment in role_assigns.values():
if (
assignment.agent_type == "User"
and assignment.role_id
in [
CONTRIBUTOR_ROLE_ID,
OWNER_ROLE_ID,
VIRTUAL_MACHINE_CONTRIBUTOR_ROLE_ID,
VIRTUAL_MACHINE_ADMINISTRATOR_LOGIN_ROLE_ID,
VIRTUAL_MACHINE_USER_LOGIN_ROLE_ID,
VIRTUAL_MACHINE_LOCAL_USER_LOGIN_ROLE_ID,
WINDOWS_ADMIN_CENTER_ADMINISTRATOR_LOGIN_ROLE_ID,
]
and assignment.agent_id == user.id
):
report = Check_Report_Azure(
metadata=self.metadata(), resource=user
)
report.subscription = subscription_id
report.status = "FAIL"
report.status_extended = f"User {user.name} without MFA can access VMs in subscription {subscription_name} ({subscription_id})"
if user.is_mfa_capable:
report.status = "PASS"
report.status_extended = f"User {user.name} can access VMs in subscription {subscription_name} ({subscription_id}) but it has MFA."
findings.append(report)
already_reported.add((user.id, subscription_id))
break
return findingsReferences
- https://www.rebeladmin.com/step-step-guide-enable-mfa-azure-admins-preview/
- https://learn.microsoft.com/en-us/entra/identity/authentication/howto-mfa-userdevicesettings
- https://www.trendmicro.com/trendaivisiononecloudriskmanagement/knowledge-base/azure/VirtualMachines/vm-access-with-mfa-enabled-identities.html