Skip to content

This tool is not affiliated with, endorsed by or sponsored by Google LLC. Google Cloud and Google Cloud Platform are trademarks of Google LLC. Other names are trademarks of their respective owners.

GCP service account impersonation: tracing the chain

Trace service account impersonation in Google Cloud audit logs: GenerateAccessToken, SignBlob, serviceAccountDelegationInfo, actAs and Token Creator grants.

Published on 5 min read

TL;DR. Service account impersonation leaves two traces. The minting call (GenerateAccessToken, GenerateIdToken, SignBlob, SignJwt on iamcredentials.googleapis.com) is a Data Access log, so it only exists if IAM Data Access logging was on. The use of the token appears in the target service's logs with principalEmail set to the service account and the real caller in authenticationInfo.serviceAccountDelegationInfo. Read both, and look for who was granted Token Creator or Service Account User in the first place.

Impersonation is legitimate and even recommended: it replaces downloadable keys with short-lived tokens. It is also one of the most used privilege-escalation paths in Google Cloud, because the permission that allows it, iam.serviceAccounts.getAccessToken, is often granted broadly. Rhino Security Labs' GCP privilege escalation research lists getAccessToken, signBlob, signJwt and implicitDelegation as separate escalation methods.

Impersonation versus using a key

Google draws the line clearly in its impersonation documentation: impersonation involves two identities (the authenticated principal and the service account), whereas authenticating with a key involves only one. For an investigator:

MechanismWhat identifies it in the logs
User-managed keyauthenticationInfo.serviceAccountKeyName (see leaked key)
Impersonation (token minted via IAM Credentials API)serviceAccountDelegationInfo on the calls, GenerateAccessToken in Data Access logs
Attached service account (VM, Cloud Run, Cloud Functions)Calls as the service account, typically from the workload's IP, no key name, no delegation
Workload Identity FederationprincipalSubject like principal://… or delegation info with a third-party principal

The third row matters: a token stolen from a VM's metadata server (T1552.005) is not impersonation in the logs; it looks like the VM's service account, but called from somewhere else.

Trace 1: the minting call

According to Google's Service Account Credentials audit logging page, these methods are recorded under cloudaudit.googleapis.com/data_access with service iamcredentials.googleapis.com. Enabling Data Access audit logs for the IAM API also enables them for this API.

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

In these entries, principalEmail is the caller (the real actor, or the previous link in the chain) and the target service account appears in resource.labels.email_id and resourceName, as shown in Google's example logs. SignBlob and SignJwt deserve special attention: signing a JWT as a service account can be exchanged for a token, and signing blobs can forge signed URLs.

Trace 2: the calls made with the token

Any API call made with an impersonated token carries the chain:

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

This is available in Admin Activity logs, which are always on. So even when the minting call is invisible, the writes made with the token still name the real caller. That is often the only trace you get.

Chains

Impersonation can be chained: A impersonates B, which impersonates C (the delegates parameter of GenerateAccessToken; each hop needs permission on the next service account, which the Token Creator role provides). The chain is recorded in serviceAccountDelegationInfo as an array. When you rebuild it:

  1. Start from the final call and read the delegation list.
  2. For each hop, look for the IAM binding that allowed it: who holds roles/iam.serviceAccountTokenCreator on which service account, and since when.
  3. Check whether any of those bindings were added during the incident window (bindingDeltas ADD, see SetIamPolicy abuse).

The third step is where attacks show: a compromised low-privilege identity grants itself Token Creator on a powerful service account, then mints tokens for it (T1098.003, then T1550.001).

actAs: impersonation through a resource

The Service Account User role (roles/iam.serviceAccountUser) grants iam.serviceAccounts.actAs: the right to attach a service account to a resource. Someone with actAs on a powerful service account and compute.instances.create can start a VM running as that account and read its token from the metadata server. Google's example logs show the check as an authorizationInfo entry with "permission": "iam.serviceAccounts.actAs" and "granted": true on the resource creation call.

So when reviewing VM, Cloud Run or Cloud Functions creations during an incident, read authorizationInfo and the service account set in the request, not only who created the resource.

Red flags

  • A human user or an external IP minting tokens for a service account that is normally only used by a workload.
  • GenerateAccessToken calls that start right after a Token Creator grant.
  • Long chains with a service account in the middle that nobody owns.
  • SignJwt or SignBlob from principals that have no reason to sign anything.
  • Calls with delegation info from a principal outside your domains.

What the analyzer shows

In the analyzer:

  • sa_impersonation (medium, privilege escalation, T1550.001) fires on successful GenerateAccessToken, GenerateIdToken, SignBlob and SignJwt calls, excluding Google-managed service agents.
  • token_creator_granted (high) fires on ADD of Token Creator, Service Account User, Service Account Key Admin or Workload Identity User.
  • The Entities tab shows, for each principal, the identities it was impersonated by (from serviceAccountDelegationInfo), and the log entry detail shows "Impersonated by".

The limit is the one above: without IAM Data Access logs, only the second trace exists, and the tool warns when an export contains no Data Access logs at all. See Data Access logs limitations.

Remediation

Remove the Token Creator / Service Account User bindings nobody needs, prefer granting them on individual service accounts rather than on the project, and review which principals can impersonate your most privileged service accounts. Google's service account permissions page lists what each role allows.

Frequently asked questions

How do I see who impersonated a service account in Google Cloud?

Two places. The token minting call (GenerateAccessToken, GenerateIdToken, SignBlob, SignJwt on iamcredentials.googleapis.com) is a Data Access log whose principalEmail is the real caller. Calls made with the resulting token list the real caller in authenticationInfo.serviceAccountDelegationInfo.

Why can't I find GenerateAccessToken in my logs?

Because it is recorded as a Data Access audit log (ADMIN_READ), which is off by default. Enabling Data Access logs for the IAM API also enables them for the Service Account Credentials API.

Further reading

Related articles

This tool is not affiliated with, endorsed by or sponsored by Google LLC. Google Cloud and Google Cloud Platform are trademarks of Google LLC. Other names are trademarks of their respective owners.