#!/usr/bin/env bash # Minimal Vault helper for CI steps (AppRole login + KVv2 reads). # Requires: curl, sed. Uses VAULT_ADDR, VAULT_ROLE_ID, VAULT_SECRET_ID from env. set -euo pipefail : "${VAULT_ADDR:?missing VAULT_ADDR}" VAULT_TOKEN_FILE="${VAULT_TOKEN_FILE:-.vault_token}" log(){ printf '[vlt] %s\n' "$*" >&2; } login() { : "${VAULT_ROLE_ID:?missing VAULT_ROLE_ID}" : "${VAULT_SECRET_ID:?missing VAULT_SECRET_ID}" log "login approle" resp="$(curl -sfS -X POST -H 'Content-Type: application/json' \ --connect-timeout 5 --max-time 20 \ -d "{\"role_id\":\"${VAULT_ROLE_ID}\",\"secret_id\":\"${VAULT_SECRET_ID}\"}" \ "${VAULT_ADDR%/}/v1/auth/approle/login")" token="$(printf '%s' "$resp" | sed -n 's/.*"client_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')" [ -n "$token" ] || { echo "login failed" >&2; exit 1; } printf '%s' "$token" > "$VAULT_TOKEN_FILE" } ensure_token() { if [ -s "$VAULT_TOKEN_FILE" ]; then VAULT_TOKEN="$(cat "$VAULT_TOKEN_FILE")" else login VAULT_TOKEN="$(cat "$VAULT_TOKEN_FILE")" fi } # kv_get (KV v2) kv_get() { mount="$1"; path="$2"; field="$3" ensure_token url="${VAULT_ADDR%/}/v1/${mount}/data/${path}" resp="$(curl -sfS --connect-timeout 5 --max-time 20 -H "X-Vault-Token: ${VAULT_TOKEN}" "$url")" RESP="$resp" python3 - "$field" <<'PY' import json, os, sys field = sys.argv[1] resp = os.environ.get("RESP", "") try: data = json.loads(resp) value = data["data"]["data"][field] except (KeyError, TypeError, json.JSONDecodeError): print(f"field not found or invalid JSON", file=sys.stderr) sys.exit(2) sys.stdout.write(value) PY } # kv_to_file [mode] kv_to_file() { mount="$1"; path="$2"; field="$3"; dest="$4"; mode="${5:-600}" tmp="$(mktemp)" kv_get "$mount" "$path" "$field" > "$tmp" install -m "$mode" "$tmp" "$dest" rm -f "$tmp" log "wrote $dest" } case "${1:-}" in login) shift; login "$@";; kv_get) shift; kv_get "$@";; kv_to_file) shift; kv_to_file "$@";; *) echo "usage: vlt {login|kv_get|kv_to_file} ..." >&2; exit 64;; esac