Skip to content

Cet outil n'est ni affilié à Google LLC, ni approuvé, ni sponsorisé par Google LLC. Google Cloud et Google Cloud Platform sont des marques de Google LLC. Les autres noms sont des marques de leurs propriétaires respectifs.

Emprunt d'identité de compte de service GCP : la chaîne

Retracer l'emprunt d'identité de comptes de service dans l'audit Google Cloud : GenerateAccessToken, SignBlob, délégation, actAs et Token Creator.

Publié le 6 min de lecture

En bref. L'emprunt d'identité d'un compte de service laisse deux traces. L'appel d'émission (GenerateAccessToken, GenerateIdToken, SignBlob, SignJwt sur iamcredentials.googleapis.com) est un journal Data Access : il n'existe que si la journalisation Data Access d'IAM était active. L'utilisation du jeton apparaît dans les journaux du service ciblé, avec principalEmail égal au compte de service et l'appelant réel dans authenticationInfo.serviceAccountDelegationInfo. Lisez les deux, et cherchez qui a reçu Token Creator ou Service Account User au départ.

L'emprunt d'identité est légitime et même recommandé : il remplace les clés téléchargeables par des jetons de courte durée. C'est aussi l'un des chemins d'élévation de privilèges les plus utilisés dans Google Cloud, car la permission qui le permet, iam.serviceAccounts.getAccessToken, est souvent accordée largement. Les travaux de Rhino Security Labs sur l'élévation de privilèges GCP listent getAccessToken, signBlob, signJwt et implicitDelegation comme autant de méthodes d'élévation distinctes.

Emprunt d'identité ou utilisation d'une clé

Google trace clairement la frontière dans sa documentation sur l'emprunt d'identité : l'emprunt implique deux identités (le principal authentifié et le compte de service), alors que l'authentification par clé n'en implique qu'une. Pour l'enquêteur :

MécanismeCe qui l'identifie dans les journaux
Clé gérée par l'utilisateurauthenticationInfo.serviceAccountKeyName (voir clé divulguée)
Emprunt d'identité (jeton émis via l'API IAM Credentials)serviceAccountDelegationInfo sur les appels, GenerateAccessToken dans les journaux Data Access
Compte de service associé (VM, Cloud Run, Cloud Functions)Appels en tant que compte de service, en général depuis l'IP de la charge de travail, sans nom de clé ni délégation
Fédération d'identité de charge de travailprincipalSubject du type principal://… ou informations de délégation avec un principal tiers

La troisième ligne compte : un jeton volé sur le serveur de métadonnées d'une VM (T1552.005) n'apparaît pas comme un emprunt d'identité ; il ressemble au compte de service de la VM, mais appelé depuis ailleurs.

Trace 1 : l'appel d'émission

D'après la page journaux d'audit de Service Account Credentials de Google, ces méthodes sont enregistrées sous cloudaudit.googleapis.com/data_access avec le service iamcredentials.googleapis.com. Activer les journaux d'audit Data Access pour l'API IAM les active aussi pour cette API.

protoPayload.serviceName="iamcredentials.googleapis.com"
protoPayload.methodName=("GenerateAccessToken" OR "GenerateIdToken" OR "SignBlob" OR "SignJwt")

Dans ces entrées, principalEmail est l'appelant (l'acteur réel, ou le maillon précédent de la chaîne) et le compte de service ciblé apparaît dans resource.labels.email_id et resourceName, comme le montrent les exemples de journaux de Google. SignBlob et SignJwt méritent une attention particulière : un JWT signé au nom d'un compte de service peut être échangé contre un jeton, et la signature de blobs permet de forger des URL signées.

Trace 2 : les appels faits avec le jeton

Tout appel d'API effectué avec un jeton obtenu par emprunt d'identité porte la chaîne :

"authenticationInfo": {
  "principalEmail": "deployer@PROJECT.iam.gserviceaccount.com",
  "serviceAccountDelegationInfo": [
    { "firstPartyPrincipal": { "principalEmail": "alice@example.com" } }
  ]
}

Cette information figure dans les journaux Admin Activity, toujours actifs. Même quand l'appel d'émission est invisible, les écritures faites avec le jeton nomment donc l'appelant réel. C'est souvent la seule trace dont on dispose.

Les chaînes

L'emprunt d'identité peut être chaîné : A emprunte l'identité de B, qui emprunte celle de C (le paramètre delegates de GenerateAccessToken ; chaque maillon a besoin d'une permission sur le compte de service suivant, que fournit le rôle Token Creator). La chaîne est enregistrée dans serviceAccountDelegationInfo sous forme de tableau. Pour la reconstituer :

  1. Partez de l'appel final et lisez la liste de délégation.
  2. Pour chaque maillon, cherchez la liaison IAM qui l'a permis : qui détient roles/iam.serviceAccountTokenCreator sur quel compte de service, et depuis quand.
  3. Vérifiez si l'une de ces liaisons a été ajoutée pendant la fenêtre d'incident (bindingDeltas ADD, voir abus de SetIamPolicy).

C'est à la troisième étape que les attaques se révèlent : une identité compromise peu privilégiée s'accorde Token Creator sur un compte de service puissant, puis émet des jetons pour lui (T1098.003, puis T1550.001).

actAs : l'emprunt d'identité par une ressource

Le rôle Service Account User (roles/iam.serviceAccountUser) accorde iam.serviceAccounts.actAs : le droit d'associer un compte de service à une ressource. Quelqu'un qui dispose d'actAs sur un compte de service puissant et de compute.instances.create peut démarrer une VM qui s'exécute sous ce compte et lire son jeton sur le serveur de métadonnées. Les exemples de journaux de Google montrent le contrôle sous la forme d'une entrée authorizationInfo avec "permission": "iam.serviceAccounts.actAs" et "granted": true dans l'appel de création de la ressource.

Quand vous passez en revue des créations de VM, de services Cloud Run ou de Cloud Functions pendant un incident, lisez donc authorizationInfo et le compte de service indiqué dans la requête, pas seulement l'auteur de la création.

Signaux d'alerte

  • Un utilisateur humain ou une IP externe qui émet des jetons pour un compte de service normalement réservé à une charge de travail.
  • Des appels GenerateAccessToken qui commencent juste après un octroi de Token Creator.
  • De longues chaînes avec, au milieu, un compte de service dont personne n'est responsable.
  • Des SignJwt ou SignBlob venant de principaux qui n'ont aucune raison de signer quoi que ce soit.
  • Des appels avec informations de délégation provenant d'un principal extérieur à vos domaines.

Ce que montre l'analyseur

Dans l'analyseur :

  • sa_impersonation (moyenne, élévation de privilèges, T1550.001) se déclenche sur les appels réussis GenerateAccessToken, GenerateIdToken, SignBlob et SignJwt, hors agents de service gérés par Google.
  • token_creator_granted (haute) se déclenche sur un ADD de Token Creator, Service Account User, Service Account Key Admin ou Workload Identity User.
  • L'onglet Entités indique, pour chaque principal, les identités qui ont emprunté la sienne (d'après serviceAccountDelegationInfo), et le détail d'une entrée de journal affiche le champ correspondant.

La limite est celle décrite plus haut : sans journaux Data Access d'IAM, seule la seconde trace existe, et l'outil avertit quand un export ne contient aucun journal Data Access. Voir les limites des journaux Data Access.

Remédiation

Retirez les liaisons Token Creator / Service Account User dont personne n'a besoin, préférez les accorder sur des comptes de service précis plutôt que sur le projet, et passez en revue les principaux capables d'emprunter l'identité de vos comptes de service les plus privilégiés. La page permissions des comptes de service de Google détaille ce que chaque rôle permet.

Questions fréquentes

Comment voir qui a emprunté l'identité d'un compte de service dans Google Cloud ?

À deux endroits. L'appel d'émission du jeton (GenerateAccessToken, GenerateIdToken, SignBlob, SignJwt sur iamcredentials.googleapis.com) est un journal Data Access dont le principalEmail est l'appelant réel. Les appels effectués avec le jeton obtenu indiquent l'appelant réel dans authenticationInfo.serviceAccountDelegationInfo.

Pourquoi GenerateAccessToken n'apparaît-il pas dans mes journaux ?

Parce qu'il est enregistré comme journal d'audit Data Access (ADMIN_READ), désactivé par défaut. Activer les journaux Data Access pour l'API IAM les active aussi pour l'API Service Account Credentials.

Pour aller plus loin

Articles liés

Cet outil n'est ni affilié à Google LLC, ni approuvé, ni sponsorisé par Google LLC. Google Cloud et Google Cloud Platform sont des marques de Google LLC. Les autres noms sont des marques de leurs propriétaires respectifs.