#!/usr/bin/env bash # Mint a read-limited OpenBao token and store it on railiance01 for # ClusterSecretStore openbao-audit-core and the VaultDynamicSecret generators. # # Policy: railiance-platform/openbao/policies/external-secrets-audit-core.hcl # # Does not print secret values. Requires an attended operator OpenBao token # that can write policies and create child tokens. set -euo pipefail DEFAULT_POLICIES="external-secrets-audit-core" POLICIES="${OPENBAO_AUDIT_CORE_POLICIES:-$DEFAULT_POLICIES}" POLICY_DIR="${OPENBAO_POLICY_DIR:-$HOME/railiance-platform/openbao/policies}" BAO_ADDR="${BAO_ADDR:-https://bao.coulomb.social}" # ~/.kube/config-hosteurope currently targets 16443 (coulombcore). railiance01 # is the k3s-api-railiance01 tunnel on 16444. Always pass this explicitly # unless you have a dedicated railiance01 kubeconfig. RAILIANCE01_KUBECONFIG="${RAILIANCE01_KUBECONFIG:-}" SECRET_NAME="${OPENBAO_AUDIT_CORE_ESO_SECRET:-openbao-audit-core-eso-token}" SECRET_NS="${OPENBAO_AUDIT_CORE_ESO_NAMESPACE:-external-secrets}" TTL="${OPENBAO_AUDIT_CORE_ESO_TTL:-768h}" if ! command -v bao >/dev/null 2>&1; then echo "ERROR: bao CLI not found" >&2 exit 1 fi if ! command -v kubectl >/dev/null 2>&1; then echo "ERROR: kubectl not found" >&2 exit 1 fi if [[ -z "$RAILIANCE01_KUBECONFIG" ]]; then echo "ERROR: set RAILIANCE01_KUBECONFIG to a kubeconfig whose server is https://127.0.0.1:16444 (railiance01)." >&2 echo "Do not use ~/.kube/config or ~/.kube/config-hosteurope — those currently hit 16443 (coulombcore)." >&2 exit 1 fi echo "OpenBao addr: $BAO_ADDR" echo "Policies: $POLICIES" echo "K8s secret: $SECRET_NS/$SECRET_NAME (railiance01)" echo "Kubeconfig: $RAILIANCE01_KUBECONFIG" if [[ -n "${BAO_TOKEN:-}" ]]; then : elif [[ -n "${OPENBAO_TOKEN_FILE:-}" && -f "${OPENBAO_TOKEN_FILE}" ]]; then BAO_TOKEN="$(head -n 1 "${OPENBAO_TOKEN_FILE}")" else read -r -s -p "OpenBao operator token: " BAO_TOKEN echo >&2 fi if [[ -z "${BAO_TOKEN:-}" ]]; then echo "ERROR: empty OpenBao token" >&2 exit 1 fi export BAO_ADDR BAO_TOKEN health="$(curl -fsS "$BAO_ADDR/v1/sys/health")" if echo "$health" | grep -q '"sealed":true'; then echo "ERROR: OpenBao at $BAO_ADDR reports sealed" >&2 exit 1 fi for policy in $POLICIES; do policy_file="$POLICY_DIR/${policy}.hcl" if [[ -f "$policy_file" ]]; then bao policy write "$policy" "$policy_file" echo "policy written: $policy" else echo "WARN: policy file missing ($policy_file); using existing OpenBao policy '$policy'" >&2 fi done # Child token: renewable, orphan so operator logout does not revoke delivery. # shellcheck disable=SC2086 token_json="$(bao token create -policy="$(echo $POLICIES | tr ' ' ',')" -ttl="$TTL" -renewable=true -orphan -format=json)" child_token="$(printf '%s' "$token_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["auth"]["client_token"])')" if [[ -z "$child_token" || ${#child_token} -lt 8 ]]; then echo "ERROR: failed to mint child token" >&2 exit 1 fi echo "minted child token length=${#child_token} (value not printed)" export KUBECONFIG="$RAILIANCE01_KUBECONFIG" # Fail closed if this kubeconfig is not railiance01. coulombcore has # core-hub-staging and no audit-core namespace. if ! kubectl get ns audit-core >/dev/null 2>&1; then echo "ERROR: kubeconfig does not see namespace audit-core; refusing to write the ESO token." >&2 echo "Expected railiance01 via https://127.0.0.1:16444 (ops-bridge tunnel k3s-api-railiance01)." >&2 exit 1 fi if kubectl get ns core-hub-staging >/dev/null 2>&1; then echo "ERROR: kubeconfig looks like coulombcore (namespace core-hub-staging present)." >&2 exit 1 fi kubectl -n "$SECRET_NS" create secret generic "$SECRET_NAME" \ --from-literal=token="$child_token" \ --dry-run=client -o yaml | kubectl apply -f - unset child_token BAO_TOKEN echo "Secret $SECRET_NS/$SECRET_NAME applied on railiance01." echo "Next: apply ClusterSecretStore openbao-audit-core, then deploy/."