#!/usr/bin/env bash set -euo pipefail VAULT_NS="${VAULT_NS:-vault}" SECRET_NAME="${SECRET_NAME:-vault-init-keys}" KV_MOUNT="${KV_MOUNT:-secret}" JOB_NS_FOR_ROLE="${JOB_NS_FOR_ROLE:-auth-proxy}" JOB_SA_FOR_ROLE="${JOB_SA_FOR_ROLE:-oauth2-bootstrap}" POLICY_NAME="${POLICY_NAME:-oauth2-writer}" ROLE_NAME="${ROLE_NAME:-eso-writer}" # --- prereqs --- command -v kubectl >/dev/null || { echo "kubectl not found"; exit 1; } command -v vault >/dev/null || { echo "vault CLI not found"; exit 1; } command -v jq >/dev/null || { echo "jq not found"; exit 1; } # --- port-forward Vault locally --- echo "==> Port-forwarding Vault service (ctrl-c in another terminal to stop when done)" kubectl -n "$VAULT_NS" port-forward svc/vault 8200:8200 >/dev/null 2>&1 & pf_pid=$! trap 'kill $pf_pid >/dev/null 2>&1 || true' EXIT sleep 2 export VAULT_ADDR="http://127.0.0.1:8200" # --- check init/seal status --- status_json="$(vault status -format=json || true)" initialized="$(jq -r '.initialized // empty' <<<"$status_json")" sealed="$(jq -r '.sealed // empty' <<<"$status_json")" root_token="" unseal_key="" # pull existing secret if present if kubectl -n "$VAULT_NS" get secret "$SECRET_NAME" >/dev/null 2>&1; then root_token="$(kubectl -n "$VAULT_NS" get secret "$SECRET_NAME" -o jsonpath='{.data.VAULT_ROOT_TOKEN}' | base64 -d || true)" unseal_key="$(kubectl -n "$VAULT_NS" get secret "$SECRET_NAME" -o jsonpath='{.data.VAULT_UNSEAL_KEY}' | base64 -d || true)" fi # initialize if needed if [[ "$initialized" != "true" ]]; then echo "==> Vault not initialized; initializing..." init_json="$(vault operator init -key-shares=1 -key-threshold=1 -format=json)" root_token="$(jq -r .root_token <<<"$init_json")" unseal_key="$(jq -r '.unseal_keys_b64[0]' <<<"$init_json")" sealed="true" echo "==> Storing root token & unseal key in Secret ${VAULT_NS}/${SECRET_NAME}" kubectl -n "$VAULT_NS" create secret generic "$SECRET_NAME" \ --from-literal=VAULT_ROOT_TOKEN="$root_token" \ --from-literal=VAULT_UNSEAL_KEY="$unseal_key" \ --dry-run=client -o yaml | kubectl apply -f - else echo "==> Vault already initialized." fi # unseal if needed if [[ "$sealed" == "true" ]]; then [[ -n "$unseal_key" ]] || { echo "ERROR: sealed and no unseal key available"; exit 1; } echo "==> Unsealing..." vault operator unseal "$unseal_key" >/dev/null fi # login if [[ -z "$root_token" ]]; then echo "==> Reading root token from Secret..." root_token="$(kubectl -n "$VAULT_NS" get secret "$SECRET_NAME" -o jsonpath='{.data.VAULT_ROOT_TOKEN}' | base64 -d)" fi vault login "$root_token" >/dev/null # ensure KV v2 enabled if ! vault secrets list -format=json | jq -e "has(\"${KV_MOUNT}/\")" >/dev/null; then echo "==> Enabling KV v2 at ${KV_MOUNT}/" vault secrets enable -path="$KV_MOUNT" -version=2 kv >/dev/null fi # configure Kubernetes auth with a reviewer token from a local SA echo "==> Ensuring reviewer SA + binding" kubectl -n "$VAULT_NS" get sa vault-auth >/dev/null 2>&1 || kubectl -n "$VAULT_NS" create sa vault-auth kubectl get clusterrolebinding vault-auth-delegator >/dev/null 2>&1 || \ kubectl create clusterrolebinding vault-auth-delegator \ --clusterrole=system:auth-delegator \ --serviceaccount="${VAULT_NS}:vault-auth" reviewer_jwt="$(kubectl -n "$VAULT_NS" create token vault-auth)" kube_ca="$(kubectl -n kube-system get configmap kube-root-ca.crt -o jsonpath='{.data.ca\.crt}')" kube_host="https://kubernetes.default.svc:443" vault auth enable kubernetes >/dev/null 2>&1 || true vault write auth/kubernetes/config \ token_reviewer_jwt="$reviewer_jwt" \ kubernetes_host="$kube_host" \ kubernetes_ca_cert="$kube_ca" >/dev/null # policy + role for ESO/oauth2 job vault policy write "$POLICY_NAME" - >/dev/null <<'HCL' path "secret/data/*" { capabilities = ["create", "update", "read", "list"] } path "secret/metadata/*" { capabilities = ["create", "update", "read", "list"] } HCL vault write auth/kubernetes/role/${ROLE_NAME} \ bound_service_account_names="${JOB_SA_FOR_ROLE},external-secrets" \ bound_service_account_namespaces="${JOB_NS_FOR_ROLE},external-secrets" \ policies="${POLICY_NAME}" \ ttl="24h" >/dev/null echo "==> Done." echo "K8s Secret with init creds: ${VAULT_NS}/${SECRET_NAME}" echo "IMPORTANT: back these up securely and delete the Secret when you’re comfortable:" echo " kubectl -n ${VAULT_NS} delete secret ${SECRET_NAME}"