SDKs & Integrations
Azure Functions
Load KeyEnv secrets in Azure Functions.
Azure Functions Integration
Load secrets from KeyEnv in your Azure Functions.
Prerequisites
- Azure account with a Function App
- Azure CLI installed
- KeyEnv service token with read access
Quick Sync
Sync secrets to Function App settings:
export KEYENV_TOKEN=your-service-token
FUNCTION_APP="my-function-app"
RESOURCE_GROUP="my-resource-group"
# Export and sync
keyenv export -p YOUR_PROJECT_ID -e production --format json | \
jq -r '.secrets[] | "\(.key)=\(.value)"' | \
xargs -I {} az functionapp config appsettings set \
--name "$FUNCTION_APP" \
--resource-group "$RESOURCE_GROUP" \
--settings "{}"Sync Script
Create a reusable sync script:
#!/bin/bash
# sync-to-azure-functions.sh
set -euo pipefail
: "${KEYENV_TOKEN:?KEYENV_TOKEN is required}"
PROJECT_ID="${KEYENV_PROJECT:-YOUR_PROJECT_ID}"
ENVIRONMENT="${KEYENV_ENV:-production}"
FUNCTION_APP="${AZURE_FUNCTION_APP:-my-function-app}"
RESOURCE_GROUP="${AZURE_RESOURCE_GROUP:-my-resource-group}"
echo "Syncing KeyEnv ($ENVIRONMENT) to Azure Functions ($FUNCTION_APP)..."
# Export secrets and sync one by one
keyenv export -p "$PROJECT_ID" -e "$ENVIRONMENT" --format json | \
jq -r '.secrets[] | @base64' | while read -r secret; do
key=$(echo "$secret" | base64 -d | jq -r '.key')
value=$(echo "$secret" | base64 -d | jq -r '.value')
az functionapp config appsettings set \
--name "$FUNCTION_APP" \
--resource-group "$RESOURCE_GROUP" \
--settings "$key=$value" \
--output none
echo "Set: $key"
done
echo "Done!"Using SDK at Runtime
For dynamic secret loading, use the Node.js or Python SDK in your function.
Node.js Function
// src/functions/httpTrigger.ts
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { KeyEnv } from '@keyenv/node';
// Initialize once, outside the handler
const keyenv = new KeyEnv({
token: process.env.KEYENV_TOKEN!,
cacheTtl: 300, // Cache for 5 minutes
});
let secretsLoaded = false;
export async function httpTrigger(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
// Load secrets on first invocation
if (!secretsLoaded) {
await keyenv.loadEnv(process.env.KEYENV_PROJECT!, 'production');
secretsLoaded = true;
}
// Use secrets
const apiKey = process.env.API_KEY;
return {
body: JSON.stringify({ status: 'ok' }),
headers: { 'Content-Type': 'application/json' },
};
}
app.http('httpTrigger', {
methods: ['GET', 'POST'],
handler: httpTrigger,
});Python Function
# function_app.py
import azure.functions as func
import os
from keyenv import KeyEnv
app = func.FunctionApp()
# Initialize client
keyenv = KeyEnv(
token=os.environ["KEYENV_TOKEN"],
cache_ttl=300,
)
secrets_loaded = False
@app.route(route="hello")
def hello(req: func.HttpRequest) -> func.HttpResponse:
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 func.HttpResponse(f"Hello!")CI/CD Integration
GitHub Actions
name: Deploy Azure Functions
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install KeyEnv CLI
run: curl -fsSL https://keyenv.dev/install.sh | bash
- name: Login to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- 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
az functionapp config appsettings set \
--name ${{ vars.AZURE_FUNCTION_APP }} \
--resource-group ${{ vars.AZURE_RESOURCE_GROUP }} \
--settings "$key=$value" \
--output none
done
env:
KEYENV_TOKEN: ${{ secrets.KEYENV_TOKEN }}
- name: Deploy Function App
uses: Azure/functions-action@v1
with:
app-name: ${{ vars.AZURE_FUNCTION_APP }}
package: .Azure DevOps Pipeline
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- script: curl -fsSL https://keyenv.dev/install.sh | bash
displayName: 'Install KeyEnv CLI'
- task: AzureCLI@2
displayName: 'Sync secrets'
inputs:
azureSubscription: 'your-subscription'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
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
az functionapp config appsettings set \
--name $(AZURE_FUNCTION_APP) \
--resource-group $(AZURE_RESOURCE_GROUP) \
--settings "$key=$value" \
--output none
done
env:
KEYENV_TOKEN: $(KEYENV_TOKEN)Using Key Vault (Recommended)
For production, store secrets in Azure Key Vault:
1. Sync to Key Vault
#!/bin/bash
VAULT_NAME="my-key-vault"
keyenv export -p YOUR_PROJECT_ID -e production --format json | \
jq -r '.secrets[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
# Key Vault doesn't allow underscores, replace with dashes
vault_key=$(echo "$key" | tr '_' '-')
az keyvault secret set \
--vault-name "$VAULT_NAME" \
--name "$vault_key" \
--value "$value" \
--output none
echo "Set: $vault_key"
done2. Reference in Function App
# Add Key Vault reference
az functionapp config appsettings set \
--name my-function-app \
--resource-group my-resource-group \
--settings "[email protected](VaultName=my-key-vault;SecretName=DATABASE-URL)"Deployment Slots
Sync different environments to different slots:
# Production slot
keyenv export -p YOUR_PROJECT_ID -e production --format json | \
jq -r '.secrets[]' | sync_to_slot "production"
# Staging slot
keyenv export -p YOUR_PROJECT_ID -e staging --format json | \
jq -r '.secrets[]' | sync_to_slot "staging"
# Helper function
sync_to_slot() {
local slot=$1
while IFS='=' read -r key value; do
if [ "$slot" == "production" ]; then
az functionapp config appsettings set \
--name "$FUNCTION_APP" \
--resource-group "$RESOURCE_GROUP" \
--settings "$key=$value"
else
az functionapp config appsettings set \
--name "$FUNCTION_APP" \
--resource-group "$RESOURCE_GROUP" \
--slot "$slot" \
--settings "$key=$value"
fi
done
}Best Practices
- Use Key Vault for production - Better security and secret rotation
- Enable managed identity - Let Functions access Key Vault without credentials
- Use deployment slots - Test with staging secrets before production
- Cache secrets - Use SDK caching to reduce API calls
Troubleshooting
Settings Not Updating
Restart the Function App:
az functionapp restart \
--name my-function-app \
--resource-group my-resource-groupKey Vault Access Denied
Grant the Function App access:
az keyvault set-policy \
--name my-key-vault \
--object-id $(az functionapp identity show --name my-function-app --resource-group my-resource-group --query principalId -o tsv) \
--secret-permissions get listEnvironment Variables Not Loading
Check current settings:
az functionapp config appsettings list \
--name my-function-app \
--resource-group my-resource-group