Secret Manager in GCP Explained: Versions, IAM, Rotation, and Best Practices

Secret Manager is GCP’s managed service for storing sensitive application credentials: database passwords, API keys, TLS certificates, OAuth tokens, and any other value that must not live in source code, config files, or shared documents. It provides versioning, IAM-based access control scoped to individual secrets, and a complete audit trail of every access event. By the end of this page you will understand how it works, when to use it, how to connect it to your workloads, and what the most common mistakes look like in practice.

The simple version

Think of Secret Manager as a locked filing cabinet for your application’s credentials. Only people with the right key can open a specific drawer, and every time someone does, it is logged automatically. When you need to change a credential, you add a new copy to the drawer. Your application finds the newest copy on its own.

Before Secret Manager, teams routinely stored passwords in environment variable files committed to git, passed tokens through Slack messages, or embedded credentials directly in application code. Any of those approaches creates a persistent exposure that is difficult to contain once it happens. Secret Manager gives you one controlled place to store those values, with access gated by IAM and every read logged in audit logs.

What Secret Manager is

Secret Manager is a fully managed GCP service. You do not provision servers, manage databases, or configure encryption. Google handles all of that. You interact with it through the gcloud CLI, client libraries, or the REST and gRPC APIs.

It is designed for values that are:

  • Sensitive enough to warrant encryption at rest and access logging
  • Referenced by applications rather than by humans in daily work
  • Subject to occasional rotation (credential changes)

Common examples include database passwords, third-party API keys, HMAC signing secrets, OAuth client secrets, TLS private keys, and service account key files (though service account keys carry their own risks and should be avoided where possible). What Secret Manager is not designed for is covered further down.

Why Secret Manager matters

Secrets stored in the wrong place are behind a significant proportion of cloud security incidents. The most common failure patterns:

  • Secrets in version control. A credential committed to git is compromised from that moment onward, even if deleted later. Git history is permanent, and scanning tools can extract it automatically.

  • Hardcoded values in application code. A developer copies a working connection string into source, ships it, and the credential reaches production builds, container images, and eventually a public repository.

  • Uncontrolled sharing. Passwords emailed or shared over chat have no audit trail, no expiry, and no access control. You cannot tell who has the credential or revoke access to it.

  • Difficult rotation. When credentials are scattered across environment variable files, CI/CD variables, and application configs, rotating them requires touching every location. Often you do not know where all the locations are.

  • No separation between environments. Sharing a credential between dev and production means a breach in your development environment exposes production data.

If it touched git, it is compromised

Removing a secret from version control does not make it safe. The commit remains in git history, and anyone with past or present repo access can retrieve it. Treat any credential that has touched version control as fully exposed: revoke it, replace it, and store the new value in Secret Manager. Do not wait.

Secret Manager addresses all of these. One controlled location, IAM-gated access, full audit history, and versioning that makes rotation a safe, incremental operation.

How Secret Manager works

The lifecycle from creation to rotation follows a predictable set of steps:

  1. Create the secret container. You create a named secret resource and choose a replication policy. No credential value is stored yet.

  2. Add a secret version. You add the actual credential value. Secret Manager stores it as version 1, encrypted at rest using Cloud KMS.

  3. Grant IAM access. You bind roles/secretmanager.secretAccessor to the service account that your application runs as, scoped to this specific secret.

  4. Application reads the secret. The application calls the Secret Manager API using the latest version alias. Secret Manager returns the plaintext value over an encrypted connection to authorised callers only.

  5. Rotate by adding a new version. When you need to change the credential, add version 2 with the new value. Applications reading latest automatically pick up the new value on their next read.

  6. Disable or destroy the old version. Once you have confirmed the application is using the new value, disable version 1 to make it inaccessible. Destroy it if you want the data permanently deleted. For a detailed walkthrough of this process see Rotating Secrets Automatically.

Version states

Every secret version is in one of three states:

ENABLED

The version is accessible and can be read by authorised callers. This is the default state when a version is first added.

DISABLED

The version is temporarily blocked. The data still exists and can be re-enabled at any time. Use this during rotation to hold the old version in reserve while you confirm the new one works.

DESTROYED

The version data is permanently deleted. This cannot be undone. Only destroy a version once you are certain it is no longer needed and the new version is confirmed stable.

Replication policy

When creating a secret, you choose how Secret Manager distributes it across Google’s infrastructure:

  • Automatic replication: Google distributes the secret across multiple regions for high availability, with no configuration required. This is the right choice for most workloads.

  • User-managed replication: you specify the exact regions where the secret is stored. Use this when data residency requirements restrict which geographic locations can hold your data. User-managed replication also enables CMEK with a region-specific key via Cloud KMS.

Secret vs secret version

This distinction trips up beginners more than almost anything else in Secret Manager. The two resources have completely different roles:

Quick reference

Secret is the named container. It holds metadata (replication policy, labels, rotation config, IAM bindings) but not the actual credential value. IAM bindings go on the secret.

Secret version is the actual stored value. Versions are numbered sequentially (1, 2, 3…) and have a state. The latest alias always resolves to the most recently added enabled version. Your application reads versions.

A practical consequence: you can add 10 versions to a secret and revoke a caller’s access to all of them in one step by removing their binding from the secret resource. You do not need to manage access per version.

IAM roles in Secret Manager

Secret Manager has four main IAM roles. Understanding which one to use and at what scope is the most operationally important part of setting it up correctly. For background on how GCP IAM roles work in general, see the IAM roles guide.

  • roles/secretmanager.secretAccessor: allows reading secret version values. Grant this to the service account that your application runs as, scoped to the specific secret it needs. Not at the project level.

  • roles/secretmanager.viewer: allows listing secrets and viewing metadata, but cannot read secret values. Useful for operations tooling or dashboards that need to know which secrets exist without accessing their contents.

  • roles/secretmanager.secretVersionManager: allows adding new versions and changing version states (enable, disable). Does not allow reading the value of existing versions. Used in automated rotation pipelines where the rotation handler needs to add a new version but should not be able to read existing ones.

  • roles/secretmanager.admin: full control, including creating and deleting secrets, managing all versions, and managing IAM bindings. Restrict this to a small number of identities, ideally not attached to running workloads.

Do not grant secretAccessor at the project level

A project-level secretAccessor binding lets the caller read every secret in the project. Your API server needs its own database password, not access to every credential your team has ever stored. Always bind secretAccessor on the specific secret resource the workload actually needs. This is a core application of least privilege.

When to use Secret Manager

Secret Manager fits whenever an application needs a sensitive value at runtime and you need auditability, rotation, and access control around it. Concrete examples:

  • Cloud Run services: inject database passwords, signing keys, or third-party API keys without baking them into container images or Cloud Run environment variables. See the Cloud Run security model for how this integrates with service identity.

  • GKE workloads: mount secrets as files using the Secret Manager CSI driver, or sync them into Kubernetes Secrets. Compare with native Kubernetes secret handling in Managing Secrets in Kubernetes.

  • Compute Engine VMs: read secrets at startup using the metadata server and the VM’s attached service account, without storing any credentials on the disk image.

  • CI/CD pipelines: inject secrets into Cloud Build steps or GitHub Actions without storing them in pipeline YAML. See Secrets in CI/CD Pipelines for patterns and caveats.

  • Third-party API credentials: Stripe keys, SendGrid API tokens, Twilio auth tokens, and similar values that need to be available to multiple services but should not be shared through code or config files.

  • Per-environment credentials: separate secrets for dev, staging, and production databases, with access granted to only the service accounts in the corresponding environment.

When not to use Secret Manager

Secret Manager is not a general-purpose tool for all configuration:

  • Non-sensitive application config. Feature flags, log levels, timeout values, and similar settings do not need encryption or access auditing. Environment variables, parameter files, or a config service are more appropriate.

  • Encrypting large files or data. Secret Manager is for small credential values (under 64 KB per version). For encrypting arbitrary data at rest, use Cloud KMS directly.

  • Managing cryptographic keys. Secret Manager stores complete values and returns them in plaintext to authorised callers. Cloud KMS stores key material and performs cryptographic operations without exposing the raw key. If you need to encrypt or sign data without the key ever leaving Google’s infrastructure, that is a Cloud KMS use case, not Secret Manager.

Secret Manager and Cloud KMS are not alternatives

Teams often think they need to choose one or the other. In practice they are complementary. Secret Manager stores your credentials and Cloud KMS encrypts them at rest. You can use both in the same project with no conflict.

Secret Manager vs alternatives

Secret Manager vs environment variables

Environment variables are quick to set up but carry real risks for sensitive values. They are not encrypted at rest, not versioned, not audited, and can appear in crash dumps, debug output, and process listings. Secret Manager encrypts values at rest, logs every access, and makes rotation possible without redeployment. For anything sensitive, Secret Manager is the better choice. For non-sensitive config, environment variables are fine.

Secret Manager vs Cloud KMS

These solve different problems. Secret Manager stores a complete value and returns it in plaintext to authorised callers. Cloud KMS stores cryptographic key material and performs encrypt/decrypt/sign operations without ever returning the raw key. Secret Manager actually uses Cloud KMS under the hood to encrypt secret versions at rest. Choosing between them is not an either/or decision. Store credentials in Secret Manager and use Cloud KMS when you need to encrypt your own data with customer-managed keys.

Secret Manager vs Kubernetes Secrets

Native Kubernetes Secrets are base64-encoded, not encrypted by default (unless you configure etcd encryption), and are scoped to a single cluster. They have no versioning and no centralised audit trail. Secret Manager integrates with GKE through the Secret Manager CSI driver, which mounts secret values as files in your pods without requiring you to manage Kubernetes Secrets at all. For GKE workloads the recommended pattern is to use Secret Manager via Workload Identity rather than native Kubernetes Secrets. For the detailed comparison see Managing Secrets in Kubernetes.

Creating and accessing secrets

Create a secret and add the first version:

# Create the secret container with automatic replication
gcloud secrets create db-password \
  --replication-policy=automatic \
  --project=my-app-prod

# Add the first version (the actual credential value)
echo -n "my-super-secret-password" | gcloud secrets versions add db-password \
  --data-file=- \
  --project=my-app-prod

Grant a service account access to read this specific secret:

gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:api-server@my-app-prod.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor" \
  --project=my-app-prod

Read the secret value:

# Read the latest version
gcloud secrets versions access latest \
  --secret=db-password \
  --project=my-app-prod

# Read a specific version by number
gcloud secrets versions access 2 \
  --secret=db-password \
  --project=my-app-prod

Manage version states during and after rotation:

# Disable an old version (data preserved, temporarily inaccessible)
gcloud secrets versions disable 1 \
  --secret=db-password \
  --project=my-app-prod

# Permanently destroy a version
gcloud secrets versions destroy 1 \
  --secret=db-password \
  --project=my-app-prod

Accessing secrets from application code

Applications running on GCP access secrets using the Secret Manager client library and the service account identity attached to the workload. Your application never needs to store a credential to retrieve a credential. The workload identity is the authentication mechanism. There are two main access patterns:

Read at startup

Read the secret once when the application starts and store the value in memory. This is simple and adds no per-request latency, but requires a restart to pick up rotated values.

from google.cloud import secretmanager

client = secretmanager.SecretManagerServiceClient()
name = "projects/my-app-prod/secrets/db-password/versions/latest"
response = client.access_secret_version(request={"name": name})
password = response.payload.data.decode("UTF-8")

Mount as a volume (Cloud Run and GKE)

Secret Manager integrates with Cloud Run and GKE to mount secret values as files in the container filesystem. The platform handles the API call; your application just reads a file. When a new secret version is added, the mounted file updates automatically, allowing zero-downtime rotation if the application watches the file for changes.

Use latest, not a pinned version number

If you reference latest, adding a new version during rotation automatically takes effect on the next read. No code change, no config update, no redeployment required. If you pin to a specific number (e.g. /versions/3), you must update that reference every time you rotate.

Rotation and automated rotation

Manual rotation

The simplest rotation process: generate a new credential value, add it as a new version, verify your application is reading the new value, then disable or destroy the old version. If your application reads latest, no code change is needed. Just add the new version.

Automated rotation via Pub/Sub

For credentials that need scheduled rotation, Secret Manager can publish a notification to a Pub/Sub topic when a rotation window arrives. A Cloud Function or Cloud Run service subscribed to that topic handles the rotation automatically:

  1. Secret Manager publishes the rotation notification to your Pub/Sub topic
  2. Your rotation handler is triggered
  3. The handler generates a new credential (e.g. rotates a database password)
  4. The handler adds the new value as a new secret version
  5. The handler updates the upstream system (e.g. updates the database user password)
  6. The handler disables the old version
# Configure rotation notifications on an existing secret
gcloud secrets update db-password \
  --rotation-period=7776000s \
  --next-rotation-time=2026-06-01T00:00:00Z \
  --topics=projects/my-app-prod/topics/secret-rotation \
  --project=my-app-prod

Because the rotation handler adds a new version and your application reads latest, the cutover happens automatically on the next secret read, with no redeployment. For the complete implementation including the Cloud Function handler and Terraform setup, see Rotating Secrets Automatically.

Common beginner mistakes

  1. Committing secrets to version control. A secret in a git repository is compromised from the moment it is committed, even if deleted later. Git history is permanent and searchable. Revoke it, replace it, and store the new value in Secret Manager immediately.

  2. Granting secretAccessor at the project level. A project-level binding lets the caller read every secret in the project, not just the ones they need. Always bind secretAccessor on the specific secret resource. An API server needs its own database password, not access to every credential in the project.

  3. Sharing one secret across multiple environments. If dev and production use the same secret, a breach in your development environment exposes production credentials. Create separate secrets per environment. Avoid sharing one secret between multiple services when each could have its own. Isolation limits blast radius.

  4. No documented owner or rotation schedule. Secrets created for one-off purposes accumulate over time until nobody knows why they exist, which services depend on them, or when they were last rotated. Every secret should have a documented owner, a purpose, and a rotation policy.

  5. Assuming environment variables are always safe. Environment variables in Cloud Run or GKE are not encrypted at rest in the same way Secret Manager is, can appear in debug output, and have no audit trail. For sensitive values, use Secret Manager and mount as a volume or read via the API.

Best practices

  • Grant secretAccessor at the secret level, not the project level. Scope access as tightly as the workload requires.

  • Create one secret per service per environment. Separate dev, staging, and prod credentials. Separate credentials per service.

  • Use latest with a tested rotation process. The alias makes rotation seamless, but validate that your rotation handler works before relying on it in production.

  • Audit access regularly. Secret Manager writes to Data Access audit logs. Review access patterns in Cloud Audit Logs to detect unexpected or anomalous reads.

  • Document secret ownership. Use labels or a runbook to track which team owns each secret, what it is used for, and what the rotation policy is.

  • Rotate high-risk credentials on a schedule. Database passwords and signing secrets should rotate on a fixed cadence, not just when something goes wrong.

  • Prefer Workload Identity over service account keys. If your workload runs on GCP infrastructure, it can authenticate to Secret Manager using its attached service account identity without needing a stored key file. See Workload Identity Federation for workloads outside GCP.

Frequently asked questions

What is Secret Manager in GCP used for?

Secret Manager stores sensitive values (API keys, database passwords, TLS certificates, OAuth tokens) in a managed, encrypted, access-controlled service. It replaces the unsafe pattern of storing secrets in source code, environment variable files, CI/CD config, or shared documents. Secrets are versioned, audited, and access-gated by IAM roles at the individual secret level.

What is the difference between a secret and a secret version?

A secret is the named container. It holds metadata like the replication policy, labels, and rotation config, but not the actual credential value. A secret version is the actual stored value. Each time you add new data, Secret Manager creates a new version with an incrementing number. The secret is where you apply IAM bindings; versions are what your application actually reads.

Is Secret Manager better than environment variables?

For sensitive credentials, yes. Environment variables are not encrypted at rest, not versioned, not audited, and can leak through crash dumps, debug output, and process inspection. Secret Manager encrypts values at rest using Cloud KMS, logs every access in audit logs, and lets you rotate values without redeploying your application. For non-sensitive config (feature flags, timeouts, log levels), environment variables are fine.

How does secret rotation work in GCP?

You add a new version with the updated credential value. If your application reads the latest alias, it picks up the new value on the next read without any code change. For automated rotation, Secret Manager can publish a Pub/Sub notification when a rotation is due, which triggers a Cloud Function or Cloud Run service to generate a new credential, store it as a new version, and disable the old one. See the dedicated rotation page for the full flow.

What is the difference between Secret Manager and Cloud KMS?

Secret Manager stores complete secret values (passwords, tokens, keys) and returns them in plaintext to authorised callers. Cloud KMS stores cryptographic keys and performs encryption or decryption operations without ever exposing the raw key material. Secret Manager actually uses Cloud KMS under the hood to encrypt secret versions at rest. They solve different problems and are often used together, not instead of each other.

Last verified: 22 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.