Phase 5+6: main host behind Authentik — copyparty trusts X-Authentik-* headers with group permissions (editors, media-admins), dumpd authorizes from headers (admins/media-admins), /sync gated to media-admins, dock drops its dump password; configure.py loses editors/admin

WebDAV continues via Authentik app passwords (provider: Intercept header authentication).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 14:55:48 -05:00
parent 76a7d06df4
commit 50c037e514
9 changed files with 109 additions and 117 deletions

View File

@@ -46,10 +46,11 @@ works from ~/vanguard-stream without sudo.
./configure.py # later: add/remove/reset streamers and editors, then apply
./configure.py --show # print current users and the OBS settings to hand out
Stateless: it reads the current values out of `Caddyfile`, `mediamtx.yml` and `copyparty.conf`,
regenerates those three plus `dump-users.txt`, installs the dump users to `/etc/vanguard`, creates
Stateless: it reads the current values out of `Caddyfile`, `mediamtx.yml` and `.env`, regenerates
`Caddyfile`, `mediamtx.yml`, `copyparty.conf` and `streamers.json` (→ `/etc/vanguard`), creates
`streams/<name>` and `clips/<name>` (with `.stignore`) for each streamer, restarts dumpd and the
containers. Removing a streamer or editor revokes access only; their files stay on disk.
containers. Editors and admins are Authentik groups (`editors`, `media-admins`, `admins`), not local
accounts. Removing a streamer revokes publishing only; their files stay on disk.
Passwords may not contain `: & ? # / \ quotes or spaces` (they ride inside the stream key).
## 4. Firewall (host nftables; OVH edge firewall is optional on top)
@@ -91,9 +92,11 @@ until Docker is restarted.
OBS → Settings → Stream → Custom: Server `rtmp://media.example.com:1935/`, key anything (the dock sets it).
OBS → Tools → WebSocket Server Settings → enable, set a password.
OBS → Docks → Custom Browser Docks → `https://media.example.com/dock/`.
OBS → Docks → Custom Browser Docks → `https://media.example.com/dock/` → log in with Discord once (the dock
is behind Authentik like everything else on that host).
In the dock: fill host/user/pass/OBS-ws-password once (stored in the dock's localStorage).
Per stream: type a title, click **Go Live**. After a bad night: **Dump tonight**.
Per stream: type a title, click **Go Live**. After a bad night: **Dump tonight** (dumps the night of the
Discord account you are logged in as; `admins`/`media-admins` may dump anyone's).
Stream key format the dock produces: `techy/Title?user=techy&pass=...`
SRT equivalent if preferred: `srt://media.example.com:8890?streamid=publish:techy/Title:techy:PASS`
@@ -212,7 +215,7 @@ streamer's Authentik username must equal their MediaMTX name.
Bandwidth: no transcoding, every viewer gets the source bitrate (~15 Mbps) → ~30 concurrent viewers on
the 500 Mbps line. For a crowd, restream to Twitch from OBS.
## 5g. Authentik forward-auth for the Caddy-gated hosts (`live.`, `bot.`; later the main host)
## 5g. Authentik forward-auth for the Caddy-gated hosts (main host, `live.`, `bot.`)
Design: **Authentik authenticates once for the whole domain; Caddy authorizes per host** from the
`X-Authentik-Groups` header the outpost returns; **Discord roles fill the Authentik groups** at login.
@@ -223,7 +226,10 @@ Design: **Authentik authenticates once for the whole domain; Caddy authorizes pe
cookie domain = the parent domain (e.g. `dumpstervigilantes.rip`). Edit the Embedded Outpost →
Applications → add it → Update. One login now covers every gated host.
3. Per-host group requirement = `.env`: `BOT_REQUIRE_GROUP=bot-users` (default), `LIVE_REQUIRE_GROUP=`
(empty = any logged-in member). `./configure.py` apply regenerates the Caddy blocks; a user outside the
(empty = any logged-in member), `SYNC_REQUIRE_GROUP=media-admins` (the `/sync` Syncthing UI on the main host).
On the main host copyparty itself authorizes by group (`editors`, `media-admins`); the dump endpoint lets
`admins`/`media-admins` dump anyone's night. Enable **"Intercept header authentication"** on the proxy
provider so WebDAV clients can log in with Authentik app passwords. `./configure.py` apply regenerates the Caddy blocks; a user outside the
group gets a 403 from Caddy before the app sees the request.
4. Discord roles → groups: Directory → Groups: create `bot-users` (and keep `streamers`, `editors`, `admins`).
Discord source → Scopes: `guilds guilds.members.read`. Customization → Policies → Expression Policy
@@ -238,11 +244,16 @@ Jellyfin and Gitea use OIDC providers instead, not this.
## 6. Editors
Browser: https://media.example.com/ → log in. Scrub any `.mp4` in the browser, download what you want.
WebDAV mount: same URL, same login. Upload finished work to `/finals`.
Log in with Discord at https://media.example.com/ (copyparty behind Caddy + Authentik). Access is by Authentik
group: **editors** read streams and clips and write `/finals`; **media-admins** have full rights everywhere
including `/trash`. Scrub any `.mp4` in the browser, download what you want.
WebDAV mount: same URL. Username = your Authentik username, password = an **Authentik app password**
(auth.HOST → your user settings → Tokens and App passwords → create). The proxy provider must have
"Intercept header authentication" enabled for this to work.
Every `.mp4` an editor sees is the same kind of file (see "Editing standard"). Raw clipper output that
needed converting is kept in a hidden `.src/` folder next to it (admins can show dotfiles in copyparty).
needed converting is kept in a hidden `.src/` folder next to it (media-admins can show dotfiles in copyparty).
## 7. Home archive box