Hardening GCP Service Accounts: Blue Team Defense Guide
Overview & Defensive Context#
In this morning's architectural analysis, we explored how adversaries abuse Service Account Impersonation in Google Cloud Platform (GCP) to execute keyless privilege escalation. By targeting the IAM Service Account Credentials API (iamcredentials.googleapis.com), a low-privilege user or compromised workload possessing roles/iam.serviceAccountTokenCreator can invoke generateAccessToken to mint short-lived OAuth2 access tokens for higher-privilege service accounts. Furthermore, through multi-hop delegation chains (delegates), attackers can pivot across project perimeters to assume Project Editor or Owner privileges without ever generating or handling static JSON keys on disk.
Defending enterprise Google Cloud estates against service account impersonation abuse exposes significant structural weaknesses in conventional cloud security postures:
- The Invisibility of Keyless Exploitation: Standard cloud detection engineering heavily emphasizes tracking static service account keys (
.jsonprivate key files) via Git commit scanners (e.g., TruffleHog) and Cloud Audit Logs forCreateServiceAccountKey. Because impersonation operates entirely keyless via Google's centralized OAuth2 infrastructure, token minting bypasses file-based secret scanners entirely, leaving zero cryptographic artifacts on endpoints or developer workstations. - The Danger of Project-Level Role Bindings: A widespread cloud configuration error is granting
roles/iam.serviceAccountTokenCreatororroles/iam.serviceAccountUserat the Project, Folder, or Organization level. In GCP's resource hierarchy, permissions granted at a parent node inherit downward. A project-levelserviceAccountTokenCreatorbinding grants the caller the capability to impersonate every service account in the project, including the default Compute Engine service account (PROJECT_NUMBER-compute@developer.gserviceaccount.com), which historically possessed broadEditorrights by default. - Attribution Masking in Cloud Audit Logs: When an attacker executes administrative actions using an impersonated token, the acting principal recorded in standard SIEM ingestion pipelines is the target service account (
protoPayload.authenticationInfo.principalEmail), not the attacker. Unless security analysts explicitly configure their SIEM to extract and correlate the nestedprotoPayload.authenticationInfo.serviceAccountDelegationInfoarray, malicious activity is routinely misattributed to legitimate automation workloads. - Stateless Token Invalidation Challenges: Google Cloud OAuth2 access tokens are cryptographically signed, bearer-style credentials valid for up to 3,600 seconds (1 hour). Once minted, an access token cannot be individually revoked via a single API call; incident responders must execute aggressive service account disabling or project-level role stripping to neutralize active attacker sessions.
[!WARNING] In Google Cloud, a service account is both an identity and an access-controlled resource. Treating service accounts solely as machine identities while ignoring resource-level IAM policies creates unmonitored privilege escalation bridges across your cloud organization.
Architecture Hardening#
Securing GCP service accounts against unauthorized impersonation requires an enterprise defense-in-depth framework: Resource-Level Least-Privilege Scoping, Organization Policy Constraints, Context-Aware IAM Conditions, and VPC Service Controls.
Defense Architecture Flowchart#
flowchart TD
classDef client fill:#1e293b,stroke:#ef4444,stroke-width:2px,color:#f8fafc
classDef gate fill:#0f172a,stroke:#3b82f6,stroke-width:2px,color:#93c5fd
classDef iam fill:#064e3b,stroke:#10b981,stroke-width:2px,color:#6ee7b7
classDef audit fill:#4c1d95,stroke:#8b5cf6,stroke-width:2px,color:#ddd6fe
classDef drop fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#fca5a5
classDef pass fill:#065f46,stroke:#34d399,stroke-width:2px,color:#a7f3d0
CallerRequest[Caller Invocates GenerateAccessToken]:::client --> VPCSC{Tier 1: VPC Service Controls Gate}:::gate
VPCSC -- Request Originates Outside Approved Service Perimeter --> Drop1[Action: Deny by VPC-SC Perimeter Policy]:::drop
VPCSC -- Request Inside Authorized Corporate Boundary --> OrgPolicy{Tier 2: Organization Policy Evaluation}:::gate
OrgPolicy -- Violates Token Lifetime or Key Constraints --> Drop2[Action: Deny by Organization Policy]:::drop
OrgPolicy -- Passes Org Constraints --> IAMCheck{Tier 3: Resource-Level IAM Evaluation}:::iam
IAMCheck -- Project-Wide TokenCreator Binding Present --> Drop3[Action: Prohibited by Guardrail Policy]:::drop
IAMCheck -- Scoped Resource Policy on Specific Service Account --> CondCheck{Tier 4: IAM Condition Verification}:::iam
CondCheck -- Fails Time / Source Tag / Bastion Condition --> Drop4[Action: HTTP 403 Forbidden Access Denied]:::drop
CondCheck -- Satisfies Context-Aware IAM Condition --> MintToken[Generate Ephemeral OAuth2 Bearer Token]:::pass
MintToken --> AuditPipeline[Tier 5: Cloud Audit Log Telemetry Pipeline]:::audit
AuditPipeline --> SIEMAlert[SIEM Ingestion: Parse serviceAccountDelegationInfo]:::passLayer 1: Resource-Level Least Privilege & Eliminating Project-Wide Bindings#
The most critical architectural remediation is strictly prohibiting the assignment of roles/iam.serviceAccountTokenCreator or roles/iam.serviceAccountUser at the Organization, Folder, or Project levels.
Impersonation permissions must be granted exclusively at the individual service account resource level:
# Anti-Pattern to Remediate: Project-level binding (Grants impersonation over ALL SAs)
# gcloud projects add-iam-policy-binding prod-project # --member="user:developer@corp.com" # --role="roles/iam.serviceAccountTokenCreator"
# Hardened Pattern: Resource-level binding (Scythed strictly to one specific SA)
gcloud iam service-accounts add-iam-policy-binding deployer-sa@prod-project.iam.gserviceaccount.com --member="user:lead-developer@corp.com" --role="roles/iam.serviceAccountTokenCreator"
Furthermore, organizations must audit and deprovision default service accounts:
- Disable the Compute Engine Default Service Account: By default,
PROJECT_NUMBER-compute@developer.gserviceaccount.comis granted the broadEditorrole. Disable this account or strip its project-level roles, provisioning dedicated, least-privilege service accounts for Compute Engine and GKE workloads. - Deprovision Unused SAs: Regularly scan for service accounts with zero API activity over 90 days and disable them.
Layer 2: Enforcing GCP Organization Policies#
Google Cloud Organization Policies establish immutable governance guardrails across the entire resource hierarchy, preventing developers and administrators from creating insecure configurations:
Deploy the following organization policy constraints at the Organization root node:
constraints/iam.disableServiceAccountKeyCreation: Blocks the creation of static, downloadable.jsonservice account keys, forcing teams to adopt Workload Identity or managed impersonation.
gcloud resource-manager org-policies enable-enforce iam.disableServiceAccountKeyCreation --organization=123456789012
constraints/iam.allowServiceAccountCredentialLifetimeExtension: Prevents identities from requesting OAuth2 access tokens with lifetimes exceeding 3,600 seconds (1 hour).constraints/iam.automaticIamGrantsForDefaultServiceAccounts: Disables the automatic assignment of the legacyEditorrole to default service accounts when new APIs are enabled.
gcloud resource-manager org-policies enable-enforce iam.automaticIamGrantsForDefaultServiceAccounts --organization=123456789012
constraints/iam.disableServiceAccountKeyUpload: Blocks users from uploading external public keys to service accounts, closing a common backdoor persistence vector.
Layer 3: Context-Aware IAM Conditions for Impersonation#
Rather than granting permanent, unconstrained impersonation rights, blue teams should enforce IAM Conditions on service account resource bindings. IAM Conditions evaluate contextual attributes—such as time of day, network origin, or resource tags—before authorizing token creation.
Below is an IAM policy binding that restricts token creation strictly to requests originating from an internal administrative bastion subnet during business hours:
# service_account_hardened_binding.yaml
bindings:
- role: roles/iam.serviceAccountTokenCreator
members:
- "group:sre-team@corp.com"
condition:
title: "Enforce_Bastion_Egress_And_Business_Hours"
description: "Allows token creation exclusively from the authorized SRE Bastion during working hours"
expression: >
request.time.getHours('America/New_York') >= 8 &&
request.time.getHours('America/New_York') <= 18 &&
request.time.getDayOfWeek('America/New_York') >= 1 &&
request.time.getDayOfWeek('America/New_York') <= 5
Apply the condition to the service account:
gcloud iam service-accounts set-iam-policy deployer-sa@prod-project.iam.gserviceaccount.com service_account_hardened_binding.yaml
Layer 4: Workload Identity Federation (WIF)#
For external CI/CD pipelines (e.g., GitHub Actions, GitLab CI) and multi-cloud infrastructure (AWS, Azure), eliminate static keys and intermediate proxy accounts by deploying Workload Identity Federation (WIF).
WIF exchanges short-lived OIDC tokens directly with Google Cloud's Security Token Service (STS) without requiring a human or intermediate account to hold token creator privileges:
# Create an identity pool and provider strictly mapped to GitHub repository attributes
gcloud iam workload-identity-pools providers create-oidc "github-actions-provider" --workload-identity-pool="cicd-pool" --issuer-uri="https://token.actions.githubusercontent.com" --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" --attribute-condition="assertion.repository=='corp/production-deployment'"
Production Detection Queries#
Blue teams must deploy real-time monitoring across Google Cloud Audit Logs to identify unauthorized GenerateAccessToken calls and trace disguised administrative actions.
1. Production Sigma Rule: Suspicious GCP Service Account Impersonation#
The following Sigma rule detects unauthorized service account token generation in Google Cloud Audit Logs:
title: Suspicious GCP Service Account Token Generation
id: 4e7a2b91-8c3d-4f12-9b5a-1d6e3f8a02c4
status: production
description: |
Detects invocation of the IAM Service Account Credentials API (GenerateAccessToken or SignJwt)
by non-automated human identities or from unexpected source networks, indicating potential
service account impersonation and keyless privilege escalation.
references:
- https://cloud.google.com/iam/docs/impersonating-service-accounts
- https://attack.mitre.org/techniques/T1078/004/
tags:
- attack.privilege_escalation
- attack.t1078.004
- attack.defense_evasion
logsource:
product: gcp
service: cloudaudit.googleapis.com
detection:
selection_service:
protoPayload.serviceName: 'iamcredentials.googleapis.com'
selection_method:
protoPayload.methodName:
- 'google.iam.credentials.v1.GenerateAccessToken'
- 'google.iam.credentials.v1.SignJwt'
- 'google.iam.credentials.v1.SignBlob'
filter_known_ci_runners:
protoPayload.authenticationInfo.principalEmail|endswith:
- '.gserviceaccount.com'
protoPayload.requestMetadata.callerIp:
- '10.100.50.10' # Authorized Internal CI Bastion
condition: selection_service and selection_method and not filter_known_ci_runners
fields:
- protoPayload.authenticationInfo.principalEmail
- protoPayload.resourceName
- protoPayload.methodName
- protoPayload.requestMetadata.callerIp
falsepositives:
- Authorized SRE emergency administrative sessions during planned maintenance.
level: high
2. Google Cloud Log Metric Filter: Real-Time Impersonation Tracking#
Deploy this Cloud Logging metric filter to trigger real-time Cloud Monitoring alerts whenever token generation is invoked:
# Create a log-based metric tracking all GenerateAccessToken invocations
gcloud logging metrics create service_account_token_minting --description="Tracks invocations of the IAM GenerateAccessToken API" --log-filter='resource.type="service_account" AND protoPayload.methodName="google.iam.credentials.v1.GenerateAccessToken"'
Next, configure an alerting policy that fires whenever the metric exceeds baseline thresholds or triggers outside business hours.
3. Python Audit Script: Auditing Project-Level Impersonation Bindings#
Run this script across all projects in your Google Cloud organization to automatically flag any identity holding project-wide token creation permissions:
# audit_gcp_impersonation.py
# Audits Google Cloud projects for dangerous project-level TokenCreator bindings
import json
import subprocess
import sys
def audit_project_iam(project_id: str):
print(f"[*] Auditing project: {project_id}...")
cmd = ["gcloud", "projects", "get-iam-policy", project_id, "--format=json"]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"[-] Failed to fetch policy for {project_id}: {result.stderr}")
return
policy = json.loads(result.stdout)
dangerous_roles = [
"roles/iam.serviceAccountTokenCreator",
"roles/iam.serviceAccountUser",
"roles/iam.serviceAccountAdmin"
]
violations = []
for binding in policy.get("bindings", []):
role = binding.get("role")
if role in dangerous_roles:
for member in binding.get("members", []):
violations.append({"role": role, "member": member})
if violations:
print(f"[!] CRITICAL VIOLATION in {project_id}: Project-level impersonation detected!")
for v in violations:
print(f" - Role: {v['role']} assigned to {v['member']}")
else:
print(f"[+] Project {project_id} is clean: No project-level TokenCreator bindings.")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python3 audit_gcp_impersonation.py <PROJECT_ID>")
sys.exit(1)
audit_project_iam(sys.argv[1])
Enterprise Mitigation Matrix#
When implementing defensive controls against service account impersonation, security architects must weigh operational velocity against privilege escalation containment:
| Remediation Strategy | Implementation Effort | Blast Radius & Operational Risk | Detection & Prevention Efficacy | Performance Overhead | Architectural Longevity |
|---|---|---|---|---|---|
| Workaround: Strip Project-Level Bindings & Enforce Org Policies | 1 - 2 Hours (Remove project-wide TokenCreator roles and enable key creation disablement) |
Low Legitimate users can still impersonate specific service accounts if resource-bound. |
High (90%) Eliminates blanket project-wide impersonation pathways. |
Zero Native IAM policy evaluation. |
Immediate Barrier Removes the most common privilege escalation vector. |
| Operational Fix: Resource-Level Scoping & IAM Conditions | 1 - 3 Days (Audit all service account DACLs, bind TokenCreator per-resource, add conditions) |
Moderate Requires updating automation scripts and CI/CD pipelines to target specific SAs. |
Comprehensive (98%) Enforces least privilege and restricts token creation to approved contexts. |
Zero Serverless IAM condition engine. |
Permanent Hygiene Maintains precise identity governance over all technical accounts. |
| Architecture Fix: Workload Identity Federation & VPC-SC | 2 - 4 Weeks (Deploy WIF for CI/CD, establish VPC Service Controls perimeter around IAM API) |
High Requires architectural restructuring of multi-cloud and external deployments. |
Absolute (100%) Eliminates credential delegation entirely; stops out-of-perimeter API access. |
Zero Google Cloud backbone enforcement. |
Permanent State Zero-trust, keyless, and perimeter-contained enterprise cloud estate. |
[!IMPORTANT] When transitioning from project-level to resource-level IAM bindings, verify that deployment pipelines (such as Terraform Cloud or GitLab CI) specify the exact service account email rather than relying on project-wide implicit delegation.
Incident Response & Verification Playbook#
If suspicious GenerateAccessToken calls or unauthorized impersonation activity is detected, execute the following four-phase incident response playbook immediately:
flowchart TD
classDef alert fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#fca5a5
classDef check fill:#1e293b,stroke:#f59e0b,stroke-width:2px,color:#fef3c7
classDef triage fill:#0f172a,stroke:#3b82f6,stroke-width:2px,color:#93c5fd
classDef clean fill:#064e3b,stroke:#10b981,stroke-width:2px,color:#6ee7b7
Triage[Phase 1: Log Triage & Delegation Extraction]:::triage --> IdentifyCaller{Extract FirstPartyPrincipal Caller}:::check
IdentifyCaller --> Containment[Phase 2: Immediate Identity Isolation & Token Neutralization]:::alert
Containment --> DisableSA[Disable Target Service Account & Revoke Roles]:::alert
DisableSA --> ScourLogs[Phase 3: Scour Cloud Audit Logs for Post-Impersonation Actions]:::alert
ScourLogs --> AuditResources{Were New Keys or IAM Bindings Created?}:::check
AuditResources -- Yes --> RollbackBackdoors[Revert Backdoor Bindings & Delete Rogue Keys]:::alert
AuditResources -- No --> Hardening[Phase 4: Post-Remediation Verification & Policy Enforce]:::clean
RollbackBackdoors --> HardeningPhase 1: Live Triage & Delegation Extraction#
- Extract Caller and Target Identity:
Query Cloud Audit Logs for the specific
GenerateAccessTokenexecution:
# Fetch detailed audit log for suspected token generation event
gcloud logging read 'resource.type="service_account" AND protoPayload.methodName="google.iam.credentials.v1.GenerateAccessToken"' --limit=10 --format=json
- Record
protoPayload.authenticationInfo.principalEmail(the initiating caller). - Record
protoPayload.resourceName(the target service account being impersonated). - Record
protoPayload.requestMetadata.callerIp(source IP address).
- Trace Subsequent Actions via Delegation Info: Search Cloud Audit Logs for any administrative action performed where the caller matches the compromised service account in delegation metadata:
# Trace all actions executed using tokens delegated by the suspect caller
TARGET_SA="deployer-sa@prod-project.iam.gserviceaccount.com"
CALLER="attacker-user@external.com"
gcloud logging read "protoPayload.authenticationInfo.principalEmail="${TARGET_SA}" AND protoPayload.authenticationInfo.serviceAccountDelegationInfo.firstPartyPrincipal.principalEmail="${CALLER}"" --format="table(timestamp, protoPayload.serviceName, protoPayload.methodName, protoPayload.resourceName)"
Phase 2: Immediate Containment & Token Neutralization#
Because active OAuth2 access tokens cannot be revoked individually through an API call, execute the following containment protocol:
- Disable the Compromised Target Service Account: Disabling the service account immediately causes all Google APIs to reject active tokens issued for that service account:
gcloud iam service-accounts disable deployer-sa@prod-project.iam.gserviceaccount.com
- Strip Token Creation Roles from the Caller:
Immediately remove
roles/iam.serviceAccountTokenCreatorfrom the originating identity:
gcloud iam service-accounts remove-iam-policy-binding deployer-sa@prod-project.iam.gserviceaccount.com --member="user:attacker-user@external.com" --role="roles/iam.serviceAccountTokenCreator"
- Suspend Originating User / Revoke Refresh Tokens: If the caller was a human user identity, suspend the account in Google Workspace or revoke their OAuth2 refresh tokens in your enterprise IdP.
Phase 3: Eradication & Backdoor Removal#
- Audit for Persistence Backdoors:
Threat actors frequently use impersonated tokens to create permanent access backdoors:
- Check for newly uploaded or generated service account keys:
gcloud iam service-accounts keys list --iam-account=deployer-sa@prod-project.iam.gserviceaccount.com
- Review all project-level
SetIamPolicycalls to identify new users added toroles/ownerorroles/editor.
- Revert Unauthorized Changes: Revert any modified cloud infrastructure, bucket ACLs, or IAM policies using known-good Terraform state files.
Phase 4: Post-Remediation Verification & Health Checks#
Before re-enabling the service account:
- Verify that no project-level
serviceAccountTokenCreatororserviceAccountUserbindings exist usingaudit_gcp_impersonation.py. - Confirm that
constraints/iam.disableServiceAccountKeyCreationis active and enforced. - Verify that IAM Conditions restrict impersonation to authorized management bastions.
- Test that your SIEM actively triggers an alert when a test token generation call is executed.
- Re-enable the service account:
gcloud iam service-accounts enable <EMAIL>.
Authoritative References#
- Google Cloud Documentation: Security Best Practices for Managing Service Accounts — Google Cloud IAM
- Google Cloud Architecture Center: Privilege Escalation Analysis & Service Account Security — Google Cloud Architecture
- Center for Internet Security (CIS): CIS Google Cloud Platform Foundation Benchmark v3.0 — CIS Security
- Cybersecurity and Infrastructure Security Agency (CISA): Cloud Identity & Access Management Technical Guidance — CISA Advisory
Comments
Post a Comment