audit-core/scripts/openbao-eso-token-apply.sh
tegwick ca6a608b16
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 5s
Add attended runtime-lease remint helper for the expired ESO token
The 768h orphan token in external-secrets/openbao-audit-core-eso-token
expired at 2026-09-14T10:23Z and ClusterSecretStore lookup-self is 403,
so ESO cannot mint database/creds/audit-core-runtime. Recreate the
Kubernetes Secret without last-applied-configuration so the token is
not stored in annotation metadata.

Assistant: grok
Assistant-Session: 01a0a182-bab7-7f11-b32b-d06f3af52082
2026-09-14 23:54:35 +02:00

104 lines
4.1 KiB
Bash
Executable file

#!/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
# Recreate rather than kubectl-apply: apply writes the token into
# last-applied-configuration, which is readable as Secret metadata.
kubectl -n "$SECRET_NS" delete secret "$SECRET_NAME" --ignore-not-found
kubectl -n "$SECRET_NS" create secret generic "$SECRET_NAME" \
--from-literal=token="$child_token"
unset child_token BAO_TOKEN
echo "Secret $SECRET_NS/$SECRET_NAME applied on railiance01."
echo "Next: force-sync ExternalSecret audit-core-database; do not bounce the pod."