Google Cloud Run
Sync KeyEnv secrets to Google Cloud Run services.
Google Cloud Run Integration
Sync secrets from KeyEnv to your Cloud Run services.
Prerequisites
- Google Cloud project with Cloud Run enabled
- gcloud CLI installed and authenticated
- KeyEnv service token with read access
Quick Sync
Sync secrets directly as environment variables:
export KEYENV_TOKEN=your-service-token
SERVICE_NAME="my-service"
REGION="us-central1"
# Export and set env vars
secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format shell)
gcloud run services update "$SERVICE_NAME" \
--region="$REGION" \
--update-env-vars="$secrets"Sync Script
Create a reusable sync script:
#!/bin/bash
# sync-to-cloud-run.sh
set -euo pipefail
: "${KEYENV_TOKEN:?KEYENV_TOKEN is required}"
PROJECT_ID="${KEYENV_PROJECT:-YOUR_PROJECT_ID}"
ENVIRONMENT="${KEYENV_ENV:-production}"
SERVICE_NAME="${CLOUD_RUN_SERVICE:-my-service}"
REGION="${CLOUD_RUN_REGION:-us-central1}"
echo "Syncing KeyEnv ($ENVIRONMENT) to Cloud Run ($SERVICE_NAME)..."
# Export secrets
secrets=$(keyenv export -p "$PROJECT_ID" -e "$ENVIRONMENT" --format shell)
# Update Cloud Run service
gcloud run services update "$SERVICE_NAME" \
--region="$REGION" \
--update-env-vars="$secrets"
echo "Done! Cloud Run is redeploying..."Using Secret Manager (Recommended)
For production, store secrets in Google Secret Manager and reference them in Cloud Run:
1. Sync to Secret Manager
#!/bin/bash
# sync-to-secret-manager.sh
set -euo pipefail
GCP_PROJECT="your-gcp-project"
# Export secrets from KeyEnv
secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format json)
# Create/update each secret in Secret Manager
echo "$secrets" | jq -r '.secrets[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
# Try to create, or add new version if exists
if gcloud secrets describe "$key" --project="$GCP_PROJECT" &>/dev/null; then
echo -n "$value" | gcloud secrets versions add "$key" --data-file=- --project="$GCP_PROJECT"
echo "Updated: $key"
else
echo -n "$value" | gcloud secrets create "$key" --data-file=- --project="$GCP_PROJECT"
echo "Created: $key"
fi
done2. Reference in Cloud Run
gcloud run services update my-service \
--region=us-central1 \
--update-secrets="DATABASE_URL=DATABASE_URL:latest,API_KEY=API_KEY:latest"Or in your service.yaml:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
containers:
- image: gcr.io/my-project/my-service
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: DATABASE_URL
key: latest
- name: API_KEY
valueFrom:
secretKeyRef:
name: API_KEY
key: latestCI/CD Integration
GitHub Actions
name: Deploy to Cloud Run
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Install KeyEnv CLI
run: curl -fsSL https://keyenv.dev/install.sh | bash
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.WIF_PROVIDER }}
service_account: ${{ vars.WIF_SERVICE_ACCOUNT }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Sync secrets to Secret Manager
run: |
export PATH="$HOME/.keyenv/bin:$PATH"
keyenv export -p ${{ vars.KEYENV_PROJECT }} -e production --format json | \
jq -r '.secrets[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
if gcloud secrets describe "$key" &>/dev/null; then
echo -n "$value" | gcloud secrets versions add "$key" --data-file=-
else
echo -n "$value" | gcloud secrets create "$key" --data-file=-
fi
done
env:
KEYENV_TOKEN: ${{ secrets.KEYENV_TOKEN }}
- name: Deploy to Cloud Run
uses: google-github-actions/deploy-cloudrun@v2
with:
service: my-service
region: us-central1
image: gcr.io/${{ vars.GCP_PROJECT }}/my-serviceCloud Build
# cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/curl'
args: ['-fsSL', 'https://keyenv.dev/install.sh', '-o', 'install.sh']
- name: 'ubuntu'
entrypoint: 'bash'
args: ['install.sh']
- name: 'ubuntu'
entrypoint: 'bash'
args:
- '-c'
- |
export PATH="$$HOME/.keyenv/bin:$$PATH"
keyenv export -p $$KEYENV_PROJECT -e production --format json | \
jq -r '.secrets[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
gcloud secrets versions add "$$key" --data-file=- <<< "$$value" || \
gcloud secrets create "$$key" --data-file=- <<< "$$value"
done
secretEnv: ['KEYENV_TOKEN']
env:
- 'KEYENV_PROJECT=your-project-id'
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'my-service', '--image', 'gcr.io/$PROJECT_ID/my-service', '--region', 'us-central1']
availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/KEYENV_TOKEN/versions/latest
env: 'KEYENV_TOKEN'Multiple Services
Sync to multiple Cloud Run services:
#!/bin/bash
SERVICES=("api" "web" "worker")
REGION="us-central1"
secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format shell)
for service in "${SERVICES[@]}"; do
echo "Syncing to $service..."
gcloud run services update "$service" \
--region="$REGION" \
--update-env-vars="$secrets"
doneTerraform Integration
# main.tf
resource "google_secret_manager_secret" "secrets" {
for_each = toset(var.secret_keys)
secret_id = each.key
replication {
auto {}
}
}
resource "google_cloud_run_v2_service" "app" {
name = "my-service"
location = "us-central1"
template {
containers {
image = "gcr.io/my-project/my-service"
dynamic "env" {
for_each = var.secret_keys
content {
name = env.value
value_source {
secret_key_ref {
secret = google_secret_manager_secret.secrets[env.value].secret_id
version = "latest"
}
}
}
}
}
service_account = google_service_account.app.email
}
}Best Practices
- Use Secret Manager - Better security and automatic rotation support
- Grant minimal permissions - Service accounts should only access needed secrets
- Use IAM conditions - Restrict secret access by service identity
- Enable audit logging - Track secret access in Cloud Audit Logs
Troubleshooting
Permission Denied
Grant the Cloud Run service account access to secrets:
gcloud secrets add-iam-policy-binding SECRET_NAME \
--member="serviceAccount:[email protected]" \
--role="roles/secretmanager.secretAccessor"Service Not Restarting
Force a new revision:
gcloud run services update my-service --region=us-central1 --no-traffic
gcloud run services update-traffic my-service --region=us-central1 --to-latestSecrets Not Mounting
Check the service configuration:
gcloud run services describe my-service --region=us-central1 --format=yaml