Files
Homelabv4/scripts/vault-init-and-store.sh
T
2026-03-09 20:21:35 -05:00

116 lines
4.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 youre comfortable:"
echo " kubectl -n ${VAULT_NS} delete secret ${SECRET_NAME}"