Verified14 commandsAI-assisted

Environment & Configuration Management

.md

Verified against Google Cloud SDK 553.0.0, verified via `gcloud topic configurations`, `gcloud info`, · official docs

What it is and where it fits 🎯#

Every other page in this tool covers a GCP service surface, Compute (02), Storage & Networking (03), Databases (04), Serverless & Messaging (05), Logging, Monitoring & Governance (06), Load Balancing & DNS (07), Secret Manager & KMS (08), Artifact Registry & Cloud Build (09), and Cloud Deploy, Workflows & IAP (10). This page covers none of that. It covers the SDK itself: what actually lands on disk when you install gcloud, what gcloud init does to your home directory, what a "named configuration" really is (gcloud's answer to an AWS CLI named profile or a kubectl context), how properties resolve when a flag, an environment variable, and a saved configuration all disagree, and how any of this changes once you're running inside a container instead of on your own laptop. Authentication and IAM identity itself (service accounts, Workload Identity Federation, role bindings) is covered on page 01 — this page is about the CLI's own local state, not about who you're authenticated as.

Skipping this page is how most "works on my machine, breaks in CI" gcloud problems happen: a script that implicitly depends on a laptop's default configuration having a project set, run on a CI runner with no such configuration, fails in a way that looks like a permissions problem but is actually a missing property.

Installation and version check#

Full per-platform install commands (apt, Homebrew, the interactive installer) are on page 01 — this page assumes gcloud is already on your PATH. Two commands worth knowing before anything else:

gcloud version               # confirm the CLI and every installed component's version
gcloud components update     # keep the CLI and all installed components in lockstep

Tip

Run gcloud components update on a schedule (weekly, or at the top of a CI image build) rather than only when something breaks. GCP ships new gcloud releases roughly every two weeks, and a stale CLI is a real, recurring source of "that flag doesn't exist" reports that turn out to just be an old install.

Core concepts: what "the SDK" actually is on disk#

Diagram

The directory is the closest thing gcloud has to a "home." Nothing about your project, your active account, or your default region lives anywhere else, it's all just files under this one tree. The red nodes above (credentials.db, application_default_credentials.json, legacy_credentials/) are the ones that hold real, usable secrets: anyone who can read them can authenticate as you or as whatever service account you last activated, with no further password prompt.

Caution

Never commit ~/.config/gcloud/ (or any subset of it) into a repository, a Docker image layer, or a shared network drive. credentials.db and legacy_credentials/*/adc.json are long-lived OAuth refresh tokens, functionally equivalent to a password with no expiry until explicitly revoked. This has caused real incidents: a team that baked a developer's ~/.config/gcloud into a "convenience" base image for faster CI cold starts shipped that developer's personal credentials into every downstream image built from it, discovered only when an access review flagged logins from build agents that had never run gcloud auth login.

Where gcloud lives — the home directory, per platform#

PlatformDefault locationOverride with
Linux / macOS~/.config/gcloudCLOUDSDK_CONFIG=/some/path
Windows%APPDATA%\gcloudCLOUDSDK_CONFIG=C:\some\path
gcloud info --format="value(config.paths.global_config_dir)"   # the actual resolved path, whatever OS you're on

CLOUDSDK_CONFIG is the single environment variable that relocates the entire directory tree from the diagram above, not just one file inside it. The two situations where you actually want to set it: $HOME is read-only or shared (a hardened CI runner image, a locked-down corporate laptop profile), or you deliberately want two fully isolated gcloud identities running side by side without touching named configurations at all, one dedicated directory per identity, selected by which CLOUDSDK_CONFIG value a given shell session exports.

First-run setup: gcloud init#

gcloud init                        # interactive: login, pick/create project, set default region + zone
gcloud init --console-only         # for a remote shell with no browser to launch
gcloud init --skip-diagnostics     # skip the network connectivity checks, faster on a known-good machine

gcloud init is a guided wrapper around three things you could otherwise do by hand: gcloud auth login, gcloud config set project, and creating (or reusing) a named configuration to hold the result. It writes exactly one file, ~/.config/gcloud/configurations/config_default, the first time you run it, and marks that configuration active by writing its name into ~/.config/gcloud/active_config.

Tip

For a scripted or headless first-time setup (a new CI runner image, a fresh dev-container), skip gcloud init entirely and go straight to the primitives it wraps: gcloud auth login --no-launch-browser (or gcloud auth activate-service-account for a non-interactive identity) followed by gcloud config set project my-project-id. gcloud init's interactive prompts have nothing to offer a process with no human watching the terminal.

Named configurations — gcloud's "profiles"#

gcloud config configurations create staging       # a fresh, empty named configuration
gcloud config configurations activate staging     # switch which one is "active" for every future command
gcloud config configurations list                 # every configuration + which one is active + its account/project
gcloud config configurations describe staging      # full property dump for one configuration
gcloud config configurations rename staging stg     # rename without losing its properties
gcloud config configurations delete staging          # prompts for confirmation unless --quiet is passed

A configuration bundles account, project, default region/zone, and any other property you've set into one named, switchable unit, the direct equivalent of an AWS CLI named profile (~/.aws/config's [profile name] blocks) or a kubectl context. Where it differs from both: only one configuration is ever active at a time for a given CLOUDSDK_CONFIG directory, chosen by writing its name into a single active_config file, not by an env var you have to remember to export in every shell (though --configuration and CLOUDSDK_ACTIVE_CONFIG_NAME below give you that per-invocation override when you want it).

Config file format#

# ~/.config/gcloud/configurations/config_staging
[core]
account = ci-deployer@my-staging-project.iam.gserviceaccount.com
project = my-staging-project

[compute]
region = us-central1
zone = us-central1-a

Plain INI, one [section] per property group, property = value lines underneath, generated for you by gcloud config set but perfectly safe to hand-write or template. This is the concrete detail that matters for baking a config into a container image: COPY or template this one file into $CLOUDSDK_CONFIG/configurations/config_<name> plus a one-line active_config file naming it, and the image boots with that configuration already active, no interactive gcloud init required at container start.

Setting and reading individual properties#

gcloud config set project my-project-id            # writes into the ACTIVE configuration's [core] section
gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-a
gcloud config get project                            # read one property back
gcloud config list                                    # every property set in the active configuration
gcloud config list --all                              # includes properties still at their unset default
gcloud config unset compute/zone

Properties are namespaced section/name (core/project, compute/region, functions/region), which matters because it's exactly how the matching environment variable is spelled: uppercase the section and name, join with an underscore, prefix CLOUDSDK_. compute/region becomes CLOUDSDK_COMPUTE_REGION, core/project becomes CLOUDSDK_CORE_PROJECT. gcloud config set project (with no explicit section) is shorthand for core/project specifically, since it's the property nearly every command needs.

Precedence: flag beats env var beats saved configuration#

Diagram

Highest wins. A one-off gcloud compute instances list --project=other-project overrides whatever the active configuration says, without changing it; a CLOUDSDK_CORE_PROJECT=other-project gcloud ... prefix does the same for exactly that one shell invocation, without touching any file on disk at all, the pattern CI systems use so a pipeline never has to mutate a shared configuration to target a different project per job. This is also how --configuration=staging (or CLOUDSDK_ACTIVE_CONFIG_NAME=staging as its env-var equivalent) works: it's a global flag on gcloud itself, available to every command, that swaps which saved configuration supplies tier-3 values for that one invocation, without running config configurations activate and leaving a different configuration active afterward.

Important

A named configuration's properties are local file state, not a live reflection of the project. gcloud init's own help text is explicit about this: changing a project's default Compute Engine zone in the Cloud Console does not change what your saved configuration reports as compute/zone — the two are independent, and a stale local zone/region setting is a genuinely common cause of "why did my instance just get created in the wrong region" when a team's cloud-side defaults have moved on since someone's laptop was last configured.

Diagnosing your environment: gcloud info#

gcloud info                                                        # active account, project, SDK root, Python version, everything
gcloud info --show-log                                             # append the most recent log file's contents
gcloud info --format="value(config.paths.active_config_path)"       # exact path of the currently active config file
gcloud info --format="value(config.account,config.project)"         # just the two values you usually actually want

gcloud info is the single command to run before reporting "gcloud is broken" to a teammate or filing a support ticket, it dumps the resolved account, project, SDK installation path, active configuration path, Python interpreter in use, and a handful of recent log file locations in one shot, which is almost always enough to spot a stale configuration or a mismatched account without any further digging.

Components: the SDK's own package manager#

gcloud components list                    # every component gcloud knows about + installed/not-installed state
gcloud components install kubectl           # add an optional component (kubectl, gke-gcloud-auth-plugin, cloud-build-local, ...)
gcloud components install alpha beta        # unlock `gcloud alpha ...` / `gcloud beta ...` command surfaces
gcloud components remove COMPONENT_ID
gcloud components reinstall                 # rebuild the whole install if something's gone inconsistent

core, gcloud-crc32c, and a handful of others ship by default; alpha, beta, bq, gsutil, kubectl, and gke-gcloud-auth-plugin are common opt-in installs. A command documented as (BETA) or (ALPHA) in its own --help output genuinely will not run until the matching component is installed, that's not a permissions error, it's a missing local component, and gcloud components install beta is the fix.

Multiple accounts and switching between them#

gcloud auth list                                     # every authenticated account on this machine + which is active
gcloud config set account jane@example.com            # switch the ACTIVE configuration's account (doesn't re-authenticate)
gcloud auth login other-account@example.com            # authenticate a second account without dropping the first

Full authentication mechanics, service accounts, impersonation, and Workload Identity Federation live on page 01. What belongs here: gcloud auth list and gcloud config set account operate on already-cached credentials, switching which authenticated identity the active configuration points at is instant and doesn't touch the network, whereas gcloud auth login is what actually round-trips through Google's OAuth flow to add a new credential to the cache in the first place.

Docker, CI, and a read-only or ephemeral $HOME#

# Dockerfile snippet — bake a service-account-driven config into a CI image
ENV CLOUDSDK_CONFIG=/etc/gcloud-config
COPY ci-config /etc/gcloud-config
RUN gcloud auth activate-service-account --key-file=/etc/gcloud-config/key.json
# Mount a config directory into a container at run time instead of baking it in
docker run --rm -v ~/.config/gcloud:/root/.config/gcloud gcr.io/my-project/my-tool:latest
gcloud auth configure-docker                          # register gcloud as Docker's credential helper for Google registries
gcloud auth configure-docker us-central1-docker.pkg.dev   # scope it to one Artifact Registry host instead of all Google registries

gcloud auth configure-docker writes into ~/.docker/config.json, not into ~/.config/gcloud/ at all, it tells docker itself to shell out to gcloud for registry credentials on every pull/push against a Google registry host, which is what lets docker push us-central1-docker.pkg.dev/... work with no separate docker login step.

Warning

Mounting ~/.config/gcloud read-write into an untrusted or multi-tenant container gives that container everything it needs to act as you, indefinitely, not just for the lifetime of the container. A refresh token cached in credentials.db outlives the container. For anything short-lived or untrusted, prefer activating a scoped service account key (or better, Workload Identity Federation, page 01) inside the container's own CLOUDSDK_CONFIG directory instead of sharing your personal one.

Real-world scenario: one laptop, personal account and a CI-service-account identity, no cross-contamination#

An engineer needs to run gcloud interactively as themselves for day-to-day debugging, and separately, run it locally as the exact CI service account to reproduce a pipeline failure, without either identity accidentally leaking into the other's session:

gcloud config configurations create personal
gcloud config set account jane@example.com --configuration=personal
gcloud config set project my-project-id --configuration=personal

gcloud config configurations create ci-repro
gcloud auth activate-service-account --key-file=/tmp/ci-key.json
gcloud config set account ci-deployer@my-project-id.iam.gserviceaccount.com --configuration=ci-repro
gcloud config set project my-project-id --configuration=ci-repro

gcloud config configurations activate personal      # back to interactive work
gcloud --configuration=ci-repro compute instances list   # one-off command as the CI identity, no need to switch active config

--configuration=ci-repro on that last line is the detail that makes this actually convenient day to day: the engineer never has to remember to switch back to personal afterward, because that single command never changed which configuration was active in the first place.

Real-world scenario: a consultancy managing five clients' GCP projects from one machine#

  • Create one named configuration per client project: gcloud config configurations create client-acme
  • Set account, project, and compute/region for each, matching that client's actual environment
  • Alias each client to a shell function (alias acme='gcloud config configurations activate client-acme') instead of typing the full configuration name every time
  • Confirm gcloud config configurations list shows the expected account/project pairing for every client before running anything destructive, a wrong-client terraform apply or gcloud ... delete is the actual failure mode this whole setup exists to prevent
  • Never share one configuration across two clients "temporarily", create a new one, it costs nothing

Tip

gcloud config configurations list's output includes the account and project columns specifically so this kind of pre-flight check is a single glance, not a gcloud config list round-trip per client.

CI/CD integration recipe: isolated per-job config on a shared GitHub Actions runner#

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      CLOUDSDK_CONFIG: ${{ runner.temp }}/gcloud-config   # isolated per job run, cleaned up with the runner
    steps:
      - uses: actions/checkout@v4
      - uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: projects/<project-number>/locations/global/workloadIdentityPools/github-pool/providers/github-provider
          service_account: ci@my-project-id.iam.gserviceaccount.com
      - uses: google-github-actions/setup-gcloud@v2
      - run: gcloud config list   # confirm the isolated config actually picked up the WIF-authenticated identity

Setting CLOUDSDK_CONFIG to a path under runner.temp (rather than letting it default to the runner's $HOME) means a self-hosted runner reused across many jobs never accumulates state between them, and two concurrent jobs on the same self-hosted machine can never see each other's active account or project.

Common pitfalls#

  • Assuming gcloud config set always edits the "default" configuration. It edits whichever one is currently active, if you activated staging last week and forgot, gcloud config set project foo just silently changed staging, not default.
  • Baking a personal ~/.config/gcloud into a shared image or volume. See the CAUTION above, credentials.db is a live, reusable credential, not a piece of harmless local cache.
  • Forgetting a component is opt-in. A (BETA)/(ALPHA) command failing with "invalid choice" almost always means gcloud components install beta/alpha, not a typo in the command itself.
  • Expecting a saved configuration's region/zone to track a project's cloud-side default. It doesn't, see the IMPORTANT callout, local config state and Console-set project defaults are independent.
  • Running gcloud init non-interactively on a CI runner and having it hang. gcloud init expects a human; use the direct auth login --no-launch-browser / auth activate-service-account + config set sequence instead, as shown above.

Exit codes#

0 success, non-zero for any auth failure, missing property that a command required, or malformed flag, gcloud doesn't distinguish "you're not authenticated" from "you're authenticated but missing a required property" in the exit code itself, gcloud info (or --verbosity=debug on the failing command) is the fastest way to tell the two apart.

When to reach for something else#

For team-shared, reviewable environment bootstrapping (which project, which region, which service account a given pipeline should run as), prefer committing that as plain values in a Terraform variables file or a CI system's own environment configuration rather than relying on a specific engineer's local named configuration, a laptop's gcloud state should never be the only place a deployment's target project is recorded. See page 01 for the authentication and IAM mechanics this page's configurations ultimately point at.