fix(knoe-users): keytab reliability + mode-aware next steps + Gitea auto-token

Keytab export (silent failure bug):
- Always delete+recreate the postgres SPN with fresh random key; old key gone
  after EmptyDir wipe; kadmin.local -q exits 0 even on error so -norandkey
  silently failed
- Clean /tmp/pg.keytab before ktadd; verify non-empty with [ -s ] before
  proceeding; die loudly if keytab not written
- Fix base64 pipeline: set -o pipefail inside sh -c so base64 failure is not
  masked by tr exit code

Next steps:
- Suppress myrddin.prole.org Samba trust step in k3d mode (no AD server)
- Remove Grafana auth.proxy reminder (configured by Helm values already)

Gitea admin token:
- Auto-generate via kubectl exec into running Gitea pod before falling back to
  manual warning; persist as gitea-admin-token secret for future re-runs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chrisfu 2026-05-03 16:34:03 -07:00
parent 9d7ef668b1
commit 30c7bc88fd

View File

@ -370,23 +370,30 @@ initialize() {
fi
fi
# 6. Create postgres service principal + export keytab
# 6. Create postgres service principal + export keytab.
# Always (re)create the SPN with a fresh random key — the old key is gone when
# the KDC pod restarts on ephemeral storage. kadmin.local -q exits 0 even on
# failure, so we verify success by checking the keytab file was written.
local pg_spn="postgres/knoe-db-rw.${KNOE_DB_NAMESPACE}.svc.cluster.local@${PROLE_KDC_REALM}"
if kdc_principal_exists "$kdc_pod" "$pg_spn"; then
log "${pg_spn} already exists"
else
log "Creating service principal ${pg_spn} ..."
kdc_addprinc_randkey "$kdc_pod" "$pg_spn"
fi
log "Creating/refreshing service principal ${pg_spn} ..."
kubectl -n "$KNOE_KDC_NAMESPACE" exec "$kdc_pod" -c kdc -- \
sh -c "kadmin.local -q 'delprinc -force ${pg_spn}' 2>/dev/null; kadmin.local -q 'addprinc -randkey ${pg_spn}'"
log "Exporting keytab for ${pg_spn} ..."
kubectl -n "$KNOE_KDC_NAMESPACE" exec "$kdc_pod" -c kdc -- \
kadmin.local -q "ktadd -k /tmp/pg.keytab -norandkey ${pg_spn}" >/dev/null
sh -c "rm -f /tmp/pg.keytab; kadmin.local -q 'ktadd -k /tmp/pg.keytab ${pg_spn}'"
# kadmin.local -q exits 0 even on failure — verify the file was actually written
kubectl -n "$KNOE_KDC_NAMESPACE" exec "$kdc_pod" -c kdc -- \
sh -c '[ -s /tmp/pg.keytab ]' \
|| die "Keytab export failed for ${pg_spn} — /tmp/pg.keytab is missing or empty. Check KDC logs."
log "Storing keytab in Secret knoe-db-pg-keytab ..."
local keytab_b64
# Use pipefail so a base64 failure propagates through the tr pipeline
keytab_b64=$(kubectl -n "$KNOE_KDC_NAMESPACE" exec "$kdc_pod" -c kdc -- \
sh -c 'base64 /tmp/pg.keytab | tr -d "\\n"')
sh -c 'set -o pipefail; base64 /tmp/pg.keytab | tr -d "\n"')
[[ -n "$keytab_b64" ]] || die "base64 encoding of keytab produced empty output."
# Write secret into the DB namespace where CNPG mounts it
kubectl -n "$KNOE_DB_NAMESPACE" create secret generic knoe-db-pg-keytab \
--from-literal=pg.keytab="$(printf '%s' "$keytab_b64" | b64_decode)" \
@ -499,10 +506,13 @@ SQL
log "=== Initialization complete ==="
log ""
log "Next steps:"
log " 1. On myrddin.prole.org: add krbtgt/PROLE.LOCAL@PROLE.ORG trust principal"
log " (samba-tool domain trust or equivalent, using trust_shared_password from knoe-kdc-secrets)"
log " 2. Confirm Grafana auth.proxy configured with: headers = Role:X-Knoe-Groups"
log " 3. After admin logs in to Gitea/GitLab for the first time, re-run: $0 initialize"
if [[ "$KNOE_DEPLOYMENT_MODE" != "k3d" ]]; then
log " 1. On myrddin.prole.org: add krbtgt/PROLE.LOCAL@PROLE.ORG trust principal"
log " (samba-tool domain trust, using trust_shared_password from knoe-kdc-secrets)"
log " 2. After admin logs in to Gitea/GitLab for the first time, re-run: $0 initialize"
else
log " 1. After admin logs in to Gitea/GitLab for the first time, re-run: $0 initialize"
fi
}
# ── knoe.user schema + user provisioning ──────────────────────────────────
@ -621,6 +631,29 @@ promote_gitea_admin() {
token=$(kubectl -n "$GITEA_NAMESPACE" get secret gitea-admin-token \
-o jsonpath='{.data.token}' 2>/dev/null | b64_decode || true)
fi
# Auto-generate an admin token by exec-ing into the Gitea pod (Gitea ≥ 1.17)
if [[ -z "$token" ]]; then
local _gitea_pod
_gitea_pod=$(kubectl -n "$GITEA_NAMESPACE" get pods \
-l "app.kubernetes.io/name=gitea" \
--field-selector=status.phase=Running \
-o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
if [[ -n "$_gitea_pod" ]]; then
log "Gitea: generating admin token via kubectl exec into ${_gitea_pod} ..."
token=$(kubectl -n "$GITEA_NAMESPACE" exec "$_gitea_pod" -- \
gitea admin user generate-access-token \
--username admin --token-name knoe-installer \
--scopes "write:admin,read:user" --raw 2>/dev/null | tail -1 || true)
if [[ -n "$token" ]]; then
# Persist so subsequent calls (and future re-runs) reuse the same token
local _tok_b64; _tok_b64=$(printf '%s' "$token" | base64 | tr -d '\n')
kubectl -n "$GITEA_NAMESPACE" create secret generic gitea-admin-token \
--from-literal=token="$token" \
--dry-run=client -o yaml | kubectl apply -f - >/dev/null 2>&1 || true
log "Gitea: admin token generated and stored in gitea-admin-token secret"
fi
fi
fi
if [[ -z "$token" ]]; then
warn "No GITEA_ADMIN_TOKEN available — skipping Gitea admin promotion"
warn " Manually: curl -X PATCH https://${GITEA_HOST}/api/v1/admin/users/${KNOE_ADMIN_PRINCIPAL} \\"