GCP for DevOps — Accessing Secrets
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