KeyEnvKeyEnv
SDKs & Integrations

Google Cloud Functions

Load KeyEnv secrets in Google Cloud Functions.

Google Cloud Functions Integration

Load secrets from KeyEnv in your Google Cloud Functions.

Prerequisites

  • Google Cloud project with Cloud Functions enabled
  • gcloud CLI installed
  • KeyEnv service token with read access

Quick Sync

Deploy with secrets as environment variables:

export KEYENV_TOKEN=your-service-token

FUNCTION_NAME="my-function"
REGION="us-central1"

# Export to .env file
keyenv export -p YOUR_PROJECT_ID -e production --format dotenv > .env.production

# Deploy with env vars
gcloud functions deploy "$FUNCTION_NAME" \
  --region="$REGION" \
  --runtime=nodejs20 \
  --trigger-http \
  --env-vars-file=.env.production

Sync Script

Create a reusable deployment script:

#!/bin/bash
# deploy-function.sh

set -euo pipefail

: "${KEYENV_TOKEN:?KEYENV_TOKEN is required}"

PROJECT_ID="${KEYENV_PROJECT:-YOUR_PROJECT_ID}"
ENVIRONMENT="${KEYENV_ENV:-production}"
FUNCTION_NAME="${FUNCTION_NAME:-my-function}"
REGION="${REGION:-us-central1}"
RUNTIME="${RUNTIME:-nodejs20}"

echo "Exporting secrets from KeyEnv ($ENVIRONMENT)..."
keyenv export -p "$PROJECT_ID" -e "$ENVIRONMENT" --format dotenv > .env.deploy

echo "Deploying $FUNCTION_NAME to Cloud Functions..."
gcloud functions deploy "$FUNCTION_NAME" \
  --region="$REGION" \
  --runtime="$RUNTIME" \
  --trigger-http \
  --allow-unauthenticated \
  --env-vars-file=.env.deploy

# Cleanup
rm .env.deploy

echo "Done!"

Using SDK at Runtime

For dynamic secret loading, use the Node.js or Python SDK.

Node.js Function

// index.js
const { KeyEnv } = require('keyenv');
const functions = require('@google-cloud/functions-framework');

const keyenv = new KeyEnv({
  token: process.env.KEYENV_TOKEN,
  cacheTtl: 300, // Cache for 5 minutes
});

let secretsLoaded = false;

functions.http('helloWorld', async (req, res) => {
  // Load secrets on first invocation (cached)
  if (!secretsLoaded) {
    await keyenv.loadEnv(process.env.KEYENV_PROJECT, 'production');
    secretsLoaded = true;
  }

  // Use secrets
  const apiKey = process.env.API_KEY;

  res.send('Hello World!');
});

Python Function

# main.py
import functions_framework
import os
from keyenv import KeyEnv

keyenv = KeyEnv(
    token=os.environ["KEYENV_TOKEN"],
    cache_ttl=300,
)

secrets_loaded = False

@functions_framework.http
def hello_world(request):
    global secrets_loaded

    if not secrets_loaded:
        keyenv.load_env(os.environ["KEYENV_PROJECT"], "production")
        secrets_loaded = True

    api_key = os.environ.get("API_KEY")

    return "Hello World!"

For production, store secrets in Google Secret Manager.

1. Sync to Secret Manager

#!/bin/bash
# sync-to-secret-manager.sh

GCP_PROJECT="your-gcp-project"

keyenv export -p YOUR_PROJECT_ID -e production --format json | \
  jq -r '.secrets[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
    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
done

2. Access in Function

// index.js
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const functions = require('@google-cloud/functions-framework');

const secretClient = new SecretManagerServiceClient();
const secrets = {};

async function loadSecret(name) {
  if (!secrets[name]) {
    const [version] = await secretClient.accessSecretVersion({
      name: `projects/${process.env.GCP_PROJECT}/secrets/${name}/versions/latest`,
    });
    secrets[name] = version.payload.data.toString();
  }
  return secrets[name];
}

functions.http('helloWorld', async (req, res) => {
  const apiKey = await loadSecret('API_KEY');
  res.send('Hello!');
});

3. Reference via Environment

Or reference secrets directly in deployment:

gcloud functions deploy my-function \
  --region=us-central1 \
  --runtime=nodejs20 \
  --trigger-http \
  --set-secrets="DATABASE_URL=DATABASE_URL:latest,API_KEY=API_KEY:latest"

CI/CD Integration

GitHub Actions

name: Deploy Cloud Function

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
        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
              gcloud secrets versions add "$key" --data-file=- <<< "$value" 2>/dev/null || \
              gcloud secrets create "$key" --data-file=- <<< "$value"
            done
        env:
          KEYENV_TOKEN: ${{ secrets.KEYENV_TOKEN }}

      - name: Deploy function
        run: |
          gcloud functions deploy my-function \
            --region=us-central1 \
            --runtime=nodejs20 \
            --trigger-http \
            --set-secrets="DATABASE_URL=DATABASE_URL:latest,API_KEY=API_KEY:latest"

Cloud 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 dotenv > .env.deploy
    secretEnv: ['KEYENV_TOKEN']
    env:
      - 'KEYENV_PROJECT=your-project-id'

  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'functions'
      - 'deploy'
      - 'my-function'
      - '--region=us-central1'
      - '--runtime=nodejs20'
      - '--trigger-http'
      - '--env-vars-file=.env.deploy'

availableSecrets:
  secretManager:
    - versionName: projects/$PROJECT_ID/secrets/KEYENV_TOKEN/versions/latest
      env: 'KEYENV_TOKEN'

Gen 2 Functions

For Cloud Functions (2nd gen):

gcloud functions deploy my-function \
  --gen2 \
  --region=us-central1 \
  --runtime=nodejs20 \
  --trigger-http \
  --entry-point=helloWorld \
  --set-secrets="DATABASE_URL=DATABASE_URL:latest"

Multiple Functions

Deploy multiple functions with shared secrets:

#!/bin/bash

FUNCTIONS=("api" "auth" "webhook")
REGION="us-central1"

# Export once
keyenv export -p YOUR_PROJECT_ID -e production --format dotenv > .env.deploy

for func in "${FUNCTIONS[@]}"; do
  echo "Deploying $func..."
  gcloud functions deploy "$func" \
    --region="$REGION" \
    --runtime=nodejs20 \
    --trigger-http \
    --env-vars-file=.env.deploy
done

rm .env.deploy

Best Practices

  1. Use Secret Manager - Better security and automatic rotation
  2. Cache secrets - Use SDK caching for warm function reuse
  3. Grant minimal permissions - Service accounts should only access needed secrets
  4. Use IAM bindings - Control who can invoke functions

Troubleshooting

Secret Access Denied

Grant the function's service account access:

gcloud secrets add-iam-policy-binding SECRET_NAME \
  --member="serviceAccount:[email protected]" \
  --role="roles/secretmanager.secretAccessor"

Function Not Seeing New Secrets

Redeploy the function:

gcloud functions deploy my-function --region=us-central1 ...

Environment Variables Not Loading

Check current configuration:

gcloud functions describe my-function --region=us-central1

On this page