8.4 KiB
Google Secret Manager Integration Guide
This guide explains how to integrate Google Cloud Secret Manager with your Node.js application to securely manage environment variables.
Overview
The Google Secret Manager integration allows you to:
- Store sensitive configuration values (passwords, API keys, tokens) in Google Cloud Secret Manager
- Load secrets at application startup and merge them with your existing environment variables
- Maintain backward compatibility with
.envfiles for local development - Use minimal code changes - existing
process.env.VARIABLE_NAMEaccess continues to work
Prerequisites
- Google Cloud Project with Secret Manager API enabled
- Service Account with Secret Manager Secret Accessor role
- Authentication - Service account credentials configured (via
GCP_KEY_FILEor default credentials)
Setup Instructions
1. Enable Secret Manager API
gcloud services enable secretmanager.googleapis.com --project=YOUR_PROJECT_ID
2. Create Secrets in Google Secret Manager
Create secrets using the Google Cloud Console or gcloud CLI:
# Example: Create a database password secret
echo -n "your-secure-password" | gcloud secrets create DB_PASSWORD \
--project=YOUR_PROJECT_ID \
--data-file=-
# Example: Create a JWT secret
echo -n "your-jwt-secret-key" | gcloud secrets create JWT_SECRET \
--project=YOUR_PROJECT_ID \
--data-file=-
# Grant service account access to secrets
gcloud secrets add-iam-policy-binding DB_PASSWORD \
--member="serviceAccount:YOUR_SERVICE_ACCOUNT@YOUR_PROJECT.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor" \
--project=YOUR_PROJECT_ID
3. Configure Environment Variables
Add the following to your .env file:
# Google Secret Manager Configuration
USE_GOOGLE_SECRET_MANAGER=true
GCP_PROJECT_ID=your-project-id
# Optional: Prefix for all secret names (e.g., "prod" -> looks for "prod-DB_PASSWORD")
GCP_SECRET_PREFIX=
# Optional: JSON file mapping secret names to env var names
GCP_SECRET_MAP_FILE=./secret-map.json
Important Notes:
- Set
USE_GOOGLE_SECRET_MANAGER=trueto enable the integration GCP_PROJECT_IDmust be set (same as used for GCS/Vertex AI)GCP_KEY_FILEshould already be configured for other GCP services- When
USE_GOOGLE_SECRET_MANAGER=falseor not set, the app uses.envfile only
4. Secret Name Mapping
By default, secrets in Google Secret Manager are automatically mapped to environment variables:
- Secret name:
DB_PASSWORD→ Environment variable:DB_PASSWORD - Secret name:
db-password→ Environment variable:DB_PASSWORD(hyphens converted to underscores, uppercase) - Secret name:
jwt-secret-key→ Environment variable:JWT_SECRET_KEY
Custom Mapping (Optional)
If you need custom mappings, create a JSON file (e.g., secret-map.json):
{
"db-password-prod": "DB_PASSWORD",
"jwt-secret-key": "JWT_SECRET",
"okta-client-secret-prod": "OKTA_CLIENT_SECRET"
}
Then set in .env:
GCP_SECRET_MAP_FILE=./secret-map.json
5. Secret Prefix (Optional)
If all your secrets share a common prefix:
GCP_SECRET_PREFIX=prod
This will look for secrets named prod-DB_PASSWORD, prod-JWT_SECRET, etc.
How It Works
-
Application Startup:
.envfile is loaded first (provides fallback values)- If
USE_GOOGLE_SECRET_MANAGER=true, secrets are fetched from Google Secret Manager - Secrets are merged into
process.env, overriding.envvalues if they exist - Application continues with merged environment variables
-
Fallback Behavior:
- If Secret Manager is disabled or fails, the app falls back to
.envfile - No errors are thrown - the app continues with available configuration
- Logs indicate whether secrets were loaded successfully
- If Secret Manager is disabled or fails, the app falls back to
-
Existing Code Compatibility:
- No changes needed to existing code
- Continue using
process.env.VARIABLE_NAMEas before - Secrets from GCS automatically populate
process.env
Default Secrets Loaded
The service automatically attempts to load these common secrets (if they exist in Secret Manager):
Database:
DB_HOST,DB_PORT,DB_NAME,DB_USER,DB_PASSWORD
Authentication:
JWT_SECRET,REFRESH_TOKEN_SECRET,SESSION_SECRET
SSO/Okta:
OKTA_DOMAIN,OKTA_CLIENT_ID,OKTA_CLIENT_SECRET,OKTA_API_TOKEN
Email:
SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASSWORD
Web Push (VAPID):
VAPID_PUBLIC_KEY,VAPID_PRIVATE_KEY
Logging:
LOKI_HOST,LOKI_USER,LOKI_PASSWORD
Loading Custom Secrets
To load additional secrets, modify the code:
// In server.ts or app.ts
import { googleSecretManager } from './services/googleSecretManager.service';
// Load default secrets + custom ones
await googleSecretManager.loadSecrets([
'DB_PASSWORD',
'JWT_SECRET',
'CUSTOM_API_KEY', // Your custom secret
'CUSTOM_SECRET_2'
]);
Or load a single secret on-demand:
import { googleSecretManager } from './services/googleSecretManager.service';
const apiKey = await googleSecretManager.getSecretValue('CUSTOM_API_KEY', 'API_KEY');
Security Best Practices
-
Service Account Permissions:
- Grant only
roles/secretmanager.secretAccessorrole - Use separate service accounts for different environments
- Never grant
roles/ownerorroles/editorto service accounts
- Grant only
-
Secret Rotation:
- Rotate secrets regularly in Google Secret Manager
- The app automatically uses the
latestversion of each secret - No code changes needed when secrets are rotated
-
Environment Separation:
- Use different Google Cloud projects for dev/staging/prod
- Use
GCP_SECRET_PREFIXto namespace secrets by environment - Never commit
.envfiles with production secrets to version control
-
Access Control:
- Use IAM policies to control who can read secrets
- Enable audit logging for secret access
- Regularly review secret access logs
Troubleshooting
Secrets Not Loading
Check logs for:
[Secret Manager] Google Secret Manager is disabled (USE_GOOGLE_SECRET_MANAGER != true)
[Secret Manager] GCP_PROJECT_ID not set, skipping Google Secret Manager
[Secret Manager] Failed to load secrets: [error message]
Common issues:
USE_GOOGLE_SECRET_MANAGERnot set totrueGCP_PROJECT_IDnot configured- Service account lacks Secret Manager permissions
- Secrets don't exist in Secret Manager
- Incorrect secret names (check case sensitivity)
Service Account Authentication
Ensure service account credentials are available:
- Set
GCP_KEY_FILEto point to service account JSON file - Or configure Application Default Credentials (ADC)
- Test with:
gcloud auth application-default login
Secret Not Found
If a secret doesn't exist in Secret Manager:
- The app logs a debug message and continues
- Falls back to
.envfile value - This is expected behavior - not all secrets need to be in GCS
Debugging
Enable debug logging by setting:
LOG_LEVEL=debug
This will show detailed logs about which secrets are being loaded.
Example Configuration
Local Development (.env):
USE_GOOGLE_SECRET_MANAGER=false
DB_PASSWORD=local-dev-password
JWT_SECRET=local-jwt-secret
Production (.env):
USE_GOOGLE_SECRET_MANAGER=true
GCP_PROJECT_ID=re-platform-workflow-dealer
GCP_SECRET_PREFIX=prod
GCP_KEY_FILE=./credentials/service-account.json
# DB_PASSWORD and other secrets loaded from GCS
Migration Strategy
-
Phase 1: Setup
- Create secrets in Google Secret Manager
- Keep
.envfile with current values (as backup)
-
Phase 2: Test
- Set
USE_GOOGLE_SECRET_MANAGER=truein development - Verify secrets are loaded correctly
- Test application functionality
- Set
-
Phase 3: Production
- Deploy with
USE_GOOGLE_SECRET_MANAGER=true - Monitor logs for secret loading success
- Remove sensitive values from
.envfile (keep placeholders)
- Deploy with
-
Phase 4: Cleanup
- Remove production secrets from
.envfile - Ensure all secrets are in Secret Manager
- Document secret names and mappings
- Remove production secrets from