feat(RAILIANCE-WP-0027): prepare operator-only OpenBao access
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02b90-83bf-75c2-81c8-aa705414e4d4
This commit is contained in:
codex 2026-08-23 12:50:23 +02:00
parent 082c76979e
commit 517f68593d
13 changed files with 413 additions and 82 deletions

View file

@ -0,0 +1,153 @@
#!/usr/bin/env bash
set -euo pipefail
ACTION="${1:-status}"
OPENBAO_NAMESPACE="${OPENBAO_NAMESPACE:-openbao}"
KUBECTL="${KUBECTL:-kubectl}"
INGRESS_NAME="${OPENBAO_PUBLIC_INGRESS_NAME:-openbao-ui-gateway}"
SERVICE_NAME="${OPENBAO_UI_SERVICE_NAME:-openbao-ui-gateway}"
DEPLOYMENT_NAME="${OPENBAO_UI_DEPLOYMENT_NAME:-openbao-ui-gateway}"
TUNNEL_NAME="${OPENBAO_UI_TUNNEL_NAME:-openbao-ui-railiance01}"
TUNNEL_URL="${OPENBAO_UI_BASE_URL:-http://127.0.0.1:18200}"
PUBLIC_URL="${OPENBAO_PUBLIC_URL:-https://bao.coulomb.social/}"
EXPECTED_CLUSTER_UID="${RAILIANCE01_CLUSTER_UID:-a553c742-0115-43d4-99a4-a5ca56fe0786}"
PRIVATE_MANIFEST="${OPENBAO_UI_OVERLAY_K8S:-helm/openbao-ui-overlay-k8s.yaml}"
ROLLBACK_MANIFEST="${OPENBAO_PUBLIC_INGRESS_ROLLBACK:-helm/openbao-public-ingress.rollback.yaml}"
MIDDLEWARE_MANIFEST="${OPENBAO_MIDDLEWARE:-helm/openbao-middleware.yaml}"
CONFIRM_RETRACT="RETRACT RMASTER-WP-0020-T09 PUBLIC OPENBAO LISTENER"
CONFIRM_ROLLBACK="ROLLBACK RMASTER-WP-0020-T09 PUBLIC OPENBAO LISTENER"
usage() {
cat <<'USAGE'
Usage: scripts/openbao-public-listener-transition.sh status|dry-run|preflight|apply|rollback
`apply` requires both:
OPENBAO_OPERATOR_LOGIN_VERIFIED=true
OPENBAO_PUBLIC_LISTENER_CONFIRM='RETRACT RMASTER-WP-0020-T09 PUBLIC OPENBAO LISTENER'
`rollback` requires:
OPENBAO_PUBLIC_LISTENER_CONFIRM='ROLLBACK RMASTER-WP-0020-T09 PUBLIC OPENBAO LISTENER'
The script never reads OpenBao credentials or secret values.
USAGE
}
fail() { printf '[ERR] %s\n' "$*" >&2; exit 1; }
ok() { printf '[OK] %s\n' "$*"; }
kube() {
# KUBECTL may include an explicit --kubeconfig argument from Make.
# shellcheck disable=SC2086
$KUBECTL "$@"
}
require_cluster() {
local observed
observed="$(kube get namespace kube-system -o jsonpath='{.metadata.uid}')"
[ "$observed" = "$EXPECTED_CLUSTER_UID" ] ||
fail "cluster identity mismatch: expected $EXPECTED_CLUSTER_UID, observed $observed"
ok "railiance01 cluster identity pinned"
}
require_private_source() {
[ -f "$PRIVATE_MANIFEST" ] || fail "missing private gateway manifest: $PRIVATE_MANIFEST"
if grep -Eq '^kind:[[:space:]]*Ingress[[:space:]]*$' "$PRIVATE_MANIFEST"; then
fail "ordinary gateway manifest still contains an Ingress"
fi
ok "ordinary gateway manifest is Ingress-free"
}
require_private_runtime() {
local service_type service_port
service_type="$(kube -n "$OPENBAO_NAMESPACE" get service "$SERVICE_NAME" -o jsonpath='{.spec.type}')"
service_port="$(kube -n "$OPENBAO_NAMESPACE" get service "$SERVICE_NAME" -o jsonpath='{.spec.ports[?(@.name=="http")].port}')"
[ "$service_type" = "ClusterIP" ] || fail "gateway Service type is $service_type, not ClusterIP"
[ "$service_port" = "8080" ] || fail "gateway Service http port is $service_port, not 8080"
kube -n "$OPENBAO_NAMESPACE" rollout status "deployment/$DEPLOYMENT_NAME" --timeout=30s >/dev/null
ok "gateway Deployment Ready behind ClusterIP"
}
require_tunnel() {
command -v bridge >/dev/null || fail "bridge CLI not found"
command -v jq >/dev/null || fail "jq not found"
local report
if ! report="$(bridge check "$TUNNEL_NAME" --json 2>/dev/null)"; then
fail "named tunnel $TUNNEL_NAME is not lifecycle-healthy"
fi
jq -e --arg name "$TUNNEL_NAME" '.[] | select(.tunnel == $name and .ok == true)' \
<<<"$report" >/dev/null || fail "named tunnel $TUNNEL_NAME did not report ok=true"
curl -fsS --max-time 10 "$TUNNEL_URL/ui/platform-overlay/presets.json" >/dev/null ||
fail "operator UI is not reachable through $TUNNEL_NAME"
ok "named operator tunnel is healthy and reaches the UI"
}
status() {
require_cluster
require_private_source
require_private_runtime
if kube -n "$OPENBAO_NAMESPACE" get ingress "$INGRESS_NAME" >/dev/null 2>&1; then
printf '[INFO] public Ingress is present\n'
else
printf '[INFO] public Ingress is absent\n'
fi
require_tunnel
}
dry_run() {
require_cluster
require_private_source
[ -f "$ROLLBACK_MANIFEST" ] || fail "missing rollback manifest: $ROLLBACK_MANIFEST"
kube apply --server-side --dry-run=server -f "$PRIVATE_MANIFEST" >/dev/null
kube apply --server-side --dry-run=server -f "$ROLLBACK_MANIFEST" >/dev/null
kube -n "$OPENBAO_NAMESPACE" delete ingress "$INGRESS_NAME" --dry-run=server >/dev/null
ok "private apply, rollback apply, and Ingress deletion pass server dry-run"
}
preflight() {
status
kube -n "$OPENBAO_NAMESPACE" get ingress "$INGRESS_NAME" >/dev/null 2>&1 ||
fail "public Ingress is already absent; use status"
ok "public Ingress is present for attended transition"
}
apply_retraction() {
[ "${OPENBAO_OPERATOR_LOGIN_VERIFIED:-false}" = "true" ] ||
fail "attended operator login has not been explicitly verified"
[ "${OPENBAO_PUBLIC_LISTENER_CONFIRM:-}" = "$CONFIRM_RETRACT" ] ||
fail "exact retraction confirmation is missing"
preflight
kube -n "$OPENBAO_NAMESPACE" delete ingress "$INGRESS_NAME" --wait=true
require_private_runtime
require_tunnel
if kube -n "$OPENBAO_NAMESPACE" get ingress "$INGRESS_NAME" >/dev/null 2>&1; then
fail "public Ingress still exists after deletion"
fi
local code
code="$(curl -kLsS --max-time 10 -o /dev/null -w '%{http_code}' "$PUBLIC_URL" || true)"
case "$code" in
2??|3??) fail "public hostname still returns successful HTTP status $code" ;;
esac
ok "public Ingress absent; private gateway and named tunnel remain healthy"
}
rollback() {
[ "${OPENBAO_PUBLIC_LISTENER_CONFIRM:-}" = "$CONFIRM_ROLLBACK" ] ||
fail "exact rollback confirmation is missing"
require_cluster
[ -f "$MIDDLEWARE_MANIFEST" ] || fail "missing middleware manifest: $MIDDLEWARE_MANIFEST"
[ -f "$ROLLBACK_MANIFEST" ] || fail "missing rollback manifest: $ROLLBACK_MANIFEST"
kube apply -f "$MIDDLEWARE_MANIFEST"
kube apply -f "$ROLLBACK_MANIFEST"
kube -n "$OPENBAO_NAMESPACE" get ingress "$INGRESS_NAME" >/dev/null
ok "prior public Ingress restored from rollback-only manifest"
}
case "$ACTION" in
status) status ;;
dry-run) dry_run ;;
preflight) preflight ;;
apply) apply_retraction ;;
rollback) rollback ;;
-h|--help|help) usage ;;
*) usage >&2; exit 2 ;;
esac

View file

@ -11,8 +11,9 @@ usage() {
cat <<'USAGE'
Usage: scripts/openbao-ui-overlay-apply.sh
Builds and applies the OpenBao KeyCape login overlay ConfigMaps and gateway
Deployment/Service/Ingress. Idempotent — safe to run on every openbao-deploy.
Builds and applies the OpenBao KeyCape login overlay ConfigMaps and private
gateway Deployment/ClusterIP Service. Idempotent — safe on every deploy. It
does not create or delete a public Ingress.
Environment:
OPENBAO_NAMESPACE Kubernetes namespace. Default: openbao
@ -71,4 +72,4 @@ $KUBECTL rollout restart deployment/openbao-ui-gateway -n "$OPENBAO_NAMESPACE"
# shellcheck disable=SC2086
$KUBECTL rollout status deployment/openbao-ui-gateway -n "$OPENBAO_NAMESPACE" --timeout=120s
printf '[OK] OpenBao UI overlay applied from %s\n' "$OVERLAY_DIR"
printf '[OK] OpenBao UI overlay applied from %s\n' "$OVERLAY_DIR"

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
BASE_URL="${OPENBAO_UI_BASE_URL:-https://bao.coulomb.social}"
BASE_URL="${OPENBAO_UI_BASE_URL:-http://127.0.0.1:18200}"
OVERLAY_DIR="${OPENBAO_UI_OVERLAY_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/helm/openbao-ui-overlay}"
CHECK_DRIFT="${CHECK_UPSTREAM_DRIFT:-0}"
@ -13,11 +13,11 @@ usage() {
cat <<'USAGE'
Usage: scripts/openbao-verify-login-overlay.sh [--check-upstream-drift]
Verifies the public OpenBao UI serves the KeyCape login overlay assets and
that index.html injection is present.
Verifies the operator-tunneled OpenBao UI serves the KeyCape login overlay
assets and that index.html injection is present.
Environment:
OPENBAO_UI_BASE_URL Public UI base URL. Default: https://bao.coulomb.social
OPENBAO_UI_BASE_URL Operator UI base URL. Default: http://127.0.0.1:18200
OPENBAO_UI_OVERLAY_DIR Local overlay directory for drift fingerprints
CHECK_UPSTREAM_DRIFT Set to 1 to compare live UI hashes with patches/
USAGE
@ -170,4 +170,4 @@ if [ "$CHECK_DRIFT" = "1" ]; then
ok "vault bundle hash matches patches/$version/manifest.sha256 (${expected_vault_path:-$vault_asset})"
fi
printf '\nOpenBao login overlay verification passed for %s\n' "$BASE_URL"
printf '\nOpenBao login overlay verification passed for %s\n' "$BASE_URL"