2 — Application Access & Managed Identities (AZ-500)
Gouvernance des identités applicatives (workload identities) dans Microsoft Entra : enterprise apps, app registrations, consentement OAuth, service principals et managed identities — l'angle « réduire la surface d'attaque des identités non-humaines ».
A. Application object vs Service principal
Distinction structurante pour toute la suite : on enregistre un application object, on consomme N service principals.
| Objet | Où il vit | Rôle | Analogie |
|---|---|---|---|
| Application object | Tenant home uniquement (App registrations) | Blueprint global : redirect URIs, credentials, scopes/app roles exposés, branding | Classe |
| Service principal (SP) | Chaque tenant où l'app est utilisée (Enterprise applications) | Instance locale : consentements, assignations users/groupes, app role assignments | Instance |
| Managed identity | — | SP « spécial », sans application object, credentials gérés par Azure | Instance sans classe |
- App ID (client ID) = identique pour app object + tous ses SP. Object ID = différent par objet.
- Enregistrer une app via le portail crée app object + SP automatiquement ; via Graph API, le SP est une étape séparée.
- Multitenant : 1 app object (chez l'éditeur) → 1 SP par tenant consommateur (créé au premier consentement).
🚨 Piège : « supprimer l'app » côté Enterprise applications = supprimer le SP (l'instance), pas l'app object. L'app object survit dans App registrations et peut recréer un SP. 🚨 Piège : une managed identity n'a pas d'application object — donc pas de redirect URI, pas de secret, pas de FIC entrant classique côté app registration.
📎 Application and service principal objects
B. App registrations — credentials & redirect URIs
Trois familles de credentials, par ordre de sécurité croissante.
| Credential | Secret en clair ? | Rotation | Verdict sécurité |
|---|---|---|---|
| Client secret | Oui (string) | Manuelle, expire | Le pire — fuite Git/CI, expiration silencieuse |
| Certificate | Clé privée à protéger | Manuelle | Mieux, mais gestion du cert |
| Federated identity credential (FIC) | Aucun | Géré par l'IdP externe | Cible Zero Trust — zéro secret stocké |
- Redirect URI : doit matcher exactement la valeur déclarée (anti-token-injection). Single-tenant vs multitenant se choisit ici.
- FIC = config de confiance OIDC :
issuer+subject+audience(api://AzureADTokenExchange). Max 20 FIC par app/UAMI. - Le couple
issuer+subjectdoit être unique sur l'app ; whitespace en tête/queue de l'issuer → échange bloqué.
🚨 Piège : subject mal configuré (ex. mauvais repo:org/repo:ref GitHub) → l'échange de token échoue sans erreur explicite côté IdP.
🚨 Piège : Application.ReadWrite.All permet d'ajouter un FIC à n'importe quelle app — vecteur de backdoor d'identité discret (pas de secret visible dans les logs).
📎 Add and manage application credentials 📎 FIC considerations & restrictions
C. Permission scopes — Delegated vs Application
Le cœur du modèle d'autorisation Entra. À maîtriser absolument pour l'examen.
| Delegated (scopes) | Application (app roles) | |
|---|---|---|
| Contexte | Au nom d'un user signé | App-only, sans user |
| Plafond d'accès | ≤ droits du user | Tout ce que la permission couvre (tenant-wide) |
| Qui consent | User (sauf admin-restricted) ou admin | Admin seulement |
| Consentement | Statique (déclaré) ou dynamique (incrémental au sign-in) | Statique uniquement |
| Résultat (Graph) | oauth2PermissionGrant |
appRoleAssignment |
| Token / flow | Auth code, scopes nommés | Client credentials, scope .default |
- Exposer une API (App registration → Expose an API) : Application ID URI (
api://{clientId}), puis scopes (delegated) et/ou app roles (application). - App roles ≠ consentables par un user → seul l'admin consent aux clients d'une app exposant des app roles.
- Durcissement :
Assignment required = Yessur l'Enterprise App → Entra n'émet de token qu'aux clients ayant un app role assigné (erreurAADSTS501051sinon).
🚨 Piège least-privilege : le réflexe « un seul scope access_as_user / user_impersonation » = full access. Découper read/write, Resource.Read vs Resource.ReadFull.
🚨 Piège : Files.Read.All en Application = lecture de tous les fichiers du tenant ; en Delegated = seulement ce que le user voit. Même chaîne, portée radicalement différente.
📎 Permissions and consent overview 📎 Expose scopes in a protected web API
D. Consentement — admin, user, et son durcissement
Le levier de gouvernance contre les apps tierces malveillantes.
- User consent settings (Entra > Enterprise apps > Consent and permissions) : trois niveaux —
- Allow user consent (toutes perms non-admin),
- Allow for verified publishers / selected low-risk permissions (recommandé),
- Do not allow (admin consent obligatoire systématique).
- Admin consent (tenant-wide) : Grant admin consent for [tenant] — depuis API permissions (App registrations) ou Permissions (Enterprise apps). Utilise le scope
.default(statique). - Admin consent workflow : si user consent restreint, le user soumet une demande → reviewers notifiés → approbation/refus tracé. Config via
adminConsentRequestPolicy. - Rôles capables d'admin consent : Cloud Application Administrator, Application Administrator, Privileged Role Administrator (selon perms).
🚨 Piège : changer les user consent settings n'affecte que les futurs consentements — les grants existants restent. Révoquer manuellement (Remove-MgOauth2PermissionGrant).
🚨 Piège : admin consent ≠ accès pour tous. Si Assignment required = Yes, seuls les users assignés accèdent malgré le consent tenant-wide.
📎 Configure how users consent to applications 📎 Overview of user and admin consent
E. Illicit consent grant attack (consent phishing)
Sujet de sécurité offensive incontournable de cette compétence.
Chaîne d'attaque : attaquant enregistre une app Entra demandant Mail.Read/Files.Read → phishing ou injection web pousse le user à consentir → l'app obtient un accès account-level OAuth aux données, sans compte dans l'org.
- Pourquoi MFA/reset password n'aide pas : l'app détient un token OAuth, externe à l'org — ces remédiations ne révoquent pas le grant.
- Détection : Audit log (Purview/Defender) → activité « Consent to application » ;
IsAdminConsent=Trueinattendu = signal fort. ScriptGet-AzureADPSPermissions.ps1→ CSV, chercherConsentType = AllPrincipals+ perms*.All/ Write. - Inventaire : Entra admin center (par user → Applications),
myapps.microsoft.com(self), ou PowerShell (rapide, tout le tenant). - Remédiation : désactiver l'app (pas supprimer — elle reviendrait via un nouveau consent), révoquer
oauth2PermissionGrant/appRoleAssignment.
Prévention : restreindre user consent (verified publishers + low-risk), publisher verification, app governance (Defender for Cloud Apps), Consent Insights workbook, revue hebdo des grants.
🚨 Piège : supprimer l'app malveillante ne suffit pas — un autre user peut re-consentir et la ressusciter. Disable d'abord.
📎 Detect and remediate illicit consent grants 📎 Protect against consent phishing
F. Service principals & Managed identities
Hiérarchie de préférence : Managed identity > FIC > SP avec cert > SP avec secret.
Service principals (auth app-only)
- Pour services hors Azure ou non-supportés par MI. Authent via client credentials (
.defaultscope). - Certificat > secret (MCSB IM-3.2). Rotation impérative, stockage en Key Vault.
- Least-privilege : RBAC ciblé, pas de standing privilege global.
Managed identities
| System-assigned (SAMI) | User-assigned (UAMI) | |
|---|---|---|
| Cycle de vie | Lié à la ressource (auto-supprimé) | Indépendant, ressource Azure à part |
| Réutilisation | 1 seule ressource | N ressources |
| Cas d'usage | Charge éphémère, 1:1 | Flotte, pré-provisionnement RBAC, CI/CD |
- Token sans credential via IMDS (endpoint local des VMs ARM). Pas de secret accessible, même à vous.
- Authz : control plane = Azure RBAC (ARM) ; data plane = mécanisme propre à la cible (ex. Storage supporte RBAC data-plane, Key Vault = RBAC ou access policies).
- Rotation cert automatique (~90 j expiration / ~45 j rotation). Gratuit.
- Limites : pas de cross-tenant ; UAMI régionale (mais SP global) ; déplacement de subscription → recréer MI + réassigner RBAC.
FIC / Workload identity federation (zéro secret)
- Cible : CI/CD GitHub Actions / Azure DevOps et workloads hors Azure (Kubernetes, autre IdP OIDC).
- Flux : IdP externe émet token OIDC → envoyé à Entra → Entra valide
issuer/subjectvs FIC → émet un access token Entra. - Deux supports : FIC sur app registration ou sur UAMI. Pour GitHub→Azure, l'UAMI est souvent plus simple (RBAC direct).
- Entra ne stocke que les 100 premières clés de signature de l'IdP externe.
🚨 Piège SAMI : supprimer la ressource détruit l'identité → les role assignments deviennent orphelins (GUID fantôme dans IAM). UAMI évite ça. 🚨 Piège : MI ne marche que vers des ressources supportant l'auth Entra ID. Vérifier la liste des services supportés avant de designer.
📎 What are managed identities 📎 Securing managed identities 📎 Services supporting managed identities 📎 Workload identity federation
🏢 Scénarios d'entreprise (CAF/WAF)
Scénario 1 : FinTech — Pipeline CI/CD GitHub vers Azure sans secret
Contexte business Une FinTech déploie 40+ services via GitHub Actions. Les identifiants Azure stockés dans GitHub fuient régulièrement et ne sont jamais renouvelés. L'audit PCI-DSS l'interdit.
Choix architectural Remplacer les secrets par une fédération OIDC : GitHub échange un jeton court contre un accès Azure, via une identité managée (UAMI) par environnement.
Architecture / pattern
- 1 UAMI par environnement (dev/staging/prod), droits limités au RG cible.
- Configurer la confiance (FIC) : on déclare quel repo/environnement GitHub a le droit de se connecter.
- Approbateurs requis sur
prod→ validation humaine avant déploiement. azure/login@v2avecid-token: write; plus aucun secret stocké.
Trade-offs assumés
- Gain : plus aucun secret à renouveler ; chaque déploiement est tracé ; couper l'accès = supprimer la confiance.
- Perte : la config OIDC est pointilleuse (le
subjectdoit matcher exactement) ; les échecs sont peu explicites ; max 20 fédérations par identité.
Pièges à éviter
subjectqui ne correspond pas à l'environnement → échec sans message clair.- Réutiliser l'UAMI de prod pour dev → casse l'isolation entre environnements.
- Oublier
id-token: write→ GitHub n'émet pas le jeton.
📐 Réf. CAF/WAF — Workload identity federation : remplacer les credentials par une fédération OIDC élimine la classe de risque « secret exposé en CI/CD ». MCSB IM-3 — Manage application identities securely
Scénario 2 : Retail — Plateforme SaaS multi-services accédant à Key Vault et Storage
Contexte business Un retailer migre son e-commerce : App Services, Functions et AKS doivent lire des secrets (Key Vault) et des données (Storage). L'ancien code contient des connection strings en clair.
Choix architectural Des identités managées partout : SAMI (1 par ressource) pour les charges simples, UAMI (partagée) pour AKS et les workloads pré-provisionnés.
Architecture / pattern
- SAMI sur chaque App Service/Function → droits data-plane précis (Key Vault Secrets User, Storage Blob Data Reader), jamais Contributor.
- UAMI partagée pour le pool AKS (réutilisable par plusieurs pods).
DefaultAzureCredentialdans le code → aucun identifiant embarqué.- Key Vault en mode RBAC plutôt qu'access policies.
Trade-offs assumés
- Gain : plus de secrets dans le code ; rotation gérée par Azure ; droits fins par ressource.
- Perte : ne fonctionne que vers des cibles compatibles Entra ; une SAMI laisse des attributions orphelines si la ressource est recréée.
Pièges à éviter
- Donner Contributor au lieu d'un rôle data-plane ciblé → sur-privilège.
- SAMI sur une ressource souvent recréée (IaC) → orphelins RBAC ; préférer une UAMI.
- Une identité managée ne marche pas vers un service tiers non-Entra.
📐 Réf. CAF/WAF — Managed identities first : privilégier les identités managées élimine l'exposition de credentials pour les identités non-humaines. MCSB IM-3.1 — Use managed identity in supported Azure resources
Scénario 3 : Santé — Gouvernance du consentement contre le consent phishing
Contexte business Un hôpital (HIPAA) subit du consent phishing : via un lien piégé, une fausse app « productivité » a obtenu l'accès aux mails et fichiers de plusieurs médecins.
Choix architectural Verrouiller ce que les utilisateurs peuvent autoriser, et industrialiser la détection/nettoyage des autorisations abusives.
Architecture / pattern
- Consentement utilisateur limité aux éditeurs vérifiés + permissions à faible risque (sans tout bloquer, pour ne pas freiner les usages légitimes).
- Workflow d'admin consent activé : l'équipe sécurité valide les demandes, qui expirent.
- Revue hebdomadaire des autorisations (Defender for Cloud Apps + workbook Consent Insights).
- Procédure incident : désactiver l'app → révoquer ses autorisations → vérifier les logs.
Trade-offs assumés
- Gain : surface de consent phishing fortement réduite ; remédiation rapide et tracée.
- Perte : apps légitimes en attente de validation (friction) ; charge de revue pour la sécurité.
Pièges à éviter
- Supprimer l'app au lieu de la désactiver → l'utilisateur peut re-consentir, l'app revient.
- Ne pas avoir activé l'audit mailbox/admin avant l'incident → impossible d'analyser après coup.
- Croire que MFA ou reset de mot de passe corrige une autorisation OAuth (inefficace).
📐 Réf. CAF/WAF — Restrict consent & verify publishers : la restriction du consentement et la vérification d'éditeur sont des contrôles de protection des identités applicatives. CAF Secure — Govern your cloud estate securely
DEMO — chemins portail
1. Restreindre le user consent + activer l'admin consent workflow
entra.microsoft.com → Entra ID > Enterprise apps > Consent and permissions > User consent settings → choisir Allow user consent for apps from verified publishers, for selected permissions → Save. Puis Admin consent settings → activer le workflow, désigner des reviewers et l'expiration des demandes.
2. Grant admin consent tenant-wide à une app
entra.microsoft.com → Entra ID > Enterprise apps > All applications → sélectionner l'app → Security > Permissions → revoir les permissions → Grant admin consent for [tenant]. (Variante App registrations → API permissions > Grant admin consent.)
3. Exposer une API avec scope + app role
Entra ID > App registrations > [app] > Expose an API > Add (Application ID URI api://{clientId}) > Add a scope (access_as_user, Who can consent: Admins and users). Puis App roles > Create app role (Allowed member types: Applications, ex. ToDoList.Read.All). Durcir : Enterprise App > Properties > Assignment required = Yes.
4. Enrôler une System-assigned MI et lui donner accès Key Vault
Sur la ressource (ex. App Service) → Settings > Identity > System assigned → On > Save (crée le SP). Puis Key Vault > Access control (IAM) > Add role assignment > Key Vault Secrets User > Managed identity > sélectionner l'App Service.
CLI :
az webapp identity assign -g rg-app -n myapp
az role assignment create --assignee <principalId> \
--role "Key Vault Secrets User" \
--scope $(az keyvault show -n mykv --query id -o tsv)
5. Configurer un FIC GitHub Actions sur une UAMI (OIDC, zéro secret)
Entra ID > onglet via la ressource Managed Identity (UAMI) > Settings > Federated credentials > Add Credential > scénario GitHub Actions deploying Azure resources → Organization, Repository, Entity = Environment (prod) → Name.
CLI :
az identity federated-credential create \
--name gh-prod --identity-name uami-prod -g rg-app \
--issuer "https://token.actions.githubusercontent.com" \
--subject "repo:org/repo:environment:prod" \
--audiences "api://AzureADTokenExchange"