#!/usr/bin/env sh set -eu secret_path="kv/atlas/hermes/developer-jenkins" jwt_file="${VAULT_K8S_JWT_FILE:-/var/run/secrets/kubernetes.io/serviceaccount/token}" vault_role="${VAULT_K8S_ROLE:-vault-admin}" log() { printf '[hermes-jenkins-token] %s\n' "$*" >&2; } retry_command() { attempt=1 while [ "${attempt}" -le 5 ]; do set +e command_output="$("$@" 2>&1)" command_status=$? set -e if [ "${command_status}" -eq 0 ]; then printf '%s' "${command_output}" return 0 fi if [ "${attempt}" -lt 5 ]; then sleep "${attempt}" fi attempt=$((attempt + 1)) done return "${command_status}" } ensure_token() { if [ -n "${VAULT_TOKEN:-}" ]; then return fi jwt="$(cat "${jwt_file}")" VAULT_TOKEN="$(retry_command vault write -field=token \ auth/kubernetes/login role="${vault_role}" jwt="${jwt}")" || { log "Vault Kubernetes login failed after retries" exit 1 } unset jwt if [ -z "${VAULT_TOKEN}" ]; then log "Vault Kubernetes login returned an empty token" exit 1 fi export VAULT_TOKEN } # Return 0 when the field exists, 10 when the secret is absent, 11 when the # secret exists without the field, and 12 for a persistent read error. read_build_token() { attempt=1 while [ "${attempt}" -le 5 ]; do set +e secret_error="$(vault kv get "${secret_path}" 2>&1 >/dev/null)" secret_status=$? set -e if [ "${secret_status}" -eq 0 ]; then set +e build_token="$(vault kv get -field=build_token "${secret_path}" 2>&1)" field_status=$? set -e if [ "${field_status}" -eq 0 ] && [ -n "${build_token}" ]; then return 0 fi if printf '%s' "${build_token}" | grep -q 'No value found'; then unset build_token return 11 fi if [ "${field_status}" -eq 0 ]; then unset build_token return 11 fi elif printf '%s' "${secret_error}" | grep -Eq 'Code: 404|No value found at'; then return 10 fi if [ "${attempt}" -lt 5 ]; then sleep "${attempt}" fi attempt=$((attempt + 1)) done unset secret_error build_token return 12 } ensure_token if read_build_token; then read_status=0 else read_status=$? fi case "${read_status}" in 0) unset build_token log "job-scoped token already present; no write performed" exit 0 ;; 11) log "secret exists without build_token; refusing to overwrite existing fields" exit 1 ;; 12) log "secret read failed after retries; refusing to seed" exit 1 ;; 10) ;; *) log "unexpected secret read state ${read_status}" exit 1 ;; esac new_token="$(retry_command vault write -field=random_bytes \ sys/tools/random/32 format=hex)" || { log "Vault random token generation failed after retries" exit 1 } if [ -z "${new_token}" ]; then log "Vault returned an empty random token" exit 1 fi set +e create_error="$(printf '%s' "${new_token}" | \ vault kv put -cas=0 "${secret_path}" build_token=- 2>&1 >/dev/null)" create_status=$? set -e unset new_token if [ "${create_status}" -eq 0 ]; then log "job-scoped token created with KV-v2 CAS create-only semantics" exit 0 fi # A simultaneous revisioned Job/Cron run may win the create. Accept that race # only if a fresh retried read finds the complete field; never rotate it. if printf '%s' "${create_error}" | grep -qi 'check-and-set'; then unset create_error if read_build_token; then read_status=0 else read_status=$? fi if [ "${read_status}" -eq 0 ]; then unset build_token log "another seeder won CAS; existing token preserved" exit 0 fi log "CAS race did not produce a readable build_token; refusing to continue" exit 1 fi unset create_error log "KV-v2 CAS create failed; refusing to retry a write" exit 1