wip: docs(sso): plan to route all beefcake web apps through kanidm SSO #680

Draft
lytedev wants to merge 1 commit from sec-sso-plan into main
Owner

What

A design/plan doc (lib/doc/sso-plan.md) for the security-audit SSO workstream. Doc only — no runtime changes, no nix code.

Deliverables

  1. Inventory of every served beefcake caddy vhost (read from config + live-probed from dragon over the tailnet): hostname · app · current auth · target · how. Notable gaps found:
    • music-assistant.h.lyte.devzero auth on an admin/API surface.
    • git.lyte.dev — kanidm client exists but the OIDC source is configured by hand in Forgejo's admin UI, not in nix.
    • files.lyte.dev / tasks.h.lyte.dev — public; intent needs confirming.
  2. Recommended declarative pattern, two lanes:
    • Path A — native OIDC: the existing immich/headscale migration + kanidm-oauth2-secrets fetcher flow (finish forgejo; add audiobookshelf, paperless).
    • Path B — caddy forward_auth → a shared oauth2-proxy (itself a kanidm OIDC client), for apps with no OIDC — kanidm has no forward-auth endpoint. Chosen over Authelia / caddy-security and justified; slots into the same 20-oauth2.hjson + secret-fetcher flow. Module shape + per-app opt-in sketched and option names verified against this flake's services.oauth2-proxy (7.15.3).
  3. Audit M8 (host-beefcakeidm_oauth2_admins): documents that this is create/modify over all OAuth2 clients (SSO-wide-rewrite blast radius, not just read), that kanidm exposes no read-only-secret role, and lists mitigations (dedicated oauth-secret-reader account, token custody + rotation runbook, a custom-ACP hardening spike).
  4. Rollout order + a follow-up-PR checklist.

Reference implementation

music-assistant behind the shared gate is fully specified but intentionally not shipped enabled — a working deploy needs a sops cookie secret (only Daniel can encrypt) + a live sso-gate client bootstrap, and can't be live-verified read-only. Shipping a half-bootstrapped oauth2-proxy would violate verify-before-merge / don't-deploy, so it's delivered as ready-to-enable code in the doc and a focused follow-up PR. Keeps this PR to one thing.

Review asks

  • Sanity-check the target-auth column (esp. files.lyte.dev/tasks.h.lyte.dev intent, and leaving atuin/home-assistant on their own auth).
  • Confirm oauth2-proxy vs authelia as the forward-auth backend.

🤖 Generated with Claude Code

## What A **design/plan** doc (`lib/doc/sso-plan.md`) for the security-audit SSO workstream. Doc only — no runtime changes, no nix code. ## Deliverables 1. **Inventory** of every served beefcake caddy vhost (read from config + live-probed from dragon over the tailnet): hostname · app · current auth · target · how. Notable gaps found: - `music-assistant.h.lyte.dev` — **zero auth** on an admin/API surface. - `git.lyte.dev` — kanidm client *exists* but the OIDC source is configured by hand in Forgejo's admin UI, not in nix. - `files.lyte.dev` / `tasks.h.lyte.dev` — public; intent needs confirming. 2. **Recommended declarative pattern**, two lanes: - **Path A — native OIDC**: the existing immich/headscale migration + `kanidm-oauth2-secrets` fetcher flow (finish forgejo; add audiobookshelf, paperless). - **Path B — caddy `forward_auth` → a shared `oauth2-proxy`** (itself a kanidm OIDC client), for apps with no OIDC — kanidm has no forward-auth endpoint. Chosen over Authelia / caddy-security and justified; slots into the same `20-oauth2.hjson` + secret-fetcher flow. Module shape + per-app opt-in sketched and option names verified against this flake's `services.oauth2-proxy` (7.15.3). 3. **Audit M8** (`host-beefcake` ∈ `idm_oauth2_admins`): documents that this is *create/modify* over all OAuth2 clients (SSO-wide-rewrite blast radius, not just read), that kanidm exposes **no** read-only-secret role, and lists mitigations (dedicated `oauth-secret-reader` account, token custody + rotation runbook, a custom-ACP hardening spike). 4. **Rollout order** + a follow-up-PR checklist. ## Reference implementation music-assistant behind the shared gate is **fully specified but intentionally not shipped enabled** — a working deploy needs a sops cookie secret (only Daniel can encrypt) + a live `sso-gate` client bootstrap, and can't be live-verified read-only. Shipping a half-bootstrapped oauth2-proxy would violate verify-before-merge / don't-deploy, so it's delivered as ready-to-enable code in the doc and a focused follow-up PR. Keeps this PR to one thing. ## Review asks - Sanity-check the target-auth column (esp. `files.lyte.dev`/`tasks.h.lyte.dev` intent, and leaving atuin/home-assistant on their own auth). - Confirm oauth2-proxy vs authelia as the forward-auth backend. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
docs(sso): plan to route all beefcake web apps through kanidm SSO
All checks were successful
/ check-format (push) Successful in 9s
/ build (push) Successful in 14m24s
543ead4b51
Security-audit follow-up. Inventories every served caddy vhost + its current
vs. target auth, and recommends one declarative pattern for the gaps:

- Path A (native OIDC) for apps that speak it — the existing immich/headscale
  migration+secret-fetcher flow (finish forgejo, add audiobookshelf/paperless).
- Path B (caddy forward_auth -> shared oauth2-proxy, itself a kanidm OIDC
  client) for apps with no OIDC, since kanidm has no forward-auth endpoint.
  Justified over authelia/caddy-security; module + per-app opt-in sketched.

Also documents audit M8 (host-beefcake in idm_oauth2_admins = SSO-wide-rewrite
blast radius; no read-only kanidm scope exists) with mitigations, and a
prioritized rollout order. music-assistant (currently zero auth) is the
reference impl, specified but left as a bootstrap follow-up (needs a sops
cookie secret + live deploy) rather than shipped half-wired.

Doc only; no runtime changes.
lytedev changed title from docs(sso): plan to route all beefcake web apps through kanidm SSO to wip: docs(sso): plan to route all beefcake web apps through kanidm SSO 2026-07-01 11:26:01 -05:00
All checks were successful
/ check-format (push) Successful in 9s
Required
Details
/ build (push) Successful in 14m24s
Required
Details
This pull request is marked as a work in progress.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin sec-sso-plan:sec-sso-plan
git switch sec-sso-plan
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lytedev/nix!680
No description provided.