Hardcoded secrets in source code, configuration files, and environment variables are a leading cause of security breaches. Google Cloud Secret Manager provides a secure, centralized way to store API keys, passwords, certificates, and other sensitive data with full audit logging, access control, and versioning.
This tutorial walks you through creating secrets, managing versions, accessing secrets from applications, and implementing rotation. For comprehensive cloud security practices, see our 30 Cloud Security Tips for 2026 guide.
Prerequisites
- Secret Manager Admin role for creating/managing secrets
- A Google Cloud project with billing enabled
- Secret Manager API enabled
- gcloud CLI installed (optional, for CLI commands)
Enable Secret Manager API
# Enable the API
gcloud services enable secretmanager.googleapis.com
# Verify it's enabled
gcloud services list --enabled | grep secretmanagerStep 1: Create a Secret
Via Google Cloud Console
-
- Navigate to [Secret Manager](https://console.cloud.google.com/security/secret-manager)
- Click **Create Secret**
- Configure the secret:
-
Name: Use descriptive names (e.g.,
database-password-prod) -
Secret value: Enter or upload the secret data
-
Replication: Automatic (recommended) or user-managed
-
Optionally configure:
-
Labels: For organization and billing
-
Rotation: Set rotation schedule
-
Expiration: Auto-delete after date
-
Customer-managed encryption: Use your own Cloud KMS key
-
Click Create Secret
Via gcloud CLI
# Create a secret (creates the secret container)
gcloud secrets create database-password-prod \
--replication-policy="automatic" \
--labels=environment=production,team=backend
# Add a secret version (the actual secret value)
echo -n "mySecretPassword123" | gcloud secrets versions add database-password-prod --data-file=-
# Or from a file
gcloud secrets versions add database-password-prod --data-file=./secret.txt**Important:** The
-nflag inecho -nprevents adding a newline character to your secret, which can cause authentication failures.
Step 2: Manage Secret Versions
Secret Manager maintains multiple versions of each secret, enabling rotation without downtime:
Add a New Version
# Add new version (becomes the latest)
echo -n "newSecretPassword456" | gcloud secrets versions add database-password-prod --data-file=-
# List all versions
gcloud secrets versions list database-password-prodAccess Specific Versions
# Access latest version
gcloud secrets versions access latest --secret=database-password-prod
# Access specific version
gcloud secrets versions access 1 --secret=database-password-prod
# Access version 2
gcloud secrets versions access 2 --secret=database-password-prodDisable and Destroy Versions
# Disable a version (prevents access but can be re-enabled)
gcloud secrets versions disable 1 --secret=database-password-prod
# Re-enable a version
gcloud secrets versions enable 1 --secret=database-password-prod
# Destroy a version (permanent - cannot be recovered)
gcloud secrets versions destroy 1 --secret=database-password-prodStep 3: Configure Access Control
Grant least-privilege access using IAM roles:
Key Roles
- roles/secretmanager.admin - Full control over secrets
- roles/secretmanager.secretAccessor - Read secret values (most common for apps)
- roles/secretmanager.viewer - View secret metadata (not values)
- roles/secretmanager.secretVersionManager - Add/manage versions
Grant Access to Service Account
# Grant accessor role to a service account
gcloud secrets add-iam-policy-binding database-password-prod \
--member="serviceAccount:my-app@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
# Grant to all secrets in project (use cautiously)
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:my-app@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"Grant Access via Console
-
- Click on a secret in Secret Manager
- Select the **Permissions** tab
- Click **Grant Access**
- Add the principal (service account email)
- Select the role (Secret Manager Secret Accessor)
- Click **Save**
Step 4: Access Secrets from Cloud Functions
Option A: Environment Variable Mounting
Mount secrets as environment variables in function configuration:
# Deploy with secret as environment variable
gcloud functions deploy my-function \
--runtime=nodejs20 \
--trigger-http \
--set-secrets='DB_PASSWORD=database-password-prod:latest'In your function code:
// Node.js
exports.myFunction = (req, res) => {
const dbPassword = process.env.DB_PASSWORD;
// Use the password
};Option B: Secret Manager API
Access secrets programmatically for dynamic retrieval:
// Node.js
const {SecretManagerServiceClient} = require('@google-cloud/secret-manager');
const client = new SecretManagerServiceClient();
async function getSecret() {
const [version] = await client.accessSecretVersion({
name: 'projects/PROJECT_ID/secrets/database-password-prod/versions/latest',
});
return version.payload.data.toString();
}# Python
from google.cloud import secretmanager
def get_secret():
client = secretmanager.SecretManagerServiceClient()
name = "projects/PROJECT_ID/secrets/database-password-prod/versions/latest"
response = client.access_secret_version(request={"name": name})
return response.payload.data.decode("UTF-8")Step 5: Access Secrets from Compute Engine
Using the VM's Service Account
-
- Ensure the VM's service account has **Secret Manager Secret Accessor** role
- Access secrets via gcloud or API:
# On the VM
gcloud secrets versions access latest --secret=database-password-prod
# Or using curl with metadata server authentication
curl "https://secretmanager.googleapis.com/v1/projects/PROJECT_ID/secrets/database-password-prod/versions/latest:access" \
-H "Authorization: Bearer $(gcloud auth print-access-token)"Using Client Libraries
# Python example on Compute Engine
from google.cloud import secretmanager
import google.auth
# Uses default credentials from VM metadata
credentials, project = google.auth.default()
client = secretmanager.SecretManagerServiceClient(credentials=credentials)
name = f"projects/{project}/secrets/database-password-prod/versions/latest"
response = client.access_secret_version(request={"name": name})
secret_value = response.payload.data.decode("UTF-8")Step 6: Access Secrets from Cloud Run
Mount as Environment Variable
# Deploy with secret
gcloud run deploy my-service \
--image=gcr.io/PROJECT_ID/my-image \
--set-secrets=DB_PASSWORD=database-password-prod:latest \
--service-account=my-app@PROJECT_ID.iam.gserviceaccount.comMount as Volume
# Mount secret as file
gcloud run deploy my-service \
--image=gcr.io/PROJECT_ID/my-image \
--set-secrets=/secrets/db-password=database-password-prod:latestAccess the mounted file in your container:
# Read from file path
with open('/secrets/db-password', 'r') as f:
db_password = f.read()Step 7: Set Up Secret Rotation
Configure automatic rotation reminders:
Create Rotation Schedule
# Set rotation period (90 days)
gcloud secrets update database-password-prod \
--rotation-period="90d" \
--next-rotation-time="2026-04-13T00:00:00Z"
# Add notification topic for rotation events
gcloud secrets update database-password-prod \
--topics=projects/PROJECT_ID/topics/secret-rotationImplement Rotation Function
Create a Cloud Function to handle rotation:
// Cloud Function triggered by Pub/Sub
const {SecretManagerServiceClient} = require('@google-cloud/secret-manager');
exports.rotateSecret = async (event, context) => {
const message = JSON.parse(Buffer.from(event.data, 'base64').toString());
const secretName = message.name;
// Generate new secret value
const newPassword = generateSecurePassword();
// Update the dependent service (e.g., database user password)
await updateDatabasePassword(newPassword);
// Add new version to Secret Manager
const client = new SecretManagerServiceClient();
await client.addSecretVersion({
parent: secretName,
payload: { data: Buffer.from(newPassword) }
});
console.log(`Rotated secret: ${secretName}`);
};Step 8: Enable Audit Logging
Track all secret access for security monitoring:
-
- Go to **IAM & Admin > Audit Logs**
- Find **Secret Manager API**
- Enable:
-
Admin Read - Who listed/viewed secret metadata
-
Data Read - Who accessed secret values
-
Data Write - Who created/modified secrets
-
Click Save
Query audit logs for secret access:
# View who accessed a secret
gcloud logging read 'protoPayload.serviceName="secretmanager.googleapis.com" AND protoPayload.methodName="google.cloud.secretmanager.v1.SecretManagerService.AccessSecretVersion"' \
--limit=100 \
--format="table(timestamp,protoPayload.authenticationInfo.principalEmail,protoPayload.resourceName)"Best Practices
- Use descriptive names - Include environment and purpose (e.g.,
api-key-stripe-prod) - Apply labels - For organization, cost tracking, and policy enforcement
- Grant least privilege - Only accessor role for applications
- Rotate regularly - At least every 90 days for passwords
- Enable audit logging - Track all access for security monitoring
- Use automatic replication - Unless compliance requires specific regions
- Store individual credentials - Not full connection strings
- Never log secret values - Mask in application logs
- Set expiration dates - For temporary secrets
Related Resources
- 30 Cloud Security Tips for 2026 - Comprehensive cloud security guide
- How to Secure Cloud SQL Database Access - Use secrets for database credentials
- Secret Manager Documentation
- Secret Rotation Guide
Need help implementing secrets management or building a comprehensive security program? Contact InventiveHQ for expert guidance on cloud security and credential management.