The Compute Engine and App Engine default service accounts are attached to workloads silently: create a VM, deploy a Cloud Run service or build a GKE cluster without naming a service account and the workload runs as the project's shared default identity. Every workload attached to that one identity shares its permissions, so a compromise of the smallest VM can reach whatever the busiest service needed. This runbook finds every resource running as a default service account across a Google Cloud organisation, shows how to check what each one actually does, and moves workloads to dedicated user-managed accounts without outages. It is for cloud security and platform engineers. Removing the Editor role from default accounts is a separate task covered in How to Find GCP Service Accounts With Owner or Editor Roles; this page is about where the accounts are attached and used.
This is an independent guide from NHI Mgmt Group, based on Google Cloud's public documentation as of November 2026. It is not sponsored or reviewed by Google. Product features change, so confirm settings against Google's current documentation.
Key takeaways
- Know the two emails.
[email protected]is the Compute Engine default;[email protected]is the App Engine default. Google classes both as user-managed accounts that you are responsible for. - The Compute default reaches further than Compute. Google documents that Cloud Run and GKE nodes use it when no account is specified, and since the 2024 change new projects run Cloud Build builds as it by default.
- Check scopes as well as roles. A VM with the default account gets a narrow default scope set; one created with the
cloud-platformscope exposes every IAM role the account holds to code on the VM. - Move workloads, do not delete the account. Google warns against deleting the Compute default account; attach dedicated accounts to each workload, then disable and block the default with organisation policy.
- Prevent with constraints.
iam.automaticIamGrantsForDefaultServiceAccountsstops the Editor grant andconstraints/container.managed.disallowDefaultComputeServiceAccountstops GKE nodes using the default.
When you need this
- Least privilege programme: you cannot cut a default account's roles until you know which workloads rely on them. Google warns that changing the Compute default account's roles affects every VM running as that account.
- Older organisations: the automatic Editor grant is blocked by default only in organisations created after 3 May 2024. In older ones, every workload on a default account may hold project Editor.
- Incident scoping: if one VM or container is compromised, the attacker can request tokens for its attached account from the metadata server (ATT&CK T1552.005). Knowing what else runs as the same identity defines the blast radius. See the Cloud Instance Metadata Services Compared Guide.
- Audit evidence: controls such as NIST SP 800-53 AC-6 and AC-2 expect a named owner and a defined purpose for each account; a shared default account has neither.
Before you start
| Where defaults appear | How the default gets attached | How to see it | How to change it |
|---|---|---|---|
| Compute Engine VMs | No service account chosen at creation | gcloud compute instances describe: serviceAccounts email and scopes | Stop VM, set-service-account, start VM |
| Cloud Run services and jobs | No service identity set at deploy | gcloud run services describe --format export: serviceAccountName | gcloud run services update --service-account (new revision) |
| GKE node pools | No node service account set | Node pool config in console or node-pools describe | New node pool with a custom account, then migrate workloads |
| Cloud Build | New projects since May to June 2024 default to the Compute default account; older projects use the Cloud Build legacy service account | Build and trigger configuration | Specify a user-specified service account on triggers and builds |
| App Engine | App Engine apps run as the App Engine default unless configured otherwise | App and service settings | Configure a user-managed account where the runtime supports it |
Discovery needs read access only: roles/browser or viewer roles on the organisation for listing, Compute, Run and Container viewer roles in projects, and roles/policyanalyzer.activityAnalysisViewer for activity data. Changing attachments later needs iam.serviceAccounts.actAs (in roles/iam.serviceAccountUser) on the new account. Keep the two roles separate.
Step-by-step
Steps 1 to 5 are read-only. Steps 6 and 7 change workloads and need an agreed window. Step 8 is reversible for 30 days.
- List projects and build the default emails. For each project record the project ID and number, since the Compute default email uses the number:
Check whether each default account exists and is enabled withgcloud projects list --format="table(projectId,projectNumber)"gcloud iam service-accounts list --project=PROJECT_ID. - Find VMs running as a default account. Per project:
Flag every instance whosegcloud compute instances list --project=PROJECT_ID \ --format="json(name,zone,status,serviceAccounts)"serviceAccounts[].emailends in[email protected]and record itsscopes. Rank instances withhttps://www.googleapis.com/auth/cloud-platformhighest. Instances using only the default scope set (devstorage.read_only,logging.write,monitoring.write,service.management.readonly,servicecontrol,trace.append) are constrained by scope as well as by roles. Include instance templates and managed instance groups, which recreate VMs with whatever account the template names. - Find Cloud Run services and GKE node pools on the default. For Cloud Run, export each service and read
spec.template.spec.serviceAccountName; a missing value or the Compute default email means the default identity:
For GKE, list clusters and node pools and read each pool's configured service account; Google documents that nodes use the Compute default account unless a custom one is set. Node pools on the default also give every pod without Workload Identity Federation the node's identity, so check those clusters with the GKE Identity Hardening Guide.gcloud run services describe SERVICE --region=REGION --format export - Check Cloud Build. For each project, record whether builds and triggers name a service account. Google documents that projects whose first build ran after the 2024 change default to the Compute default account, while older projects keep the Cloud Build legacy service account, and that triggers must specify an account unless the project default is the legacy one.
- Measure what each default account actually does. Last authentication per account (a Pre-GA feature, dates only):
An account with nogcloud policy-intelligence query-activity \ --activity-type=serviceAccountLastAuthentication --project=PROJECT_IDlastAuthenticatedTimein the observation period has not authenticated. For accounts that are used, query Cloud Audit Logs in Logs Explorer forprotoPayload.authenticationInfo.principalEmailequal to the default email, grouped byprotoPayload.serviceNameandprotoPayload.methodName. That list of services and methods is the starting point for each workload's new, narrow role set. Role recommendations also help for bindings older than 90 days. See the Google Cloud Audit Logs and Log Sinks Guide. - Create one dedicated account per workload and grant only what step 5 showed. Use Policy Simulator before removing anything from the default account. For GKE nodes, create a custom node account with
roles/container.defaultNodeServiceAccount, the minimum Google documents:gcloud iam service-accounts create SA_NAME gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com" \ --role=roles/container.defaultNodeServiceAccount - Re-attach workloads. VMs must be stopped first:
Google recommends thegcloud compute instances stop VM_NAME gcloud compute instances set-service-account VM_NAME \ --service-account=SA_EMAIL --scopes=cloud-platform gcloud compute instances start VM_NAMEcloud-platformscope with access controlled by IAM roles, which is safe only once the new account holds narrow roles. Cloud Run:gcloud run services update SERVICE --service-account SA_EMAIL. GKE: add a node pool with the custom account, cordon and drain the old pool, then remove it. Update instance templates and infrastructure as code so the default does not return on the next deploy. - Disable, do not delete, the default. When step 5 shows no authentication for a full business cycle, disable the account with
gcloud iam service-accounts disable. Google warns that disabling or deleting it can break dependent applications and that deleted accounts can be recovered only within 30 days; for the Compute default, Google advises disallowing it through organisation policy rather than deleting it.
Prioritise the work
| Finding | Priority | Reason |
|---|---|---|
Default account with Editor, attached to an internet-facing VM or Cloud Run service with cloud-platform scope | 1 | A web exploit becomes project Editor through the metadata server |
| GKE node pool on the default account, workloads without Workload Identity Federation | 1 | Every pod can use the node identity |
| Cloud Build running as the Compute default with Editor | 2 | A malicious build step inherits project-wide write |
| VM on default account with default scopes only | 3 | Scopes limit the APIs, but the identity is still shared |
| Default account exists, no attachment, no authentication | 4 | Disable it and block reuse |
Reading scopes and roles together
For a VM, what code can do with the attached account is the overlap of two settings: the OAuth access scopes set on the instance and the IAM roles granted to the account. Scopes are a legacy, per-instance limit; roles are the real permission model. That has two consequences for this task. First, a default account with Editor on a VM that kept the default scope set is less exposed than the same account on a VM created with cloud-platform, so record both values before ranking. Second, when you move a VM to a dedicated account, Google recommends the cloud-platform scope and narrow roles, which means the scope stops protecting you: the role set you grant in step 6 is now the only limit. Do not widen the scope on a VM that still runs as a default account with Editor. Cloud Run, GKE workloads using Workload Identity Federation and Cloud Build do not use instance scopes, so for them the roles are the whole story.
Verify it worked
- Attachments: re-run steps 2 to 4; no resource names a default email.
- Activity: Activity Analyzer and audit logs show no authentication by the default accounts after the change window.
- Workloads: no rise in
PERMISSION_DENIEDerrors in the new accounts' audit log entries; if there is, the role set from step 5 missed a method. - Policy: the organisation policy constraints show as enforced at the organisation node.
Rollback and common errors
| Situation | Fix |
|---|---|
| Application fails after re-attaching a VM | Stop the VM and run set-service-account with the previous email and scopes you recorded in step 2, then add the missing role to the new account |
| Cloud Run revision fails | Route traffic back to the previous revision, which still carries the old identity |
| Something breaks after disabling the default account | gcloud iam service-accounts enable; the account keeps its bindings |
| Default account was deleted | gcloud iam service-accounts undelete with the account's unique ID, within 30 days |
| Fingerprint mismatch error on VM update | Another change raced yours; describe the VM again and retry |
| GKE nodes fail to log or pull images on the new account | Check roles/container.defaultNodeServiceAccount and image registry read access |
Hardening afterwards
- Organisation policy: enforce
iam.automaticIamGrantsForDefaultServiceAccountsandconstraints/container.managed.disallowDefaultComputeServiceAccount, and set the Cloud Build constraints so builds use user-specified accounts. See the Google Cloud Organization Policy Guide. - Pipeline checks: fail infrastructure as code that creates a VM, template, Cloud Run service or node pool without an explicit service account.
- Who can act as the new accounts: each dedicated account is only as safe as the list of principals with
actAson it. See How to Audit GCP Service Account Impersonation Rights. - Owners: label each new account with an owner and purpose and add it to your NHI inventory.
Small estate or large organisation
A handful of projects can be checked with the per-project commands in a short script. A large organisation should loop the same read-only commands over every project from a central security project, store the results in BigQuery, and work through projects by owning team. Enforce the organisation policies first in a test folder, since a newly enforced constraint can block deployments that still assume the default account.
Metrics
| Metric | Target |
|---|---|
| Resources attached to a default service account | Zero, or a documented exception list |
| Default accounts holding Editor | Zero |
| Default accounts authenticated in the last 30 days | Falling to zero |
| Folders with the default account constraints enforced | All |
VMs with cloud-platform scope on a broad role account | Zero |
Common failure patterns
- Fixing the VM but not the template: the managed instance group recreates the VM with the default account at the next autoscale event.
- Stripping Editor before moving workloads: every workload on the default account breaks at once, and the change is reversed under pressure.
- Granting the new account Editor "for now": the identity is no longer shared, but nothing else improved. Use the method list from the audit logs.
- Forgetting the node identity: moving applications to Workload Identity Federation while node pools still run as a broad default account leaves system workloads exposed.
- Deleting the Compute default account: Google explicitly advises against it; disable and block instead.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | AC-2 Account Management; AC-6 Least Privilege | Dedicated, owned accounts with only the needed roles |
| NIST SP 800-53 Rev 5 | CM-2 Baseline Configuration | Templates and IaC set an explicit account |
| NIST CSF 2.0 | PR.AA-01; PR.AA-05 | Service identities managed; permissions reviewed |
| MITRE ATT&CK | T1078.004 Cloud Accounts; T1552.005 Cloud Instance Metadata API | Shared default identities widen what a stolen metadata token can do |
Practitioner checklist
- Record each project's number and the two default account emails.
- List VMs, templates, Cloud Run services, GKE node pools and Cloud Build settings that use a default account.
- Record access scopes and rank
cloud-platforminstances first. - Measure actual use with Activity Analyzer and audit log method lists.
- Create one dedicated account per workload with roles from observed use.
- Re-attach workloads, update templates and IaC, verify no permission errors.
- Disable unused default accounts; never delete the Compute default.
- Enforce the default account organisation policy constraints.
Standards and references
- Google Cloud: Service account types
- Google Cloud: Service accounts for Compute Engine
- Google Cloud: Change the attached service account of a VM
- Google Cloud: Cloud Run service identity
- Google Cloud: Service accounts in GKE
- Google Cloud: Cloud Build service account change
- Google Cloud: View recent usage for service accounts and keys
Related NHI Mgmt Group resources: Google Cloud IAM and Service Accounts Guide · How to Find GCP Service Accounts With Owner or Editor Roles · Compute Engine Security Guide · Cloud Run and Cloud Functions Security Guide