add arrstack oauth app + per-app access groups #18

Merged
benvin merged 2 commits from benvin/arrstack-oauth into main 2026-08-16 16:11:19 +10:00
Member

Why

arrproxy (a Go service) will be the single front door for the media stack at https://arrstack.unkin.net, fronted by an oauth2-proxy sidecar doing Authentik OIDC. After login, arrproxy derives which backend apps (sonarr, radarr, prowlarr) a user may reach from the user's Authentik group membership carried in the OIDC groups claim (oauth2-proxy passes it as X-Auth-Request-Groups). This adds the Authentik OIDC application for that front door plus the per-app entitlement groups it reads.

Changes

  • config/providers_oauth2/arrstack.yaml: confidential oauth2 client client_id: arrstack, litellm-style authorization/invalidation flows, client_secret from Vault kv kubernetes/namespace/arrstack/default/oauth-credentials, openid/email/profile scopes, redirect https://arrstack.unkin.net/oauth2/callback, launch https://arrstack.unkin.net/. The module unconditionally attaches the estate hierarchical ak_groups scope mapping, so this front door emits the groups claim.
  • config/permissions/akP-arrstack-user.yaml: front-door access gate (application: arrstack) — only members of this permission (or a role nesting it) can complete OIDC to the arrstack app.
  • config/permissions/akP-arrstack-{sonarr,radarr,prowlarr}.yaml: per-app entitlements, deliberately unbound (no application) so they never gate OIDC and exist only to surface in the user's ak_groups claim for arrproxy to authorize the matching backend.
  • config/roles/akR-arrstack-user.yaml: full-media role nesting the front door + all three per-app perms. Narrower access = assign individual akP-arrstack-<app> perms (plus akP-arrstack-user) to a user directly.
  • config/roles/akR-global-admin.yaml: also nests the arrstack front door + all per-app perms (arrstack has no admin tier; this gives global admins full media access).

How per-app access reaches arrproxy

The estate ak_groups (hierarchical) scope mapping walks each of a user's groups up through .parents and emits the union of group names. A member of akR-arrstack-user therefore gets an ak_groups claim containing:
akR-arrstack-user, akP-arrstack-user, akP-arrstack-sonarr, akP-arrstack-radarr, akP-arrstack-prowlarr.

arrproxy/oauth2-proxy must request the ak_groups scope and read the ak_groups claim (oauth2-proxy --oidc-groups-claim=ak_groups), then map akP-arrstack-sonarr -> sonarr, -radarr -> radarr, -prowlarr -> prowlarr. The three managed openid/email/profile scopes alone do NOT carry groups; the ak_groups scope is required on the token request.

Out-of-band before apply

Seed Vault kv kv/kubernetes/namespace/arrstack/default/oauth-credentials with client_secret (and the deploy-side client_id/cookie_secret for oauth2-proxy) — Terraform only reads client_secret. Not applied here.

Validation

yamllint (repo relaxed profile) passes; no trailing whitespace. No apply.

## Why `arrproxy` (a Go service) will be the single front door for the media stack at https://arrstack.unkin.net, fronted by an oauth2-proxy sidecar doing Authentik OIDC. After login, arrproxy derives which backend apps (sonarr, radarr, prowlarr) a user may reach from the user's Authentik group membership carried in the OIDC groups claim (oauth2-proxy passes it as X-Auth-Request-Groups). This adds the Authentik OIDC application for that front door plus the per-app entitlement groups it reads. ## Changes - `config/providers_oauth2/arrstack.yaml`: confidential oauth2 client `client_id: arrstack`, litellm-style authorization/invalidation flows, `client_secret` from Vault kv `kubernetes/namespace/arrstack/default/oauth-credentials`, openid/email/profile scopes, redirect `https://arrstack.unkin.net/oauth2/callback`, launch `https://arrstack.unkin.net/`. The module unconditionally attaches the estate hierarchical `ak_groups` scope mapping, so this front door emits the groups claim. - `config/permissions/akP-arrstack-user.yaml`: front-door access gate (`application: arrstack`) — only members of this permission (or a role nesting it) can complete OIDC to the arrstack app. - `config/permissions/akP-arrstack-{sonarr,radarr,prowlarr}.yaml`: per-app entitlements, deliberately unbound (no `application`) so they never gate OIDC and exist only to surface in the user's `ak_groups` claim for arrproxy to authorize the matching backend. - `config/roles/akR-arrstack-user.yaml`: full-media role nesting the front door + all three per-app perms. Narrower access = assign individual `akP-arrstack-<app>` perms (plus `akP-arrstack-user`) to a user directly. - `config/roles/akR-global-admin.yaml`: also nests the arrstack front door + all per-app perms (arrstack has no admin tier; this gives global admins full media access). ## How per-app access reaches arrproxy The estate `ak_groups` (hierarchical) scope mapping walks each of a user's groups up through `.parents` and emits the union of group **names**. A member of `akR-arrstack-user` therefore gets an `ak_groups` claim containing: `akR-arrstack-user`, `akP-arrstack-user`, `akP-arrstack-sonarr`, `akP-arrstack-radarr`, `akP-arrstack-prowlarr`. arrproxy/oauth2-proxy must request the `ak_groups` scope and read the `ak_groups` claim (oauth2-proxy `--oidc-groups-claim=ak_groups`), then map `akP-arrstack-sonarr` -> sonarr, `-radarr` -> radarr, `-prowlarr` -> prowlarr. The three managed openid/email/profile scopes alone do NOT carry groups; the `ak_groups` scope is required on the token request. ## Out-of-band before apply Seed Vault kv `kv/kubernetes/namespace/arrstack/default/oauth-credentials` with `client_secret` (and the deploy-side `client_id`/`cookie_secret` for oauth2-proxy) — Terraform only reads `client_secret`. Not applied here. ## Validation yamllint (repo relaxed profile) passes; no trailing whitespace. No apply.
unkin-agent added 1 commit 2026-08-16 15:00:37 +10:00
add arrstack oauth app + per-app access groups
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
e7c1f561f1
Add the Authentik OIDC application that fronts the arrproxy media front door
at arrstack.unkin.net, plus the per-app entitlement groups arrproxy reads from
the user's groups claim to decide which backends (sonarr/radarr/prowlarr) a
user may reach.

- config/providers_oauth2/arrstack.yaml: confidential oauth2 client
  client_id=arrstack, litellm-style auth/invalidation flows, client_secret
  from Vault kv kubernetes/namespace/arrstack/default/oauth-credentials,
  openid/email/profile scopes, redirect https://arrstack.unkin.net/oauth2/callback,
  launch https://arrstack.unkin.net/. The module always attaches the estate's
  hierarchical ak_groups scope mapping, so the front door emits the groups claim.
- config/permissions/akP-arrstack-user.yaml: front-door gate (application: arrstack).
- config/permissions/akP-arrstack-{sonarr,radarr,prowlarr}.yaml: per-app
  entitlements, unbound (no application) so they only surface in the ak_groups
  claim for arrproxy to authorize backends.
- config/roles/akR-arrstack-user.yaml: full media role nesting all four.
- akR-global-admin: also nests the arrstack front door + all per-app perms.
unkin-agent added 1 commit 2026-08-16 15:41:33 +10:00
ci: re-run plan after oauth-credentials seed
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
547cad6542
benvin merged commit 5f4b3557c1 into main 2026-08-16 16:11:19 +10:00
benvin deleted branch benvin/arrstack-oauth 2026-08-16 16:11:19 +10:00
Sign in to join this conversation.