# Brief: Phase 2 OIDC — GKE deploy **Status:** Active **Filed:** 2026-05-02 **Author:** Junie **Depends on:** Queue #3 (image rename `knoe-authority` → `knoe-auth`) — **shipped 2026-05-02** --- ## 1. Context knoe-auth Phase 2 adds an OIDC provider surface to the existing Kerberos enrollment service. The k3d dev sandbox shipped 2026-05-02 (commit 93157b0): `application-k3d.yml` profile, `etc/gen_oidc_signing_key.sh` keypair generator, and all OIDC endpoints (`/.well-known/openid-configuration`, `/jwks.json`, `/authorize`, `/token`, `/userinfo`) are exercisable locally. This brief covers the remaining work to ship Phase 2 in production on GKE: 1. Generate a production RS256 keypair and store it in 1Password (consistent with the existing secret pattern in `etc/init_knoe_auth.sh`). 2. Wire the signing key into the `knoe-auth-oidc` K8s Secret in `knoe-system`. 3. Enable OIDC in the GKE deployment (`KNOE_AUTH_OIDC_ENABLED=true`, issuer URL, signing key). 4. Add a Kong route so `https://api.knoe.dev/auth` proxies to knoe-auth (the `/auth/v1/*` routes already go to GoTrue — knoe-auth needs `/auth` without the `/v1` prefix). 5. Rollout and verify externally. Design reference: [`docs/knoe-auth-phase-2.md`](../knoe-auth-phase-2.md). --- ## 2. Deliverables ### 2.1 Production RS256 keypair Generate once on the engineer's laptop (same tool as k3d): ```bash ./etc/gen_oidc_signing_key.sh # writes etc/secrets/knoe-auth-oidc-key.{pem,b64} ``` Store the base64 PKCS#8 private key (`knoe-auth-oidc-key.b64`) in 1Password as item `knoe-auth-oidc-signing-key` field `signing_key`. This follows the same pattern as `knoe-google-oidc` / `knoe-kdc-master` used by `op_secret()` in `init_knoe_auth.sh`. > **Do not commit the key.** `etc/secrets/` is gitignored. ### 2.2 `init_knoe_auth.sh` — new `create_oidc_signing_key_secret` function Add a function (GKE path only) alongside `create_google_oidc_secret()`: ```bash create_oidc_signing_key_secret() { if kube -n "$NAMESPACE" get secret knoe-auth-oidc >/dev/null 2>&1; then info "knoe-auth-oidc already exists — skipping." return fi info "Creating knoe-auth-oidc secret..." local signing_key signing_key=$(op_secret "knoe-auth-oidc-signing-key" "signing_key") kube -n "$NAMESPACE" create secret generic knoe-auth-oidc \ --from-literal=signing-key="$signing_key" info "knoe-auth-oidc created." } ``` Call it from the `schema` subcommand block (GKE path), after `create_google_oidc_secret`. Note: the existing `knoe-auth-oidc-secret.example.yaml` also has `client-id` and `client-secret` fields (for knoe-auth acting as an OIDC *client*). Those are not needed for Phase 2 (knoe-auth is the *provider*, not a client). The secret only needs `signing-key` for now; the example file can stay as-is. ### 2.3 `deploy/gcp/gke/knoe-auth-deployment.yaml` — enable OIDC Change the three OIDC env vars (already present, currently disabled): ```yaml - name: KNOE_AUTH_OIDC_ENABLED value: "true" # was: "${KNOE_AUTH_OIDC_ENABLED:-false}" - name: KNOE_AUTH_OIDC_ISSUER value: "https://api.knoe.dev/auth" # was: empty / placeholder ``` The `KNOE_AUTH_OIDC_SIGNING_KEY` env var already reads from `knoe-auth-oidc` secret (`signing-key` key) — no change needed there. ### 2.4 Kong route for `/auth` → knoe-auth In `supabase/helm/knoe-supabase/templates/kong/config.yaml`, add a new service + route block **before** the existing GoTrue `/auth/v1` block (Kong matches longest prefix first, so order matters): ```yaml _format_version: "2.1" services: # ── knoe-auth OIDC provider (/auth — no /v1 prefix) ───────────────────── - name: knoe-auth url: http://knoe-auth.knoe-system.svc.cluster.local:8080 routes: - name: knoe-auth-oidc strip_path: false paths: - /auth # Note: /auth/v1/* is handled by GoTrue below; Kong routes by longest # prefix so /auth/v1/... hits GoTrue, /auth/... hits knoe-auth. ``` Verify with `helm template` that both routes render and that `/auth/v1/` still resolves to GoTrue. ### 2.5 `docs/knoe-system.md` update - §2 WIP table: flip Phase 2 OIDC GKE deploy from **Pending** → **Shipped**. - §7 Open work items: remove the Phase 2 GKE pending bullet; update pg_oauth note to say "OIDC issuer now reachable — pg_oauth can resume". --- ## 3. Out of scope - pg_oauth wiring (separate brief; resumes after this lands). - Round 1.5 OpenBao transit-key encryption. - JWKS key rotation (future operational concern). - knoe-auth acting as an OIDC *client* (the `client-id`/`client-secret` fields in the oidc secret example are for a future phase). --- ## 4. Definition of done - [ ] `kubectl -n knoe-system get secret knoe-auth-oidc` exists with `signing-key` field - [ ] `kubectl rollout status deployment/knoe-auth -n knoe-system` → success - [ ] `curl -fsS https://api.knoe.dev/auth/.well-known/openid-configuration | jq .issuer` → `"https://api.knoe.dev/auth"` - [ ] `curl -fsS https://api.knoe.dev/auth/jwks.json | jq '.keys[0].kty'` → `"RSA"` - [ ] `curl -fsS https://api.knoe.dev/auth/v1/` still routes to GoTrue (not knoe-auth) - [ ] `docs/knoe-system.md` Phase 2 GKE status → Shipped - [ ] `docs/TODO.md` Phase 2 OIDC GKE deploy moved from In progress → Done --- ## 5. Commit shape ``` feat(auth): Phase 2 OIDC GKE deploy - init_knoe_auth.sh: add create_oidc_signing_key_secret (GKE path) - deploy/gcp/gke/knoe-auth-deployment.yaml: enable OIDC (ENABLED=true, ISSUER set) - supabase/helm/knoe-supabase/templates/kong/config.yaml: add /auth route → knoe-auth - docs/knoe-system.md: Phase 2 GKE status → Shipped - docs/TODO.md: Phase 2 OIDC GKE deploy → Done Depends on: queue #3 (knoe-auth image rename, shipped 2026-05-02). Unblocks: pg_oauth resume. ```