gcp-sandbox.orgOne Google Cloud service and one hands-on lab a day. Independent; not affiliated with Google.
Monday, November 2, 2026BeginnerSecurity and identity

Secret Manager from Cloud Shell: store a key, rotate it, then retire the old version

Stop pasting API keys into code and config files. Create a secret, read it back, add a new version, disable and destroy the old one, and delete everything at the end, all inside the free tier.

Secret Manager, in plain words

Secret Manager is a locked drawer for the small, sensitive strings your apps need: API keys, database passwords, OAuth client secrets, TLS keys. Instead of baking them into source code or an environment file, you store them once in Google Cloud and let only the identities that need them read them. Everything is encrypted in transit and at rest by default, and you can bring your own Cloud KMS key (CMEK) if your rules demand it.

Two ideas carry most of the service. A secret is the named container that holds labels, replication settings and IAM permissions. A secret version holds the actual bytes (up to 64 KiB) and is numbered 1, 2, 3 and so on. Rotating a key means adding a new version, not editing the old one. Each version can be enabled, disabled (reads fail, but you can switch it back on) or destroyed (the data is gone for good). The alias latest always points at the newest version, which is handy in a lab but risky in production, where Google advises pinning a version number.

Pricing is by active version and by read. The free tier covers 6 active versions, 10,000 access operations and 3 rotation notifications per month for each billing account. Beyond that, an active version costs about $0.06 a month and reads cost $0.03 per 10,000. Enabled and disabled versions both count as active; destroyed ones are free, and creating or changing secrets costs nothing. Automatic replication is billed as one location; user-managed replication is billed once per region you pick. There were no Secret Manager release notes in the last two weeks; the most recent entries, from August and September 2026, were about Parameter Manager, its companion service for plain configuration values.

Reach for it when

  • A Cloud Run service or job needs a database password or third-party API key; mount it with --set-secrets instead of writing it into the container image or a plain environment variable.
  • Several apps or teammates share one credential and you want a single place to rotate it, with IAM deciding exactly who can read it and audit logs showing who did.
  • You need to retire a leaked key quickly: add a new version, switch apps over, then disable the old one so any lingering reads fail loudly.

Skip it when

  • The value is ordinary configuration such as a feature flag or a region name; Parameter Manager (or a normal config file) fits better and keeps secrets and settings apart.
  • You want Google Cloud identities to call Google Cloud APIs; use service accounts and IAM roles directly rather than storing keys, and never create downloadable service account keys just to stash them here.
  • The data is larger than 64 KiB, such as a certificate bundle with big files or a dataset; keep it in Cloud Storage with tight IAM, optionally encrypted with Cloud KMS.

The AI angle

AI apps are full of keys: a third-party model API key, a vector database password, an OAuth client for a tool your agent calls. The Gemini Enterprise Agent Platform (formerly Vertex AI) docs for deployed agents on Agent Runtime say API keys and OAuth client secrets are kept in Secret Manager at the project level, where several agents can share them and labels can tag which agent uses which. Calls to Google's own models from inside Google Cloud should use a service account and IAM (for example roles/aiplatform.user) rather than a stored key, so reserve Secret Manager for credentials Google Cloud cannot issue for you.

Hands-on lab: Store, rotate and retire a practice secret

Create a secret holding a random practice value, read it back, add a second version, disable and destroy the first, inspect who can read it, then delete the secret.

TIME10 minutes
COST$0 in a typical sandbox. The lab holds at most two active versions for a few minutes and makes a handful of reads. Even if your billing account already uses its free allotment, the charge would be a small fraction of a cent.
FREE TIER / CREDITSSecret Manager's free tier is 6 active secret versions, 10,000 access operations and 3 rotation notifications per month, counted per billing account. Destroyed versions and management actions such as create and delete are never billed.

Before you start

  • A sandbox Google Cloud project you own (shown here as YOUR_PROJECT_ID) with billing linked.
  • Cloud Shell, or any terminal with the gcloud CLI signed in as a user who can enable APIs and administer secrets (Secret Manager Admin, roles/secretmanager.admin; a project Owner has it).
  • The value used here is random practice data. Do not put a real password or key in a lab project.
  1. Point gcloud at your project and enable the API

    Open Cloud Shell, set the project, pick a secret name and turn on the Secret Manager API. Enabling it is free.

    gcloud config set project YOUR_PROJECT_ID
    export SECRET_ID="sandbox-lab-secret"
    gcloud services enable secretmanager.googleapis.com
  2. Create the secret with a random first version

    --data-file=- reads the value from standard input, so the value never appears in your command line or shell history. openssl rand makes a fake 32-character key, and tr -d strips the trailing newline so it is not stored as part of the value. With no replication flags the secret uses automatic replication, billed as one location.

    openssl rand -hex 16 | tr -d '\n' | gcloud secrets create "$SECRET_ID" \
      --data-file=- --labels=purpose=sandbox-lab
    
    gcloud secrets describe "$SECRET_ID"
  3. Read it back

    Read version 1 by number and again through the latest alias; both print the same value because only one version exists. Output goes to the terminal as text, which is fine for this hex string; for binary secrets the reference suggests --out-file instead.

    gcloud secrets versions access 1 --secret="$SECRET_ID"; echo
    gcloud secrets versions access latest --secret="$SECRET_ID"; echo
  4. Rotate: add a second version

    Adding a version is how you rotate. Afterwards latest points at version 2, while version 1 still works until you switch it off. List the versions to see both, with their state.

    openssl rand -hex 16 | tr -d '\n' | gcloud secrets versions add "$SECRET_ID" --data-file=-
    
    gcloud secrets versions access latest --secret="$SECRET_ID"; echo
    gcloud secrets versions list "$SECRET_ID"
  5. Disable, then destroy the old version

    Disabling is the safe first move: reads of version 1 now fail with an error, but you could re-enable it if an app breaks. Once you are sure, destroy it; that is permanent, and destroyed versions stop counting toward billing. Finally, look at the secret's IAM policy. It is empty, which means only project-level roles such as Owner can read it; in real use you would grant roles/secretmanager.secretAccessor on this one secret to the app's service account.

    gcloud secrets versions disable 1 --secret="$SECRET_ID"
    gcloud secrets versions access 1 --secret="$SECRET_ID"   # expect an error
    
    gcloud secrets versions destroy 1 --secret="$SECRET_ID" --quiet
    gcloud secrets versions list "$SECRET_ID"
    
    gcloud secrets get-iam-policy "$SECRET_ID"

Check that it worked

The two reads in step 3 print the same 32-character hex string; after step 4, latest prints a different string; in step 5 the read of version 1 fails once it is disabled, and the final list shows version 2 as enabled and version 1 as destroyed.

Clean up

Delete the secret. This destroys every remaining version and cannot be undone, so check the name first. Then confirm it is gone. Leave the Secret Manager API on if anything else in the project uses it; if this is a practice-only project with no other secrets, you can disable it, or delete the whole practice project instead.

gcloud secrets delete "$SECRET_ID" --quiet

# Confirm: this should print nothing
gcloud secrets list --filter="name:$SECRET_ID"

# Optional, practice-only project with no other secrets:
# gcloud services disable secretmanager.googleapis.com
unset SECRET_ID

Gotchas

  • Disabled versions still count as active and are billed; only destroyed versions are free. Disable first to test, then destroy what you no longer need.
  • echo "value" adds a newline that becomes part of the stored secret and can break logins; use printf, echo -n, or strip it as this lab does.
  • Avoid latest in production. A Cloud Run environment variable reads the secret only when an instance starts, so Google recommends pinning a version number there; a mounted volume reads it on each file read.
  • IAM can be granted on a secret but not on a single version, so anyone with access to a secret can read every enabled version of it.
  • User-managed replication bills each chosen region separately: 5 versions in 3 regions count as 15 active versions.