Secrets Management on GCP
Never store Open Astra credentials in environment files, Docker images, or source code. GCP Secret Manager is the correct place for all sensitive values. Both Firebase App Hosting and Cloud Run can pull secrets from Secret Manager at runtime — no .env file needed on the server.
What to store in Secret Manager
| Secret name (suggested) | Env var | Description |
|---|---|---|
astra-database-url | DATABASE_URL | PostgreSQL connection string (includes password) |
astra-jwt-secret | JWT_SECRET | Min 32 chars — signs all user tokens |
astra-typesense-api-key | TYPESENSE_API_KEY | Typesense admin key |
astra-typesense-url | TYPESENSE_URL | Internal URL of your Typesense instance |
astra-internal-api-key | INTERNAL_API_KEY | Service-to-service auth key |
astra-openai-api-key | OPENAI_API_KEY | Add one per LLM provider you use |
Step 1 — Create the secrets
Run this once after creating your GCP project:
# Create every secret Open Astra needs
# Run once per GCP project — values are stored encrypted in Secret Manager
echo -n "postgresql://user:pass@host:5432/astra" \
| gcloud secrets create astra-database-url --data-file=-
echo -n "$(openssl rand -hex 32)" \
| gcloud secrets create astra-jwt-secret --data-file=-
echo -n "your-typesense-api-key" \
| gcloud secrets create astra-typesense-api-key --data-file=-
echo -n "http://your-typesense-host:8108" \
| gcloud secrets create astra-typesense-url --data-file=-
echo -n "$(openssl rand -hex 32)" \
| gcloud secrets create astra-internal-api-key --data-file=-
# LLM provider keys (add the ones you use)
echo -n "sk-..." | gcloud secrets create astra-openai-api-key --data-file=-
echo -n "gsk_..." | gcloud secrets create astra-groq-api-key --data-file=-Firebase App Hosting
Firebase App Hosting reads secrets declared in apphosting.yaml at the root of your repository. Each entry maps a secret name in Secret Manager to an environment variable in the runtime container.
apphosting.yaml
# apphosting.yaml — Firebase App Hosting
# Place this file at the root of your repository.
# Secrets are pulled from GCP Secret Manager at build and runtime.
runConfig:
concurrency: 80
env:
- variable: DATABASE_URL
secret: astra-database-url
availability: [BUILD, RUNTIME]
- variable: JWT_SECRET
secret: astra-jwt-secret
availability: [RUNTIME]
- variable: TYPESENSE_API_KEY
secret: astra-typesense-api-key
availability: [RUNTIME]
- variable: TYPESENSE_URL
secret: astra-typesense-url
availability: [RUNTIME]
- variable: INTERNAL_API_KEY
secret: astra-internal-api-key
availability: [RUNTIME]
# LLM provider keys — add the ones you use
- variable: OPENAI_API_KEY
secret: astra-openai-api-key
availability: [RUNTIME]Grant access
The App Hosting service account must have roles/secretmanager.secretAccessor on each secret. Run this after creating your secrets and before deploying:
# Grant the App Hosting service account access to each secret
# Replace PROJECT_ID and BACKEND_ID with your values.
# BACKEND_ID is shown in the Firebase console under App Hosting.
SA="firebase-app-hosting-compute@PROJECT_ID.iam.gserviceaccount.com"
for SECRET in \
astra-database-url \
astra-jwt-secret \
astra-typesense-api-key \
astra-typesense-url \
astra-internal-api-key \
astra-openai-api-key
do
gcloud secrets add-iam-policy-binding $SECRET \
--member="serviceAccount:$SA" \
--role="roles/secretmanager.secretAccessor"
doneapphosting.yaml and granting IAM, push a commit to trigger a new build. Firebase App Hosting resolves secret values at build time for BUILD availability and injects them at container start for RUNTIME only.Cloud Run
For the Terraform + Cloud Run deployment path, pass secrets as environment variable references using --set-secrets. Each reference is resolved at container start — the plaintext value never appears in the deploy command's output.
Deploy with secrets
# Cloud Run — inject secrets as environment variables at deploy time
gcloud run deploy astra-gateway \
--image us-central1-docker.pkg.dev/PROJECT_ID/astra-images/gateway:latest \
--region us-central1 \
--set-secrets=DATABASE_URL=astra-database-url:latest \
--set-secrets=JWT_SECRET=astra-jwt-secret:latest \
--set-secrets=TYPESENSE_API_KEY=astra-typesense-api-key:latest \
--set-secrets=TYPESENSE_URL=astra-typesense-url:latest \
--set-secrets=INTERNAL_API_KEY=astra-internal-api-key:latest \
--set-secrets=OPENAI_API_KEY=astra-openai-api-key:latestGrant access
# Grant the Cloud Run service account access to secrets
SA="astra-gateway-sa@PROJECT_ID.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:$SA" \
--role="roles/secretmanager.secretAccessor"Rotating secrets
Secret Manager is versioned — adding a new version does not delete the old one. Services keep running on the old version until they are redeployed or restarted.
# Update a secret value (creates a new version, old version stays)
echo -n "new-value" | gcloud secrets versions add astra-jwt-secret --data-file=-
# For Cloud Run: force a new revision to pick up the new version
gcloud run services update astra-gateway --region us-central1
# For Firebase App Hosting: redeploy from the Firebase console or push a commitBUILD vs RUNTIME availability
| Availability | When injected | Use for |
|---|---|---|
BUILD | During npm run build | Variables needed at SSR build time (e.g. public API URLs) |
RUNTIME | When the container starts | All credentials — never expose at build time |
[BUILD, RUNTIME] | Both phases | DATABASE_URL if migrations run at build time |
See also: GCP Deployment for the full Cloud Run + Cloud SQL setup, Workspace Secrets for runtime secret injection into agents.