Abus d'identités managées et de principaux de service Azure
Comment les attaquants abusent des principaux de service et identités managées Azure : secrets fuités, vol de jeton IMDS, identifiants fédérés, runbooks.
En bref. Les identités non humaines sont la majorité silencieuse des appelants Azure, et le déguisement préféré des intrus. Trois schémas : un principal de service dont le secret a fuité (variables CI/CD, dépôt, poste de travail) utilisé depuis une nouvelle IP ; un jeton d'identité managée récupéré auprès de l'Instance Metadata Service de la VM (169.254.169.254) et rejoué ailleurs ; et la persistance via des informations d'identification fédérées, des runbooks Automation, des Logic Apps ou des Functions s'exécutant sous une identité privilégiée. Dans les logs, la claim xms_mirid signale une identité managée, et « même identité, nouvelle IP » est le signal isolé le plus fort dont vous disposez.
Quand j'examine un abonnement compromis, les comptes humains sont généralement faciles : peu nombreux, horaires prévisibles, MFA dans les claims. Le plus dur, ce sont les dizaines d'identités applicatives qui appellent Azure Resource Manager toute la journée. C'est là que les attaquants se fondent dans le décor.
Principaux de service et identités managées, vus des logs
| Identité | Ce que c'est | Comment elle apparaît dans les claims de l'Activity Log |
|---|---|---|
| Principal de service (inscription d'application) | Identité d'application authentifiée par secret client, certificat ou information d'identification fédérée | appid + object ID, souvent idtyp: app ; caller est un GUID |
| Identité managée | Principal de service géré par Azure, lié à une ressource (affectée par le système) ou autonome (affectée par l'utilisateur) | Idem, plus xms_mirid = ID de la ressource VM / application / identité à laquelle elle appartient |
| Utilisateur | Compte humain | UPN, nom, amr (par ex. pwd, mfa) |
L'analyseur Azure Forensics classe les appelants de cette façon (claims d'abord, puis principalType, puis appelants en forme de GUID) et affiche le type dans l'onglet Entités. Dans les logs Key Vault et Storage, les mêmes claims apparaissent sous identity.claim et identity.requester.
Schéma 1 : un secret de principal de service fuité
L'accès initial se passe hors d'Azure : un secret commité dans un dépôt, affiché dans un log de CI ou volé sur le poste d'un développeur. Microsoft Entra ID voit la connexion (journaux de connexion des principaux de service) ; Azure voit la suite.
Signaux dans les logs Azure :
- Le principal appelle ARM depuis une IP jamais utilisée. Les runners CI ont un petit ensemble d'IP stables ou une plage cloud connue ; le VPS d'un attaquant n'est ni l'un ni l'autre.
- Le principal fait quelque chose qu'il n'a jamais fait : attributions de rôles, Run Command,
listKeys, modification de stratégies d'accès. - Le moment : les principaux de déploiement tournent quand les pipelines tournent. Une rafale à 02:14 un dimanche sans exécution de pipeline en dit long.
MITRE ATT&CK : T1078.004 Cloud Accounts. Comment le secret a fuité, et si de nouveaux secrets ont été ajoutés à l'application (T1098.001 Additional Cloud Credentials), est enregistré dans le journal d'audit Entra ID, analysé par l'outil voisin m365forensics.com.
Schéma 2 : vol de jeton d'identité managée via IMDS
N'importe quel processus d'une VM peut demander à l'Instance Metadata Service un jeton pour l'identité managée de la VM :
GET http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
Metadata: true
Microsoft énonce clairement la frontière de sécurité : tout code ou script s'exécutant sur une machine virtuelle peut demander et récupérer des jetons pour toutes les identités managées qui y sont disponibles (utiliser les identités managées sur une VM pour obtenir un jeton). L'en-tête Metadata est une atténuation contre les SSRF, pas un contrôle d'autorisation.
Ainsi, l'exécution de code sur une VM, via Run Command, un web shell ou une SSRF capable de poser des en-têtes, devient une identité cloud. L'attaquant copie le jeton porteur et l'utilise depuis sa propre machine jusqu'à son expiration (T1528 Steal Application Access Token).
Le signal est simple et fort : une identité managée utilisée depuis une IP qui n'est pas celle de son hôte. L'identité managée d'une VM atteint normalement Key Vault et le stockage depuis l'IP privée de la VM (via un point de terminaison de service ou privé) ou depuis une IP publique sortante stable. Le même object ID qui apparaît avec une adresse résidentielle ou de VPS, et un user agent curl, c'est du rejeu de jeton.
Schéma 3 : persistance par les identités
Une fois une identité privilégiée en main, l'attaquant en veut une qui survive aux réinitialisations de mot de passe et à la rotation des secrets :
| Persistance | Opération dans l'Activity Log | MITRE |
|---|---|---|
| Information d'identification fédérée sur une identité managée affectée par l'utilisateur (permet à un IdP externe d'obtenir des jetons pour elle) | Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/write | T1098.001 |
| Runbook ou webhook Automation, s'exécutant sous l'identité du compte Automation | Microsoft.Automation/automationAccounts/runbooks/write, …/webhooks/write, …/jobs/write | T1648 |
| Code de Logic App ou de Function modifié | Microsoft.Logic/workflows/write, Microsoft.Web/sites/functions/write, clés de fonction écrites | T1648 |
| Nouveau secret ou certificat sur une inscription d'application | Journal d'audit Entra ID, pas l'Activity Log | T1098.001 |
Les informations d'identification fédérées sont légitimes et courantes (GitHub Actions, identité de charge de travail AKS). La question est toujours : quel émetteur et quel sujet, créés par qui, et quelqu'un en est-il responsable ?
Ce que signale l'analyseur
| Règle | Détecte | Niveau |
|---|---|---|
AZ-ID-001 | Principal de service appelant ARM depuis une IP non vue pendant la période d'apprentissage de 72 heures | Moyen |
AZ-ID-002 | Identité managée utilisée depuis une nouvelle IP : Activity Log, Key Vault ou Storage | Haut |
AZ-RBAC-002 | Principal de service ou identité managée recevant Owner, Contributor ou un rôle de gestion des accès | Haut |
AZ-PER-001 | Runbook, webhook ou job Automation créé | Moyen |
AZ-PER-002 | Code de Logic App ou de Function modifié | Faible |
AZ-PER-003 | Information d'identification fédérée ajoutée à une identité managée | Haut |
Les règles « nouvelle IP » ont besoin d'historique : avec moins de 72 heures de logs avant l'activité suspecte, elles ne peuvent pas s'exécuter, et le bloc de couverture le signale. Faux positifs connus : runners CI dont l'IP change, VM redéployées avec une nouvelle IP privée.
Checklist de tri
- Listez chaque identité non humaine ayant un constat dans l'onglet Entités, puis ouvrez ses événements.
- Établissez la référence de chacune : IP habituelles, opérations habituelles, horaires habituels. Le premier écart marque le début de votre chronologie.
- Pour une identité managée : à quelle ressource est-elle liée (
xms_mirid) ? Y a-t-il eu exécution de code sur cette ressource peu avant (Run Command, extension, déploiement) ? - Pour un principal de service : quand son dernier identifiant a-t-il été ajouté, et par qui ? (Journal d'audit Entra.)
- Qu'a-t-elle touché ? Lectures Key Vault, lectures Storage, attributions de rôles. Chacune ouvre une nouvelle branche d'investigation.
Remédiation
- Faites tourner les secrets et certificats des principaux de service compromis ; supprimez les identifiants dont personne n'est responsable.
- Une identité managée n'a pas de secret à faire tourner. Contenez l'hôte (isolez et reconstruisez la VM) et réduisez les attributions de rôles de l'identité. Les jetons d'accès déjà volés restent valides jusqu'à leur expiration : surveillez un moment l'activité de l'identité depuis des IP étrangères, et faites tourner les secrets qu'elle pouvait lire.
- Supprimez les informations d'identification fédérées, runbooks et webhooks inconnus.
- Réduisez les privilèges : pas de Contributor sur tout l'abonnement pour l'identité d'une application web.