Mermaid 10.7.0 chokes on bare <placeholder> in message text, parsing it as HTML. Swap to square brackets in the cross-realm §4.3 sequence diagram and the Gitea SPNEGO §5 diagram: <svc-host>, <SPNEGO> (§4.3) <blob> (§5) Matches the same fix landed in knoe-db's docs/knoe-auth.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
15 KiB
knoe-auth — prole.org deployment overlay
Customer-specific overlay of the canonical architecture documented in
~/dev/knoe-db/docs/knoe-auth.md. Read the canonical doc first for components, flows, and intent. This file documents what's specific to theprole.orghomelab deployment — hostnames, IdP wiring, Kerberos realm names, cross-realm trust setup, current state of each integration.Filed 2026-05-11. Related:
db-access.md,knoe-auth-phase-2.md,oidc-setup.md,local-dev-knoe-auth.md.
1. Identity sources (what's authoritative)
The prole deployment has two upstream identity layers, each authoritative for a different population:
| IdP | Authoritative for | Realm / Domain |
|---|---|---|
| Samba AD on myrddin | Homelab humans + workstation logins | Kerberos realm PROLE.ORG; SMB workgroup PROLE |
| Google Workspace (knoey.com) | Engineers, OIDC sign-ins, email-based identity | @knoey.com |
Both feed into knoe-auth as upstream IdPs:
- Samba AD via Kerberos cross-realm trust (KNOE.LOCAL ↔ PROLE.ORG)
- Google Workspace via OIDC (knoe-auth registers as a Google OAuth client)
A single human (chrisfu, ron, …) typically has both:
chrisfu@PROLE.ORG (workstation Kerberos identity) and
chrisfu@knoey.com (Google Workspace / OIDC identity). The
preferred_username claim canonicalizes them to the same short-name
(chrisfu) so downstream services see one identity.
2. Deployments
Two clusters in the prole homelab, plus the managed GKE deployment for production:
| Cluster | Where | Role | knoe-auth URL |
|---|---|---|---|
k3s (prole-service-cluster) |
myrddin + merlin + gandalf | Homelab production — Gitea, Supabase, OpenBao, Grafana, Garage | https://auth.prole.org (planned) / http://knoe-auth.knoe-system.svc.cluster.local:8080 (in-cluster) |
k3d (k3d-knoe) |
Engineer laptop | Dev loop — knoe-auth Phase 3 shipped | http://localhost:8090 (host port-forward) |
GKE (knoe-dev-0 + knoe-dev-cnpg-0) |
plenary-truck-485623-p7 |
Production OIDC issuer for the broader knoe.dev platform |
https://api.knoe.dev/auth |
A workstation in the prole homelab typically uses the GKE-hosted issuer for OIDC (because that's where Google Workspace OAuth client registration lives) and the k3s in-cluster KDC for Kerberos (because that's where the Samba AD trust lives). Both are addressable externally via their respective ingresses.
3. Hostname map
| Hostname | Resolves to | What lives there |
|---|---|---|
myrddin.prole.org |
LAN IP | Samba AD DC, k3s server node, Kerberos KDC for PROLE.ORG |
merlin.prole.org, gandalf.prole.org |
LAN IPs | k3s agent nodes |
morgana.prole.org, zinfandel.prole.org |
LAN IPs | Engineer workstations |
git.prole.org |
k3s Traefik | Gitea + SPNEGO proxy |
db.prole.org |
k3s Traefik | Supabase Studio (current: Google OAuth via oauth2-proxy) |
auth.prole.org |
k3s Traefik (planned) | knoe-auth OIDC issuer (homelab path) |
svc.prole.org |
k3s Traefik | Kong API gateway for internal services |
api.knoe.dev |
GKE GCE LB | knoe-auth OIDC issuer (production path) |
db.knoe.dev |
GKE GCE LB (planned) | Supabase Studio + knoe-auth OIDC (per per-user-supabase-workspace.md) |
db.0.knoe.dev |
GKE GCE LB | Supabase Studio (current; Google OAuth via oauth2-proxy) — to be aliased + deprecated when db.knoe.dev lands |
pg.0.knoe.dev |
GKE TCP LB | CNPG external endpoint (port 5432) |
4. Cross-realm Kerberos trust (PROLE.ORG ↔ KNOE.LOCAL)
This is the prole-specific glue that lets a workstation user with a PROLE.ORG TGT obtain a KNOE.LOCAL service ticket without re-typing a password.
4.1 Setup
Provisioned by the Ansible playbook
infrastructure/playbooks/kerberos_trust_setup.yml
(landed in commits 5cece40..ad1eced on 2026-05-10/11). Reads the
shared trust_shared_password from the k8s Secret
knoe-system/knoe-kdc-secrets and writes it both:
- On myrddin (Samba side) — creates user
krbtgt_KNOE.LOCALin Samba with the shared password, sets UPN tokrbtgt/KNOE.LOCAL@PROLE.ORG(the Kerberos-canonical form), pinsmsDS-SupportedEncryptionTypes = 4(RC4 only). - In-cluster MIT KDC —
etc/init_kdc.shcreates bothkrbtgt/KNOE.LOCAL@PROLE.ORGandkrbtgt/PROLE.ORG@KNOE.LOCALlocally viakadmin.local addprinc -e arcfour-hmac:normalwith the matching shared password.
RC4 enforcement on both sides is critical — AES key derivation uses a
salt (Samba salts as <remote_realm>+UPN, MIT salts as
<local_realm>+<principal-no-realm>), so the same password produces
different AES keys on each side. RC4 has no salt, keys converge.
4.2 What works today
Verified 2026-05-10 from morgana (workstation) and myrddin (DC):
$ kdestroy && kinit chrisfu@PROLE.ORG
$ kvno krbtgt/KNOE.LOCAL@PROLE.ORG
krbtgt/KNOE.LOCAL@PROLE.ORG: kvno = 3
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: chrisfu@PROLE.ORG
krbtgt/PROLE.ORG@PROLE.ORG (local TGT)
krbtgt/KNOE.LOCAL@PROLE.ORG (cross-realm referral)
Workstation Kerberos config is provisioned by
infrastructure/playbooks/workstation_kerberos.yml
(landed in earlier commits). It deploys /etc/krb5.conf with both
realms defined, plus Chrome/Edge managed-policy AuthServerAllowlist
so the browser will offer Kerberos SPNEGO for *.prole.org.
4.3 Cross-realm flow
sequenceDiagram
autonumber
participant WS as Workstation<br/>(morgana, PROLE.ORG-joined)
participant SambaKDC as Samba KDC<br/>(myrddin, PROLE.ORG)
participant MITKDC as MIT KDC<br/>(in-cluster, KNOE.LOCAL)
participant Svc as Kerberized service<br/>(HTTP/git.prole.org)
WS->>SambaKDC: AS_REQ chrisfu@PROLE.ORG
SambaKDC-->>WS: TGT (krbtgt/PROLE.ORG@PROLE.ORG)
Note over WS: User opens https://git.prole.org<br/>(realm of svc = PROLE.ORG for SPNEGO,<br/>but pretend = KNOE.LOCAL for illustration)
WS->>SambaKDC: TGS_REQ for krbtgt/KNOE.LOCAL@PROLE.ORG
Note right of SambaKDC: Samba's krbtgt_KNOE.LOCAL user<br/>has the shared RC4 key
SambaKDC-->>WS: cross-realm TGT<br/>(enc with shared key, kvno N)
WS->>MITKDC: TGS_REQ for HTTP/[svc-host]@KNOE.LOCAL
Note right of MITKDC: Decrypts inbound TGT<br/>with matching RC4 key (kvno N)
MITKDC-->>WS: service ticket
WS->>Svc: HTTP/2 + Authorization: Negotiate [SPNEGO]
Svc-->>WS: 200 + identity = chrisfu (PROLE.ORG)
Today's only Kerberized service is git.prole.org (Gitea SPNEGO) —
that one is HTTP/git.prole.org@PROLE.ORG, so the cross-realm
mechanic isn't actually exercised in production yet. The cross-realm
trust exists for future services that live in the cluster (KNOE.LOCAL)
and want to accept workstation TGTs from PROLE.ORG without forcing the
operator to maintain two parallel user databases.
4.4 Operational notes
- The
kerberos_trust_setup.ymlplaybook is idempotent. Re-running it rotates the password (matches the cluster Secret) and bumps the kvno on the Samba side. If the cluster Secret is rotated, re-run the playbook to sync. - MIT side kvno must match Samba side kvno; tonight's debug session (2026-05-11) walked through what happens when they drift.
- pg_tde Transparent Data Encryption is in
shared_preload_librarieson the in-cluster Postgres. If you ever patch the cluster spec to remove it, the next pod restart will fail to open the encrypted data directory. Don't.
5. Gitea SPNEGO at git.prole.org
Shipped 2026-05-09. Workflow:
sequenceDiagram
autonumber
participant Br as Browser<br/>(PROLE.ORG-joined, Kerberos TGT)
participant Trf as k3s Traefik
participant SpnegoProxy as gitea-spnego-proxy
participant Gitea as Gitea
Br->>Trf: GET https://git.prole.org/
Trf->>SpnegoProxy: pass-through
SpnegoProxy-->>Br: 401 + WWW-Authenticate: Negotiate
Br->>SambaKDC: get HTTP/git.prole.org service ticket
Br->>SpnegoProxy: GET / + Authorization: Negotiate [blob]
SpnegoProxy->>SpnegoProxy: validate SPNEGO with keytab<br/>(HTTP/git.prole.org@PROLE.ORG)
SpnegoProxy->>Gitea: GET / + X-WEBAUTH-USER: chrisfu
Note over Gitea: ENABLE_REVERSE_PROXY_AUTHENTICATION=true<br/>auto-provisions user on first sign-in
Gitea-->>Br: 200 (signed-in as chrisfu)
Components:
gitea-spnego-proxyDeployment (Go service, port 4000) with aHTTP/git.prole.org@PROLE.ORGkeytab mounted from a k8s Secret- Gitea env
ENABLE_REVERSE_PROXY_AUTHENTICATION=true+REVERSE_PROXY_AUTHENTICATION_HEADER=X-WEBAUTH-USER - Traefik IngressRoute routing
git.prole.org→ proxy → Gitea - Gitea Helm-deployed; PVC on local-path SC; values managed in
gitea/deploy.sh
For password fallback (1Password-stored), each engineer has a Gitea
recovery password set via etc/init_knoe_users.sh:gitea_api_set_password
(landed today after several false-positive-success rounds — see commits
5d545d2, d5f6e8f, 4f23b63).
6. Supabase Studio web SSO
Two endpoints, two states.
6.1 db.prole.org (k3s, current)
Live since 2026-04-30. Google OAuth via oauth2-proxy with
--email-domain=knoey.com. Backed by the k3s Supabase deployment.
Auth flow is the standard oauth2-proxy → Kong → Studio chain
documented in the canonical doc.
Future plan: keep db.prole.org on Google OAuth as the homelab path
(prole workstations don't have a domain-joined identity that maps
to knoey.com naturally). A separate Kerberos-gated path can be
layered in later if needed.
6.2 db.knoe.dev (GKE, planned)
Brief: docs/plans/junie/per-user-supabase-workspace.md.
Target state — swap oauth2-proxy + GoTrue from Google OAuth to
knoe-auth OIDC as the upstream, so engineers sign in once
(via knoe-auth) and land in their per-user Postgres schema.
Blocked on: pg_oauth-image-install.md
— the knoe-db image doesn't yet contain the pg_oauth extension, so
the Studio → Postgres step can't validate JWTs.
7. Engineer psql access
Two paths active.
7.1 SCRAM (Phase 1; current default)
Per-engineer LOGIN role with a strong password rotated through
1Password (knoey vault). Works today, scales poorly. See
db-access.md §Phase 1.
7.2 OAUTHBEARER via Device Flow (Phase 2; shipped, blocked)
Brief: pg-oauth-resume.md. Shipped
to source (commit eef729a) on 2026-05-11 with full spec changes to
deploy/gcp/gke/knoe-db.yaml and etc/init_cnpg_gke.sh, but the
matching pg_oauth extension was never installed in the knoe-db
Docker image. The cluster crashed on rollout attempt
(2026-05-11 evening); rolled back via kubectl patch to remove
pg_oauth from shared_preload_libraries. Live cluster spec
currently diverged from git — will reconcile when
pg_oauth-image-install.md
lands.
8. Engineer onboarding (prole-specific steps)
- knoey.com Google Workspace — invite
<short>@knoey.com(existing operator with admin role does this in Google Admin). - Samba AD — provision the workstation account on myrddin:
sudo samba-tool user create <short> <password> sudo samba-tool group addmembers prole-engineers <short> - knoe-auth user table —
etc/init_knoe_users.sh provision_user <primary> <short> <short>@knoey.com '<Full Name>' developer(or use the lower-leveletc/onboard_engineer.sh). - Postgres role — same per-engineer SCRAM role flow as
db-access.mdPhase 1. Afterinit_user_schemas_gke.sh(or local k3s equivalent) lands the per-user schema brief, also add to the allowlist there. - 1Password access — share the
knoeyvault. - Workstation join (optional) — if they'll log into a homelab
workstation, run
realm join PROLE.ORGplus the Ansibleworkstation_kerberos.ymlplaybook so their/etc/krb5.confand browser policies are set up for SPNEGO.
9. Known fragility / current incidents
| Issue | First seen | State |
|---|---|---|
| pg_oauth extension missing from knoe-db image | 2026-05-11 | Open. Cluster spec rolled back; awaiting pg_oauth-image-install.md. |
init_user_schemas_gke.sh silent no-op |
2026-05-11 | Open. Manually patched chrisfu + ron tonight; brief filed at init-user-schemas-heredoc-fix.md. |
deploy.sh calls non-existent knoe.deploy_pipeline module |
Since rebrand 2026 commit 55b6a6a |
Open. Brief: deploy-pipeline-restore.md. |
MagicMock leaking into conf/*.cfg despite shipped fix |
2026-05-11 (after a220400) |
Open. Original brief todo-1-cfg-save-path-bug.md is shipped but doesn't catch this shape; needs reopen. |
| KDC cross-realm trust needs a re-run after cluster Secret rotation | Always | Documented; idempotent playbook handles it. |
| Gitea admin-promotion PATCH resets password on SPNEGO users | 2026-05-10 | Fixed (commits 5d545d2, d5f6e8f, 4f23b63). |
10. Reference
| File / dir | Role |
|---|---|
infrastructure/playbooks/kerberos_trust_setup.yml |
Cross-realm trust on the Samba side |
infrastructure/playbooks/workstation_kerberos.yml |
Workstation /etc/krb5.conf + browser policy |
etc/init_knoe_users.sh |
User-table + Gitea + Kerberos principal provisioning |
etc/init_kdc.sh |
In-cluster MIT KDC + cross-realm krbtgts |
etc/init_1password.sh |
1Password preflight + knoey vault bootstrap |
gitea/deploy.sh |
Gitea Helm install + SPNEGO proxy + reverse-proxy auth env |
k8s/knoe/gitea-spnego-proxy.yaml |
gitea-spnego-proxy Deployment + keytab Secret mount |
deploy/opentofu/k3s/manifests/knoe/ |
k3s manifests (mirror of knoe-db's deploy/gcp/gke/ + k8s/knoe/) |
~/.vault_pass |
Ansible vault password file (operator-local, not in repo) |
inventory/group_vars/ad_dc/vault.yml |
Samba admin password (Ansible vault) |
inventory/group_vars/all/vault_k3s.yml |
k3s join token + secrets |
11. See also
~/dev/knoe-db/docs/knoe-auth.md— canonical architecturedb-access.md— engineer psql access (Phase 1 + 2)knoe-auth-phase-2.md— OIDC issuer Phase 2 designlocal-dev-knoe-auth.md— k3d dev loop for the knoe-auth podoidc-setup.md— Google OAuth client registration for oauth2-proxy + Grafana