Verplichte MFA voor Azure fase 2: welke identiteiten vastlopen op Resource Manager

Samantha Kloos-Kilkens
12-08-2026 · Samantha Kloos-Kilkens

Sinds 1 juli 2026 kan geen enkele tenant fase 2 van de verplichte MFA voor Azure nog verder uitstellen. Elke create, update of delete die een gebruikersaccount naar Azure Resource Manager stuurt, vraagt nu om MFA, ongeacht de client. De tijdlijn is elders al uitgebreid beschreven, dus deze blog gaat over de werking: waar de controle precies plaatsvindt, waarom je Conditional Access-uitsluitingen hier niets uitmaken, welke accounts er meestal op stuklopen en hoe je ze in je logs vindt voordat de eerste deployment faalt.

Auto's in de rij voor tolpoortjes, van bovenaf Foto: Getty Images via Unsplash

Wat er wordt afgedwongen, en waar

Fase 1 (vanaf oktober 2024) ging over de portals: de Azure portal, het Entra en Intune admin center en vanaf februari 2025 het Microsoft 365 admin center. Fase 2 legt de controle in Azure Resource Manager zelf. De FAQ op Learn is daar duidelijk over: de handhaving zit aan de serverkant van Resource Manager, dus elk request naar https://management.azure.com valt eronder. De client maakt niet uit. Azure CLI, Azure PowerShell, de Azure mobile app, de SDK's, losse REST-calls en IaC-tools (die via de app-ID's van CLI of PowerShell authenticeren) komen allemaal bij hetzelfde endpoint uit.

Alleen create, update en delete worden afgedwongen, lezen niet. Dat verklaart waarom veel organisaties na de start van de uitrol dachten dat ze er goed vanaf kwamen: een inventarisatiescript dat alleen Get-AzResource draait blijft gewoon werken, en de eerste fout komt pas weken later, als iemands deployment draait.

Minstens zo nuttig is weten wat er buiten valt. Microsoft Graph valt in het algemeen niet onder de handhaving, omdat alleen management.azure.com telt; een script dat met een gebruikersaccount Graph aanroept heeft hier geen last van (je eigen Conditional Access is een ander verhaal). Volgens diezelfde definitie vallen data plane-endpoints zoals Key Vault of Storage er ook buiten. Workload identities, dus managed identities en service principals, worden door geen van beide fases geraakt, en het serviceaccount van Entra Connect of Cloud Sync ook niet. In de sovereign clouds wordt op dit moment helemaal niet gehandhaafd.

Aan de foutmelding aan de clientkant zie je ook hoe de handhaving is gebouwd. Volgens Microsofts aankondiging van fase 2 loopt de handhaving via Azure Policy, en de FAQ zegt dat Microsoft bij systeemhandhaving dezelfde policy uitrolt die je ook zelf kunt toewijzen. Een geblokkeerde schrijfactie in Azure CLI komt terug als RequestDisallowedByPolicy met de tekst "Users must authenticate with multi-factor authentication to create or update resources", en dat is letterlijk de naam van de ingebouwde definitie. Daar zijn er twee van: één voor create en update (4e6c27d5-a6ee-49cf-b2b4-d8fe90fa2b8b, Audit of Deny) en één voor delete (db4a9d17-db75-4f46-9fcb-9f9526604417, AuditAction of DenyAction). Met Azure CLI 2.76 of nieuwer en Az PowerShell 14.3 of nieuwer bevat de foutmelding ook meteen een az login --claims-challenge- of Connect-AzAccount -ClaimsChallenge-commando, zodat een interactieve gebruiker kan opschalen naar MFA (zie de troubleshootingpagina van de CLI). Oudere versies geven vagere fouten, en dat is op zich al een goede reden om beheerwerkplekken en build agents bij te werken.

Waar ik steeds op terugkom: het deny-effect van Azure Policy beoordeelt create- en update-requests, en denyAction ondersteunt op dit moment alleen delete. POST-acties, zoals de sleutels van een storage account opvragen of een VM herstarten, zijn geen van beide. Ik heb Microsoft nergens zien zeggen of de systeemhandhaving die wel afvangt, dus ik zou er niet op bouwen als gat. Voor mij is het vooral een reden waarom je eigen Conditional Access-policy die MFA eist voor Azure-beheer de echte maatregel blijft, met de platformhandhaving als ondergrens daaronder.

Conditional Access-uitsluitingen en systeemhandhaving

Omdat de controle in Resource Manager zit en naar het token kijkt, is er geen Conditional Access-policy waar je van uitgesloten kunt worden. Entra geeft prima een token zonder MFA-claim uit als je eigen policies dat toestaan, en Resource Manager weigert vervolgens de schrijfactie. De FAQ zegt expliciet dat de systeemhandhaving geldt voor alle gebruikersaccounts, ook break-glass accounts, beheerders met actieve of eligible rollen en accounts met user exclusions in je policies. Heb je uitzonderingen in je MFA-policy, dan gelden die voor deze acties niet meer. Strengere policies, zoals een phishing-resistente authentication strength op Azure-beheer, blijven wel gewoon van kracht.

In de praktijk betekent dit dat je lijst met Conditional Access-uitsluitingen nu een lijst met kandidaat-storingen is. Elk account dat ooit "om technische redenen" van MFA is uitgezonderd en iets in Azure aanmaakt, wijzigt of verwijdert, staat erop. Er is geen opt-out, testtenants doen ook mee, en zodra de handhaving voor jouw tenant gestart is, kan alleen een Global Administrator Microsoft Support nog vragen om die tijdelijk op te heffen.

De identiteiten die meestal vastlopen

Gebruikersaccounts die als serviceaccount worden gebruikt, zijn de grootste groep. Een svc-deploy-account met Contributor op een subscription dat aanmeldt met Connect-AzAccount -Credential of az login -u -p gebruikt de resource owner password credentials-flow (ROPC), en ROPC kan geen MFA. De Learn-pagina noemt ook de SDK-varianten, waaronder DefaultAzureCredential of EnvironmentCredential met AZURE_USERNAME en AZURE_PASSWORD gezet. Die mis je makkelijk, want het zit in applicatiecode die niemand van het identityteam ooit leest. Serviceaccounts die vanuit Active Directory gesynchroniseerd zijn, lopen er op precies dezelfde manier tegenaan.

Gedeelde beheeraccounts zijn de volgende groep. Een azureadmin@-account dat een heel team gebruikt, is meestal uitgezonderd van MFA, of heeft MFA geregistreerd op de telefoon van één persoon, wat een probleem op zich is. Fase 2 dwingt die vraag af, en het goede antwoord is persoonlijke beheeraccounts.

Break-glass accounts moeten ook MFA doen. Microsoft raadt daarvoor een passkey (FIDO2) of certificate-based authentication aan, en beide voldoen aan de eis; de richtlijn voor emergency access accounts noemt passkeys inmiddels de aanbevolen methode en CBA voor organisaties die al een PKI hebben. Leunde je noodprocedure op terugvallen naar CLI of PowerShell met een lang wachtwoord, omdat de portal sinds fase 1 al om MFA vroeg, dan is die uitweg nu weg.

Gastbeheerders zijn de laatste groep die ik altijd nakijk: partners en leveranciers met een RBAC-rol op je subscriptions. Voor B2B-gasten moet de MFA óf in jouw tenant gebeuren, óf in hun eigen tenant, waarbij jouw cross-tenant access settings hun MFA-claims vertrouwen. Vertrouw je inkomende MFA niet, dan moeten ze een methode in jouw tenant registreren, en dat regel je makkelijker voordat hun deployment faalt.

De betrokken accounts vinden

Begin bij de status. Een Global Administrator kan de fase 2-pagina openen via aka.ms/postponePhase2MFA; de banner laat zien of en sinds wanneer de handhaving voor je tenant geldt. Is de handhaving nog niet bij jouw tenant aangekomen, dan kun je de twee ingebouwde definities zelf in audit-modus toewijzen met de Azure Policy-tutorial. Zoek de resultaten niet in het compliance-overzicht: deze definities beoordelen requests en geen resources, dus compliance blijft op nul resources staan en de audit-events verschijnen alleen in de Activity Log. De voorbeeldquery in de tutorial laat weg wie de actie deed, en dat is juist wat ik nodig heb, dus ik voeg Caller toe:
AzureActivity
| where CategoryValue == "Policy"
| extend p = parse_json(Properties)
| extend policies = parse_json(tostring(p.policies))
| mv-expand policies
| where tostring(policies.policyDefinitionId) in~ (
    "/providers/Microsoft.Authorization/policyDefinitions/4e6c27d5-a6ee-49cf-b2b4-d8fe90fa2b8b",
    "/providers/Microsoft.Authorization/policyDefinitions/db4a9d17-db75-4f46-9fcb-9f9526604417")
| summarize Events = count(), LastSeen = max(TimeGenerated) by Caller, OperationNameValue
| sort by Events desc
De sign-in logs werken ongeacht of je al gehandhaafd wordt. CLI, PowerShell en de SDK's vragen allemaal een token aan voor de Windows Azure Service Management API (app-ID 797f4846-ba00-4fd7-ba43-dac1f8f63013), dus filter op die resource in zowel de interactieve als de niet-interactieve user sign-in-tabel:
union SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(30d)
| where ResourceIdentity == "797f4846-ba00-4fd7-ba43-dac1f8f63013"
| where ResultType == "0"
| where AuthenticationRequirement == "singleFactorAuthentication"
| summarize SignIns = count(), Clients = make_set(AppDisplayName),
    Protocols = make_set(AuthenticationProtocol), IPs = make_set(IPAddress, 20),
    LastSeen = max(TimeGenerated) by UserPrincipalName, UserType
| sort by SignIns desc
Lees het resultaat met enige zorg. AuthenticationRequirement laat zien wat er voor die aanmelding vereist was, niet wat de gebruiker toevallig deed. In een tenant waar Conditional Access al MFA eist voor Azure-beheer blijven vooral je uitsluitingen over, en dat is precies de lijst die je zoekt. In een tenant zonder zo'n policy staat bijna alles op single factor, en dan zijn ropc in de protocolkolom (een script met een wachtwoord) en IP-adressen van build agents of automatiseringsservers de nuttige signalen. UserType geeft je de gasten er gratis bij.

Automatisering naar workload identities verhuizen

De oplossing is overal dezelfde, maar de vorm hangt af van waar de code draait. Alles wat in Azure draait (een VM, Functions, een Automation-runbook) hoort een managed identity te gebruiken, in PowerShell is dat Connect-AzAccount -Identity. Pipelines horen workload identity federation te gebruiken, zodat er helemaal geen secret bestaat: in GitHub Actions de azure/login-action met OpenID Connect en een federated credential op een app registration of user-assigned managed identity, in Azure DevOps een Azure Resource Manager service connection met workload identity federation (bestaande service connections met een secret die Azure DevOps zelf heeft aangemaakt, kun je ter plekke converteren). Voor code die ergens anders draait, bijvoorbeeld op een on-premises scheduler, is een service principal met een certificaat de terugvaloptie, liever geen client secret:
Connect-AzAccount -ServicePrincipal -ApplicationId $appId -Tenant $tenantId -CertificateThumbprint $thumbprint
Gebruikte je Conditional Access om te beperken waarvandaan het oude serviceaccount mocht aanmelden, dan kun je dat meenemen met Conditional Access voor workload identities; daarvoor heb je een Workload Identities Premium-licentie nodig. Dat werkt wel alleen voor single-tenant service principals (app registrations): managed identities kun je met die policies niet targeten. En nu je toch een nieuwe identiteit aanmaakt: geef die een rol op de resource groups waar hij echt naar deployt, in plaats van de Contributor-rol op de hele subscription van het oude account te kopiëren.

Kort samengevat: draai de sign-in-query over de afgelopen 30 dagen, leg elke UPN die eruit komt naast je lijst met Conditional Access-uitsluitingen, en geef elk account een eigenaar en een doelidentiteit (managed identity, federated credential of certificaat) voordat de volgende deployment draait die ervan afhangt.

Geschreven door een expert van Argus IT

Zo’n expert in je team, of zelf zo werken in security, IAM of cloud?

Blijf op de hoogte

Schrijf je in voor onze nieuwsbrief en ontvang een seintje wanneer we een nieuw artikel publiceren of nieuws te delen hebben.