#!/usr/bin/env bash # vault-env.sh — fetch secrets from Vault and run a command with them as env vars # # Usage: # vault-env.sh -- docker compose up -d # vault-env.sh kitestacks/authentik -- docker compose -f apps/authentik/docker-compose.yml up -d # vault-env.sh kitestacks/cloudflared -- docker compose -f apps/cloudflared/docker-compose.yml up -d # # Vault secret paths follow the pattern: kitestacks/ # Each key in the secret maps directly to an env var name. # # Example: vault kv put kitestacks/authentik \ # AUTHENTIK_SECRET_KEY="abc123" \ # PG_PASS="postgres-pw" set -euo pipefail VAULT_ADDR="${VAULT_ADDR:-http://127.0.0.1:8200}" VAULT_TOKEN_FILE="${HOME}/.vault-token" if [[ $# -lt 3 ]] || [[ "$2" != "--" ]]; then echo "Usage: vault-env.sh -- " echo "Example: vault-env.sh kitestacks/authentik -- docker compose up -d" exit 1 fi SECRET_PATH="$1" shift 2 # remove path and -- # Check Vault is reachable if ! vault status -address="${VAULT_ADDR}" &>/dev/null; then echo "ERROR: Vault is not reachable at ${VAULT_ADDR}" echo " Start it: cd apps/vault && docker compose up -d" echo " Unseal: VAULT_ADDR=${VAULT_ADDR} vault operator unseal" exit 1 fi # Check we have a token if [[ -z "${VAULT_TOKEN:-}" ]] && [[ ! -f "${VAULT_TOKEN_FILE}" ]]; then echo "ERROR: No VAULT_TOKEN set and no ~/.vault-token file found" echo " Login: vault login -address=${VAULT_ADDR}" exit 1 fi # Fetch the secret as JSON and convert to KEY=VALUE exports SECRET_JSON=$(vault kv get -address="${VAULT_ADDR}" -format=json "secret/${SECRET_PATH}" 2>/dev/null) || { echo "ERROR: Secret not found at secret/${SECRET_PATH}" echo " Create it: vault kv put secret/${SECRET_PATH} KEY=value ..." exit 1 } # Build env from the secret's data map declare -a ENV_ARGS=() while IFS='=' read -r key value; do ENV_ARGS+=("${key}=${value}") done < <(echo "${SECRET_JSON}" | python3 -c " import json, sys data = json.load(sys.stdin) for k, v in data['data']['data'].items(): print(f'{k}={v}') ") # Execute the command with secrets injected as env vars exec env "${ENV_ARGS[@]}" "$@"