Retire static OpenBao ESO token bootstrap (RPF-WP-0045-T06)

The openbao-activity-core store has used OpenBao Kubernetes auth since
2026-09-21 and synced cleanly for more than 24 hours. Remove the
openbao-eso-token-apply script and Makefile target, point the manifest
comments and runbooks at the Kubernetes-auth store, and guard against
reintroducing the script.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 151606@bnt-lap001
Assistant-Session: 3c0a4ad5-bb8b-4bf7-b9f0-fa5f29204e48
This commit is contained in:
tegwick 2026-09-23 17:47:11 +02:00
parent 94b5c45f22
commit b690ce03fa
8 changed files with 26 additions and 114 deletions

View file

@ -10,7 +10,7 @@ export
prod-automation-status refresh-live-images \
dev-up dev-down railiance-up railiance-down \
start-worker start-api start-event-router \
openbao-eso-token-apply agents-list agents-update agents-validate
agents-list agents-update agents-validate
# ── Help ──────────────────────────────────────────────────────────────────────
@ -102,9 +102,6 @@ railiance-up: ## Build image and start full railiance stack (no Elasticsearch)
railiance-down: ## Stop and remove railiance stack containers
docker compose -f docker-compose.railiance.yml down
openbao-eso-token-apply: ## Mint coulombcore OpenBao ESO token for railiance01 activity-core
OPENBAO_TOKEN_FILE="$(HOME)/.local/openbao/platform-admin.token" bash scripts/openbao-eso-token-apply.sh
# ── Local dev processes ───────────────────────────────────────────────────────
start-worker: ## Start Temporal worker (reads env from .env if present)

View file

@ -585,7 +585,7 @@ mount of `~/railiance-platform` on the worker) with `apply: true` and posts
| Retention | newest **3** versions per package (`container`, `pypi`, `npm`, `generic`) |
| Org | `coulomb` |
| Protected | live cluster image tags + Helm values (`--live-images-file` / live scan) |
| Credential | `FORGEJO_TOKEN` in `actcore-runtime-secret` via ExternalSecret `actcore-forgejo-admin` (OpenBao `platform/workloads/forgejo/forgejo-admin` field `API_TOKEN`; `warden route show forgejo-admin-api-token`). ESO token: `scripts/openbao-eso-token-apply.sh` (includes `workload-kv-read-forgejo-admin`). |
| Credential | `FORGEJO_TOKEN` in `actcore-runtime-secret` via ExternalSecret `actcore-forgejo-admin` (OpenBao `platform/workloads/forgejo/forgejo-admin` field `API_TOKEN`; `warden route show forgejo-admin-api-token`). Store: `ClusterSecretStore/openbao-activity-core` on OpenBao Kubernetes auth (RPF-WP-0045); its role policy includes `workload-kv-read-forgejo-admin`. |
| Rollback | restore package versions from Nextcloud `forgejo dump` if a needed tag was removed |
**Enabled 2026-07-21** after dry-run + first apply evidence

View file

@ -1,9 +1,10 @@
# Sync Option A offsite backup credentials into actcore-runtime-secret.
#
# Prereqs on railiance01:
# - ClusterSecretStore openbao-activity-core
# - ESO token includes policy workload-kv-read-railiance-backup-offsite-lane
# (scripts/openbao-eso-token-apply.sh defaults updated in RAILIANCE-WP-0016)
# - ClusterSecretStore openbao-activity-core (railiance-platform addon; OpenBao
# Kubernetes auth via ServiceAccount activity-core/activity-core-eso since
# RPF-WP-0045, 2026-09-21 — no static ESO token)
# - Store role policy includes workload-kv-read-railiance-backup-offsite-lane
#
# OpenBao path: platform/workloads/railiance/backup/offsite-lane
# Fields synced (never AGE_PRIVATE_KEY):

View file

@ -2,11 +2,10 @@
#
# Prereqs on railiance01:
# - External Secrets Operator (namespace external-secrets)
# - ClusterSecretStore openbao-activity-core (railiance-platform addon)
# - Secret external-secrets/openbao-activity-core-eso-token with policies:
# workload-kv-read-issue-core-runtime
# workload-kv-read-forgejo-admin
# (scripts/openbao-eso-token-apply.sh)
# - ClusterSecretStore openbao-activity-core (railiance-platform addon; OpenBao
# Kubernetes auth via ServiceAccount activity-core/activity-core-eso since
# RPF-WP-0045, 2026-09-21 — no static ESO token)
# - Store role policy includes workload-kv-read-forgejo-admin
#
# OpenBao path: platform/workloads/forgejo/forgejo-admin
# property: API_TOKEN → secret key FORGEJO_TOKEN

View file

@ -2,8 +2,9 @@
#
# Prereqs on railiance01:
# - External Secrets Operator (namespace external-secrets)
# - ClusterSecretStore openbao-activity-core (railiance-platform addon)
# - Secret external-secrets/openbao-activity-core-eso-token (scripts/openbao-eso-token-apply.sh)
# - ClusterSecretStore openbao-activity-core (railiance-platform addon; OpenBao
# Kubernetes auth via ServiceAccount activity-core/activity-core-eso since
# RPF-WP-0045, 2026-09-21 — no static ESO token)
#
# OpenBao path: platform/workloads/issue-core/issue-core/issue-core-runtime
# property: ISSUE_CORE_API_KEY (shared with issue-core ingestion)

View file

@ -57,9 +57,12 @@ ACTIVITY-WP-0039.
| `actcore-backup-offsite` | `platform/workloads/railiance/backup/offsite-lane` | `NC_WEBDAV_TOKEN`, `NC_WEBDAV_URL` |
| `llm-connect-provider-secrets` | `platform/workloads/activity-core/llm-connect/llm-connect-provider-secrets` | `OPENROUTER_API_KEY` |
Prereqs: `ClusterSecretStore/openbao-activity-core` and ESO token bootstrap with
the four exact-path read policies (`OPENBAO_TOKEN_FILE=~/.local/openbao/platform-admin.token
./scripts/openbao-eso-token-apply.sh`). The llm-connect `ExternalSecret` remains
Prereqs: `ClusterSecretStore/openbao-activity-core`, owned by railiance-platform.
Since RPF-WP-0045 (2026-09-21) it uses OpenBao Kubernetes auth through the
`activity-core/activity-core-eso` ServiceAccount, with a 15-minute token and a
role policy limited to exact paths. The static-token bootstrap
(`scripts/openbao-eso-token-apply.sh`) is retired; do not recreate a static
`openbao-activity-core-eso-token`. The llm-connect `ExternalSecret` remains
owned by the llm-connect deployment package rather than activity-core.
Roll back to audit mode by setting `ISSUE_SINK_TYPE=null` and restarting worker
and event-router deployments. See `docs/issue-core-emission-boundary.md`.
@ -97,8 +100,7 @@ ssh railiance01
cd ~/activity-core
bash k8s/railiance/bootstrap-secrets.sh
kubectl apply -f k8s/railiance/10-infrastructure.yaml
# Bootstrap OpenBao ESO token + apply ExternalSecrets (once per cluster):
OPENBAO_TOKEN_FILE=~/.local/openbao/platform-admin.token ./scripts/openbao-eso-token-apply.sh
# Apply the store (railiance-platform addon, Kubernetes auth) + ExternalSecrets:
kubectl apply -f ~/railiance-platform/argocd/platform-addons/openbao-secretstore/openbao-activity-core.clustersecretstore.yaml
kubectl apply -f k8s/railiance/15-externalsecret-issue-core.yaml
kubectl apply -f k8s/railiance/15-externalsecret-forgejo-admin.yaml

View file

@ -1,80 +0,0 @@
#!/usr/bin/env bash
# Mint a read-limited OpenBao token on coulombcore (bao.coulomb.social) and store
# it on railiance01 for ClusterSecretStore openbao-activity-core / ExternalSecrets:
# - actcore-issue-core-runtime (ISSUE_CORE_API_KEY)
# - actcore-forgejo-admin (FORGEJO_TOKEN for package prune)
# - actcore-backup-offsite (NC_WEBDAV_* for Option A backups)
# - llm-connect-provider-secrets (OPENROUTER_API_KEY for llm-connect)
#
# Default policies (already present in OpenBao; files re-written when present):
# workload-kv-read-issue-core-runtime
# workload-kv-read-forgejo-admin
# workload-kv-read-railiance-backup-offsite-lane
# workload-kv-read-llm-connect-provider-secrets
set -euo pipefail
# Space-separated policy names. Override with OPENBAO_ACTIVITY_CORE_POLICIES.
DEFAULT_POLICIES="workload-kv-read-issue-core-runtime workload-kv-read-forgejo-admin workload-kv-read-railiance-backup-offsite-lane workload-kv-read-llm-connect-provider-secrets"
POLICIES="${OPENBAO_ACTIVITY_CORE_POLICIES:-$DEFAULT_POLICIES}"
POLICY_DIR="${OPENBAO_POLICY_DIR:-$HOME/railiance-platform/openbao/policies}"
BAO_ADDR="${BAO_ADDR:-https://bao.coulomb.social}"
RAILIANCE01_KUBECONFIG="${RAILIANCE01_KUBECONFIG:-$HOME/.kube/config-hosteurope}"
SECRET_NAME="${OPENBAO_ACTIVITY_CORE_ESO_SECRET:-openbao-activity-core-eso-token}"
SECRET_NS="${OPENBAO_ACTIVITY_CORE_ESO_NAMESPACE:-external-secrets}"
if ! command -v bao >/dev/null 2>&1; then
echo "ERROR: bao CLI not found" >&2
exit 1
fi
echo "OpenBao addr: $BAO_ADDR"
echo "Policies: $POLICIES"
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 (coulombcore / bao.coulomb.social): " 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
policy_flags=()
for policy in $POLICIES; do
policy_file="$POLICY_DIR/${policy}.hcl"
if [[ -f "$policy_file" ]]; then
bao policy write "$policy" "$policy_file"
else
echo "WARN: policy file missing ($policy_file); using existing OpenBao policy '$policy'" >&2
fi
policy_flags+=(-policy="$policy")
done
token_json="$(bao token create "${policy_flags[@]}" \
-display-name="eso-activity-core-runtime" \
-period=720h \
-format=json)"
token="$(python3 -c "import json,sys; print(json.load(sys.stdin)['auth']['client_token'])" <<<"$token_json")"
KUBECONFIG="$RAILIANCE01_KUBECONFIG" kubectl create namespace "$SECRET_NS" --dry-run=client -o yaml | KUBECONFIG="$RAILIANCE01_KUBECONFIG" kubectl apply -f -
KUBECONFIG="$RAILIANCE01_KUBECONFIG" kubectl create secret generic "$SECRET_NAME" \
--namespace "$SECRET_NS" \
--from-literal=token="$token" \
--dry-run=client -o yaml | KUBECONFIG="$RAILIANCE01_KUBECONFIG" kubectl apply -f -
unset BAO_TOKEN token token_json
echo "ok: applied $SECRET_NS/$SECRET_NAME on railiance01 (token not printed)"
echo "ok: policies attached: $POLICIES"

View file

@ -4,20 +4,12 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_activity_core_eso_token_covers_every_declared_runtime_lane():
script = (ROOT / "scripts" / "openbao-eso-token-apply.sh").read_text(encoding="utf-8")
required_policies = {
"workload-kv-read-issue-core-runtime",
"workload-kv-read-forgejo-admin",
"workload-kv-read-railiance-backup-offsite-lane",
"workload-kv-read-llm-connect-provider-secrets",
}
default_line = next(
line for line in script.splitlines() if line.startswith("DEFAULT_POLICIES=")
)
for policy in required_policies:
assert policy in default_line
def test_static_eso_token_bootstrap_stays_retired():
# RPF-WP-0045 moved the store to OpenBao Kubernetes auth; a static token
# would expire again and must not be reintroduced.
assert not (ROOT / "scripts" / "openbao-eso-token-apply.sh").exists()
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
assert "openbao-eso-token-apply" not in makefile
def test_railiance_runbook_applies_and_waits_for_llm_connect_external_secret():