GCP for DevOps — Accessing Secrets

2 minute read

Accessing Secrets

Secret Manager integrates with Cloud Run, GKE, Cloud Functions, and Compute Engine. This page covers how to securely inject secrets into your workloads without embedding them in code or environment variables.

Cloud Run — Secrets as Env Vars

# Mount secret as environment variable
$ gcloud run deploy my-api \
    --image=gcr.io/my-project/my-api:v1 \
    --region=us-central1 \
    --set-secrets=DB_PASSWORD=my-db-password:latest \
    --set-secrets=API_KEY=my-api-key:latest

# The container sees:
# DB_PASSWORD=SuperS3cret!
# API_KEY=my-api-key-value

Cloud Run — Secrets as Mounted Files

# Mount secret as a file
$ gcloud run deploy my-api \
    --image=gcr.io/my-project/my-api:v1 \
    --region=us-central1 \
    --set-secrets=/secrets/db-password=my-db-password:latest

# The container reads from: /secrets/db-password
# Read secret from mounted file
with open("/secrets/db-password", "r") as f:
    db_password = f.read()

Cloud Functions — Secrets

# Mount secrets in Cloud Functions
$ gcloud functions deploy my-function \
    --gen2 \
    --runtime=python312 \
    --region=us-central1 \
    --source=. \
    --entry-point=handler \
    --trigger-http \
    --set-secrets=DB_PASSWORD=my-db-password:latest \
    --set-secrets=/secrets/api-key=my-api-key:latest

GKE — Secrets Store CSI Driver

Use the Secret Manager CSI driver to mount secrets as volumes in GKE pods:

# Enable the Secret Manager addon on GKE
$ gcloud container clusters update my-cluster \
    --region=us-central1 \
    --update-addons=SecretManagerAddon=ENABLED
# secret-provider-class.yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: my-secrets
spec:
  provider: gcp
  parameters:
    secrets: |
      - resourceName: "projects/my-project/secrets/my-db-password/versions/latest"
        path: "db-password"
      - resourceName: "projects/my-project/secrets/my-api-key/versions/latest"
        path: "api-key"
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  serviceAccountName: my-app-sa
  containers:
    - name: app
      image: gcr.io/my-project/my-app:v1
      volumeMounts:
        - name: secrets
          mountPath: /secrets
          readOnly: true
  volumes:
    - name: secrets
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: my-secrets

GKE — Workload Identity + Secret Manager

# Set up Workload Identity
$ gcloud iam service-accounts create app-sa \
    --display-name="App Service Account"

# Grant secret access
$ gcloud secrets add-iam-policy-binding my-db-password \
    --member="serviceAccount:app-sa@my-project.iam.gserviceaccount.com" \
    --role="roles/secretmanager.secretAccessor"

# Bind Kubernetes SA to GCP SA
$ gcloud iam service-accounts add-iam-policy-binding \
    app-sa@my-project.iam.gserviceaccount.com \
    --role="roles/iam.workloadIdentityUser" \
    --member="serviceAccount:my-project.svc.id.goog[default/my-app-sa]"
# kubernetes-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app-sa
  annotations:
    iam.gke.io/gcp-service-account: app-sa@my-project.iam.gserviceaccount.com

Compute Engine — Access from VMs

# Using the client library (Python)
$ gcloud compute ssh my-vm --command='python3 -c "
from google.cloud import secretmanager
client = secretmanager.SecretManagerServiceClient()
response = client.access_secret_version(
    request={\"name\": \"projects/my-project/secrets/my-db-password/versions/latest\"}
)
print(response.payload.data.decode(\"UTF-8\"))
"'

# Using gcloud from a VM
$ gcloud secrets versions access latest --secret=my-db-password

Comparison of Access Methods

Method Use Case Pros Cons
Env Var Cloud Run, Functions Simple, native support Visible in process list
File Mount Cloud Run, GKE More secure, larger secrets Needs volume config
CSI Driver GKE Native K8s, auto-rotation Setup complexity
Client Library Any workload Full control, any language Code dependency
gcloud CLI Scripts, VMs Quick access Requires gcloud installed

Common Mistakes

Mistake Why It’s Wrong Fix
Using env vars for large secrets 32 KB limit, visible in process Use file mounts
Missing Workload Identity binding Pod can’t access secrets Bind K8s SA to GCP SA
Hardcoding project ID Breaks portability Use GOOGLE_CLOUD_PROJECT env
Not pinning secret versions latest may change unexpectedly Pin to specific version in prod
No least-privilege access Over-permissioned SA Grant secretAccessor only to needed secrets

Quick Reference

Platform Secret Access Method
Cloud Run --set-secrets=ENV=SECRET:VERSION
Cloud Functions --set-secrets=ENV=SECRET:VERSION
GKE SecretProviderClass + CSI driver
Compute Engine Client library or gcloud CLI

Next → Cloud Asset Inventory

Updated: