Skip to content
DevOps AI ToolKit
Core Guide · Cloud & Security

gcloud CLI

A gcloud CLI reference for engineers who operate real Google Cloud projects — the two separate credentials, enabling APIs, IAM inheritance and the actAs trap, org policy constraints that beat Owner, quotas versus capacity, GKE auth, etags and preconditions, and the errors each of them returns.

Last reviewed September 2026 Reference · Cheat sheet · 30 min read

Technically validated: Commands target the Google Cloud CLI (`gcloud`) against Google Cloud. Where behaviour depends on a specific mechanism — Application Default Credentials, the GKE auth plugin, org policy inheritance — that is stated inline rather than assumed.

On this page

Google Cloud fails in four recognisable ways, and only one of them exists on the other major clouds. The API is not enabled. You are holding the wrong one of two credentials. IAM will not let you act as a service account. An org policy overrules you regardless of your role. Get those four straight and most PERMISSION_DENIED triage becomes mechanical. This reference is organized around them.

Authentication: you have two credentials, not one

This is the single most confusing thing about gcloud, and it explains an enormous share of “works in my terminal, fails in Terraform”.

Authentication & identity

Command What it does Risk
gcloud auth login
Credentials for the gcloud CLI itself. Safe
gcloud auth application-default login
Application Default Credentials — what SDKs and Terraform read. Safe
gcloud auth list
Every account gcloud knows, with the ACTIVE one starred. Safe
gcloud config list
Active account, project, region and zone. Run this first when confused. Safe
gcloud auth print-access-token
Prove you can actually mint a token right now. Caution
gcloud auth revoke <account>
Drop a stale credential rather than debugging around it. Caution
gcloud <cmd> --impersonate-service-account=<sa>
Act as a service account without a key file. Needs TokenCreator. Caution
gcloud auth application-default set-quota-project <p>
Fixes the 'quota project not set' warning from SDK calls. Caution

Application Default Credentials resolve in this order:

1. GOOGLE_APPLICATION_CREDENTIALS   an explicit key file path
2. gcloud ADC file                  ~/.config/gcloud/application_default_credentials.json
3. attached service account         the metadata server on GCE, GKE, Cloud Run, Cloud Functions

Credential failures: missing authentication credential 401, reauthentication required, invalid_grant / JWT signature (often clock skew or a rotated key), insufficient authentication scopes — a VM’s scopes are separate from its IAM roles — and workload identity default credentials.

Projects, configurations and defaults

gcloud config list                              # active account, project, region, zone
gcloud config set project <project-id>
gcloud projects list --format="table(projectId, name, projectNumber)"

# Named configurations — keep prod and dev cleanly separated
gcloud config configurations create prod
gcloud config configurations activate prod
gcloud config configurations list

Use the project ID, not the display name or the number — they are three different things and only the ID is accepted in most commands. A wrong-project error is far more common than a permissions error, and looks identical at first.

Enabling APIs: the blocker that only exists here

Every Google Cloud API must be explicitly enabled per project before you can call it. This has no real equivalent on AWS or Azure, and it is the first wall almost everyone hits.

# Is it on?
gcloud services list --enabled --filter="config.name:compute" 

# Turn it on (takes a minute or two to propagate)
gcloud services enable compute.googleapis.com

# Bootstrap a project properly, in one go
gcloud services enable \
  compute.googleapis.com container.googleapis.com iam.googleapis.com \
  logging.googleapis.com monitoring.googleapis.com artifactregistry.googleapis.com

The error reads “API [x] has not been used in project [y] before or it is disabled” with status SERVICE_DISABLED, and it is genuinely a configuration step rather than a permissions problem — see API not enabled. Enable APIs during project bootstrap, not during the first deploy, and note that enabling propagates asynchronously: an immediate retry can still fail.

A disabled billing account produces a similar-looking wall — billing account disabled — and blocks far more than you would expect.

IAM: inheritance, and the actAs trap

Google Cloud’s hierarchy is Organization → Folder → Project → resource, and IAM bindings inherit downward and are additive. A role granted at the folder applies to every project inside it.

IAM diagnosis

Command What it does Risk
gcloud projects get-iam-policy <p> --flatten='bindings[].members' --filter='bindings.members:<email>' --format='table(bindings.role)'
Every role a principal holds on the project. The canonical incantation. Safe
gcloud projects add-iam-policy-binding <p> --member=<m> --role=<r>
Grant safely — this does a read-modify-write with the etag for you. Caution
gcloud policy-troubleshoot iam <resource> --principal-email=<e> --permission=<perm>
Ask IAM WHY a specific permission is allowed or denied. Safe
gcloud iam service-accounts get-iam-policy <sa>
Who may impersonate or act as this service account. Safe
gcloud iam roles describe <role>
The exact permissions a role contains. Safe
gcloud asset search-all-iam-policies --scope=projects/<p> --query='policy:<email>'
Find a principal's bindings across the whole hierarchy. Safe
# Grant actAs on ONE service account — narrow, not project-wide
gcloud iam service-accounts add-iam-policy-binding <sa-email> \
  --member="user:deployer@example.com" \
  --role="roles/iam.serviceAccountUser"

Other IAM failures: permission denied 403, service account does not exist, secret manager access denied, storage objects 403 and Artifact Registry upload denied.

Org policy: constraints that beat Owner

Org policies are not IAM. They are constraints applied at the organization, folder or project level, and they override permission entirely — a Project Owner cannot do something an org policy forbids.

gcloud resource-manager org-policies list --project=<p>
gcloud resource-manager org-policies describe compute.vmExternalIpAccess --project=<p>

Common ones that surprise people: compute.vmExternalIpAccess (no public IPs), iam.disableServiceAccountKeyCreation (no downloadable keys), compute.requireShieldedVm, and residency constraints restricting which regions you may deploy into. The error names the constraint — read it rather than editing the request, because the policy usually exists deliberately. See org policy violation.

Quotas versus capacity

Two different failures that both stop a deployment, with different responses.

Which error means which

Command What it does Risk
RESOURCE_EXHAUSTED / QUOTA_EXCEEDED
A project QUOTA. Request an increase; the capacity exists. Safe
ZONE_RESOURCE_POOL_EXHAUSTED
Google has no capacity in that ZONE right now. Try another zone or machine type. Safe
RESOURCE_OPERATION_RATE_EXCEEDED
Too many operations on one resource too quickly. Back off. Safe
# Project-wide quotas and current usage
gcloud compute project-info describe --project=<p> \
  --format="table(quotas.metric, quotas.usage, quotas.limit)"

# Regional quotas — these bite far more often than global ones
gcloud compute regions describe us-central1 \
  --format="table(quotas.metric, quotas.usage, quotas.limit)"

Compute quotas are largely regional, so a project with plenty of global headroom still fails in one region. Guides: resource exhausted / quota exceeded, CPUs quota exceeded, zone resource pool exhausted, in-use addresses quota, BigQuery concurrent query quota and resource operation rate exceeded.

GKE

gcloud container clusters get-credentials <cluster> --region <r> --project <p>
gcloud container clusters list --format="table(name, location, status, currentMasterVersion)"
gcloud container node-pools list --cluster=<c> --region=<r>

Workload Identity is the right way for a pod to authenticate: bind the Kubernetes service account to a Google service account with roles/iam.workloadIdentityUser and annotate the KSA. No key file ever enters the cluster. When it is misconfigured the pod falls back to the node’s default credentials and fails confusingly — workload identity default credentials.

GKE scheduling and capacity failures: insufficient CPU / unschedulable, untolerated taint, pod exceeded ResourceQuota, node disk pressure eviction, nodes unhealthy, IP space exhausted and ImagePullBackOff from Artifact Registry.

Etags, preconditions and concurrent modification

Google Cloud uses etags for optimistic concurrency on policies and many resources. Read-modify-write is the required pattern, and doing it by hand is where 412s come from.

# The safe pattern — gcloud handles the etag for you
gcloud projects add-iam-policy-binding <p> --member=<m> --role=<r>

# The manual pattern — only when you must edit several bindings at once
gcloud projects get-iam-policy <p> --format=json > policy.json
#   ...edit policy.json, KEEPING the etag field intact...
gcloud projects set-iam-policy <p> policy.json

See precondition failed 412, 409 already exists, resource in use by another resource and Cloud SQL operation already in progress.

Logging and diagnosis

Cloud Logging is queryable directly from the CLI, which is faster than the console for most triage:

# Recent errors from one resource type
gcloud logging read 'resource.type="gce_instance" severity>=ERROR' \
  --limit=20 --freshness=1h --format="table(timestamp, resource.labels.instance_id, textPayload)"

# Everything about one Cloud Run revision
gcloud logging read 'resource.type="cloud_run_revision" AND resource.labels.service_name="<svc>"' \
  --limit=50 --freshness=30m

# Who changed this? Admin Activity audit logs
gcloud logging read 'logName:"cloudaudit.googleapis.com%2Factivity"' --limit=20 \
  --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.methodName)"

# The raw HTTP exchange, when nothing else explains it
gcloud <command> --log-http

Output, filters and scripting

Making gcloud scriptable

Command What it does Risk
--format='value(name)'
Bare values, one per line — the right choice for shell loops. Safe
--format='table(name, status, zone)'
Human-readable columns. Safe
--format=json | jq
Full structured output for anything non-trivial. Safe
--filter='status=RUNNING AND zone:us-central1'
Narrow the result set. See the caveat below. Safe
--flatten='bindings[].members'
Expand a nested list so --filter can match inside it. Safe
--quiet
Never prompt. Essential in CI, dangerous interactively. Caution
--log-http
Print the underlying HTTP request and response. Safe
gcloud components update
Update the CLI and installed components. Caution
# A safe scripting shape
set -euo pipefail
gcloud config set core/disable_prompts true   # or pass --quiet per command

for name in $(gcloud compute instances list --format='value(name)' --filter='status=RUNNING'); do
  gcloud compute instances describe "$name" --format='value(machineType)'
done

Troubleshooting specific errors

The Google Cloud failures engineers hit most often, each with a dedicated guide:

For anything else, browse the error library or paste the message into the Incident Assistant.

Production checklist

  • Know which credential you are using. gcloud auth login and application-default login are separate.
  • gcloud config list first when anything is unexpectedly denied — wrong project outranks wrong permission.
  • Enable APIs at project bootstrap, not during the first deploy. Enabling is asynchronous.
  • Grant roles/iam.serviceAccountUser on the service account, not project-wide, when someone must deploy as it.
  • Check org policy before adding roles. A constraint beats Owner.
  • Impersonate instead of downloading keys; use Workload Identity Federation for CI outside Google Cloud.
  • Use add-iam-policy-binding, not get/set, so the etag is handled for you.
  • Remember compute quotas are regional. Global headroom proves nothing.
  • Install gke-gcloud-auth-plugin before blaming kubectl.
  • Use the project ID, never the name or number.
  • --format='value(...)' in scripts, and do not assume --filter reduces API load.

Frequently asked questions

Why does gcloud work but my application or Terraform cannot authenticate?

Because they read different credentials. gcloud auth login authenticates the CLI; client libraries, Terraform and the language SDKs read Application Default Credentials, which come from gcloud auth application-default login (or GOOGLE_APPLICATION_CREDENTIALS, or the attached service account on a Google Cloud VM). Running the first alone leaves gcloud fully working while every SDK call fails. Run gcloud auth application-default login and, if you see a quota-project warning, set it with gcloud auth application-default set-quota-project.

I have Owner and still get PERMISSION_DENIED. Why?

Three possibilities, in the order worth checking. The API may not be enabled on the project, which returns a permission-shaped error but is really a configuration step. An org policy constraint may forbid the action outright — those are not IAM and cannot be out-granted, not even by Owner. Or the operation needs iam.serviceAccounts.actAs on a specific service account, which Owner on the project does not automatically confer in the way people expect. gcloud policy-troubleshoot iam will tell you which.

What is the actAs permission and why do I need it?

Creating a resource that runs as a service account — a VM with an attached SA, a Cloud Run service, a Cloud Function, a Dataflow job — is effectively borrowing that identity, so Google requires explicit permission to do it. That permission is iam.serviceAccounts.actAs, normally granted through roles/iam.serviceAccountUser on the service account itself. Without it, someone with full Compute Admin still cannot launch a VM with a service account attached. Grant it per service account rather than at project level.

Do I need to enable an API before using it?

Yes, per project, and this is the main structural difference from AWS and Azure. The error reads “API [x] has not been used in project [y] before or it is disabled” with status SERVICE_DISABLED. Enable it with gcloud services enable <api>.googleapis.com, and note that enabling propagates asynchronously — an immediate retry can still fail, so wait a minute. Enable everything a project needs during bootstrap so this never appears in a deploy.

What is the difference between a quota error and a zone exhaustion error?

RESOURCE_EXHAUSTED or QUOTA_EXCEEDED means your project is not permitted that many, and a quota increase fixes it. ZONE_RESOURCE_POOL_EXHAUSTED means Google itself has no capacity for that machine type in that zone right now — no quota increase helps, and the fix is another zone, another machine type, or waiting. A detail that catches people out: most Compute Engine quotas are regional, so a project with plenty of global headroom can still fail in one region.

Why did my set-iam-policy fail with 412?

Because the policy changed between your get-iam-policy and your set-iam-policy. Google Cloud uses etags for optimistic concurrency: the etag you read is submitted back, and if it no longer matches, the write is rejected rather than silently overwriting someone else’s change. That is the system protecting you. Re-read the policy, reapply your edit, and submit again — and for single-binding changes use add-iam-policy-binding, which does the whole cycle atomically.

  • Guide: AWS CLI — the same operational ground on AWS; credentials, IAM evaluation and quotas rhyme closely.
  • Guide: Azure CLI — and again on Azure, where the identity model is the dominant failure class.
  • Guide: Cloud Security — least privilege and the identity model underneath the IAM section here.
  • Guide: Kubernetes Security — where GKE workloads pick up from cluster-side controls.
  • Tool: Incident Assistant — paste a Google Cloud error and get an ordered triage plan.

Did this solve your problem?

Continue learning

Related Core Guides that build on this one.

Written by James Joyner IV, Sr. Systems Software Engineer — for engineers who run what they build.

Last reviewed September 2026. Found an error or an out-of-date command? Tell us — accuracy is the point of a Core Guide.