Commit Graph

90 Commits

Author SHA1 Message Date
benvin 93c634e4c4 Merge pull request 'Onboard repospawner UI to Authentik OIDC' (#32) from benvin/repospawner-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #32
2026-08-31 22:21:09 +10:00
unkin-agent 3977f6f86b Merge remote-tracking branch 'origin/main' into benvin/repospawner-oidc
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
# Conflicts:
#	config/roles/akR-global-admin.yaml
2026-08-31 22:07:36 +10:00
benvin 6d014ce913 Merge pull request 'Onboard OpenBao as an Authentik OIDC client' (#33) from benvin/vault-oidc-provider into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #33
2026-08-30 22:17:39 +10:00
unkin-agent 230db5ad7e Onboard OpenBao as an Authentik OIDC client
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Adds config/providers_oauth2/vault.yaml so human logins to OpenBao go
through Authentik SSO (bao CLI and the web UI). Machine auth (approle,
kubernetes, CI) and break-glass are unchanged and stay on the OpenBao side.

Extends the oauth2 provider module so a config may generate its own client
secret instead of reading a pre-seeded one: client_secret_vault.generate
creates a random_password and writes {client_id, client_secret} to the given
kv-v2 path. Providers without the flag keep the existing read-only data source
behaviour. This is what lets the provider land with no manual Vault seed.

Gates the new application with akP-vault-admin and nests it in
akR-global-admin, matching how every other app in this repo is bound.
2026-08-30 21:25:39 +10:00
unkin-agent 2f80c4a536 Onboard repospawner UI to Authentik OIDC
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
Add an OAuth2/OIDC provider + application for the repospawner operator tool,
fronted by oauth2-proxy, and gate it on a new akP-repospawner-admin permission
group nested under akR-global-admin (mirrors the watchstate precedent).
2026-08-30 15:09:47 +10:00
benvin 5ecd03cdd5 Merge pull request 'Namespace service account token map keys by account' (#31) from benvin/token-foreach-namespacing into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #31
2026-08-30 00:03:11 +10:00
unkin-agent 0c6a9104c0 Namespace service account token map keys by account
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Two service_accounts declaring the same token identifier collapsed into a
single entry under merge(), silently dropping one token. Key the map by
account/identifier the way service_account_permissions already does, and
carry the bare identifier as a field for the authentik_token attribute.
2026-08-29 23:10:38 +10:00
benvin 3884a5b21f Merge pull request 'Manage the agent API service account and token in Terraform' (#30) from benvin/agent-api-token-iac into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #30
2026-08-29 23:04:04 +10:00
unkin-agent 8ec8bbda8e Manage the agent API service account and token in Terraform
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
The Authentik API token used by estate automation was created by hand in the
UI and pasted into Vault, so it was undocumented, unauditable and impossible
to rotate reproducibly. Model it as config instead.

Add a service_accounts config kind, discovered from config/service_accounts/
like the other kinds. Each entry creates a service_account user, an RBAC role
carrying its global permissions, its API tokens, and (optionally) a kv-v2
write publishing each token key.

Add sa-agent-api granting view_outpost, view_token and view_token_key, with a
non-expiring api token agent-api-token published to kv/service/authentik/agent-api-token.
2026-08-29 22:58:40 +10:00
benvin 09f7c9042e Merge pull request 'Onboard mediamark to Authentik OIDC' (#29) from benvin/mediamark-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #29
2026-08-29 21:55:34 +10:00
unkin-agent 1485962cf5 Fix mediamark Vault secret path and permission group name
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
The terraform-authentik runner's Vault policy only grants read on
kv/data/kubernetes/namespace/+/default/oauth-credentials (literal trailing
filename), so the arrstack/default/mediamark-oauth-credentials path 403s at
plan time and reddens CI. mediamark deploys in its own `mediamark` namespace
(watchstate model), so point the data source at
kubernetes/namespace/mediamark/default/oauth-credentials, which the policy
covers. Hostnames are unchanged.

Rename the permission group to akP-mediamark-user to match the peer tier-suffix
convention (akP-watchstate-admin, akP-arrstack-user). The group name is derived
from the filename in config/config.hcl, so update the akR-media-adult
reference too.
2026-08-29 21:13:41 +10:00
unkin-agent 72e65d7810 Onboard mediamark to Authentik OIDC
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
Add an oauth2 provider/application for the mediamark kids-content marking UI,
a permission group gating it, and nest that permission in akR-media-adult.
2026-08-29 20:57:54 +10:00
benvin e397fd909f Merge pull request 'Jellyfin SSO: cheeztv OIDC hosts, media-group gating, LDAP outpost' (#28) from benvin/jellyfin-sso into main
ci/woodpecker/push/apply Pipeline failed
Reviewed-on: #28
2026-08-29 11:51:19 +10:00
unkin-agent 9760c2eb3f Fix KV path comment in jellyfin-ldap provider configuration.
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Reference the actual Vault KV seed path for outpost token instead of deferring to PR body.
2026-08-26 22:23:32 +10:00
unkin-agent 3396b399ce Jellyfin SSO: cheeztv OIDC hosts, media-group gating, LDAP outpost
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
Completes the Authentik-side plumbing for Jellyfin SSO across both media
instances -- fafflix (adults, jellyfin.k8s.syd1.au.unkin.net) and cheeztv
(kids, cheeztv.unkin.net + cheeztv.k8s.syd1.au.unkin.net) -- and adds an
LDAP outpost so native clients can authenticate with app passwords.

Why: the previously-merged jellyfin OIDC provider only covered the fafflix
host and gated on the generic jellyfin permission groups. cheeztv needs SSO
too, access should be limited to media users, and native (non-browser)
clients need a password-based path.

How:
- providers_oauth2/jellyfin.yaml: one shared confidential client now lists
  strict redirect URIs for all three hosts using the verified
  jellyfin-plugin-sso callback path /sso/OID/redirect/authentik. Client
  secret moved to kv kubernetes/namespace/fafflix/default/oauth-credentials.
- Access is gated to media users only: akP-media-fafflix and akP-media-cheeztv
  now carry `application: jellyfin` and bind to the app; akP-jellyfin-admin /
  akP-jellyfin-user are demoted to pure role-claim groups (no app binding),
  still mapped by the plugin for admin/user rights. Per-instance authz
  (adults -> both, kids -> cheeztv only) stays with the media proxy.
- providers_ldap/jellyfin-ldap.yaml: new LDAP provider (base_dn
  DC=ldap,DC=goauthentik,DC=io, direct bind/search) + application
  (jellyfin-ldap) + outpost (jellyfin-ldap-outpost) via the existing module.
- modules/authentik/main.tf: resolve LDAP bind/unbind flow slugs to ids via
  data.authentik_flow, matching the oauth2/saml convention.
2026-08-26 22:15:28 +10:00
benvin 77adee64aa Merge pull request 'watchstate: add external watchstate.unkin.net redirect URI' (#27) from benvin/watchstate-external-uri into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #27
2026-08-25 21:47:39 +10:00
unkin-agent 643c484dea watchstate: add external watchstate.unkin.net redirect URI
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
watchstate is being exposed externally at watchstate.unkin.net; oauth2-proxy needs the external callback registered.
2026-08-25 21:42:26 +10:00
benvin 31b92b2b93 Merge pull request 'Onboard watchstate into Authentik (oauth2-proxy, admin-team-gated)' (#26) from benvin/watchstate-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #26
2026-08-25 20:48:01 +10:00
unkin-agent 00f835ac8c Retrigger plan: oauth-credentials kv secret now seeded
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-08-25 20:15:49 +10:00
unkin-agent db5bf753b5 Onboard watchstate into Authentik for oauth2-proxy
ci/woodpecker/pr/plan Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline was successful
watchstate is an internal media watch-state sync admin tool deployed at
watchstate.k8s.syd1.au.unkin.net behind oauth2-proxy (OIDC against
Authentik). Add the OAuth2/OIDC provider + application mirroring the
logviewer/traefik in-cluster admin pattern, gate it with the
akP-watchstate-admin permission group bound to the app, and nest that
permission into the akR-global-admin role so only the admin team can
authorize.
2026-08-25 20:11:38 +10:00
benvin 06e71604cf Merge pull request 'Add adult/kids media groups for media split' (#25) from benvin/media-groups into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #25
2026-08-24 22:03:32 +10:00
unkin-agent ec0646657d Add adult/kids media groups for media split
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
The media services are splitting into an adult (fafflix) and kids (cheeztv)
tier, and Authentik group membership will drive the media proxy's routing and
authorization. This adds the two-tier RBAC groups so users can be assigned the
right media access ahead of the provider/application wiring.

- Add akP-media-fafflix and akP-media-cheeztv per-service permission entitlements
  (unbound, so they surface in the hierarchical ak_groups claim for the proxy)
- Add akR-media-adult role nesting both fafflix and cheeztv (adults reach both)
- Add akR-media-kids role nesting only cheeztv (kids reach kids services only)
2026-08-24 22:01:25 +10:00
benvin ef84176633 Merge pull request 'Point identity env provider at in-cluster authentik-server ClusterIP' (#24) from benvin/incluster-provider-url into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #24
2026-08-23 23:22:56 +10:00
unkin-agent ae679ab587 ci: move authentik_url ClusterIP override into woodpecker only
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Keep local/default terragrunt runs pointed at the real public URL;
set the goauthentik#954 ClusterIP workaround via TF_VAR_authentik_url
in the CI environment blocks instead of as a terragrunt input.
2026-08-23 23:20:32 +10:00
unkin-agent 218a640882 Point identity env provider at in-cluster authentik-server ClusterIP
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Parameterise the authentik provider url as var.authentik_url (default:
the environment's public URL) and override it for
identity.k8s.syd1.au.unkin.net to
http://authentik-server.authentik.svc.cluster.local. Combined with
sessionAffinity: ClientIP on the Service, in-cluster CI runs pin to a
single server replica, eliminating the cross-replica read-back race
(goauthentik/terraform-provider-authentik#954).
2026-08-23 23:07:04 +10:00
benvin 62fb15791a Merge pull request 'Add logviewer OAuth2 provider/application and akP-logviewer-admin permission' (#21) from benvin/logviewer-oidc into main
ci/woodpecker/push/apply Pipeline failed
Reviewed-on: #21
2026-08-23 23:02:38 +10:00
benvin 73378cef30 Merge pull request 'Run plan without acquiring the Consul state lock' (#22) from benvin/lockfree-plan into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #22
2026-08-23 22:55:52 +10:00
benvin c047ba3819 Merge pull request 'ci: fetch vault from artifactapi instead of dnf install' (#23) from benvin/vault-via-artifactapi into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #23
2026-08-23 22:54:08 +10:00
unkin-agent 0480303db6 Merge origin/main (traefik #20) into benvin/logviewer-oidc
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-08-23 22:48:36 +10:00
benvin 5079d95ada Merge pull request 'Add traefik OAuth2 provider/application and akP-traefik-admin' (#20) from benvin/traefik-oidc into main
ci/woodpecker/push/apply Pipeline failed
Reviewed-on: #20
2026-08-23 22:46:35 +10:00
unkin-agent 937efb0360 Merge origin/main (jellyfin #19) into benvin/logviewer-oidc
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Resolve akR-global-admin.yaml keeping both akP-jellyfin-admin (main) and
akP-logviewer-admin (this branch).
2026-08-23 22:41:11 +10:00
unkin-agent ef4d29d1ad ci: fetch vault from artifactapi instead of dnf install
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
dnf install reads metadata for every enabled repo and downloads the
vendored vault RPM on every pipeline run. Fetch the pinned upstream zip
from the artifactapi hashicorp-releases remote instead, matching
terraform-vault and terraform-artifactapi.

- Replace dnf install vault with a pinned curl of the vault zip from the
  artifactapi hashicorp-releases remote, extracted to /usr/local/bin.
2026-08-23 22:37:12 +10:00
unkin-agent aa1f8955c8 Run plan without acquiring the Consul state lock
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
PR plan pipelines were failing with "Error acquiring the state lock"
when they collided with a concurrent apply (or another plan) holding
the lock on the same Consul-backed state.

- plan: pass -lock=false to terragrunt plan; apply keeps locking
2026-08-23 22:21:08 +10:00
unkin-agent 5f8dfc8450 ci: trigger pipeline on PR head
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-08-23 22:17:54 +10:00
unkin-agent b4e3ef3149 ci: re-run plan after merge of main
ci/woodpecker/pr/plan Pipeline was canceled
ci/woodpecker/pr/pre-commit Pipeline was canceled
2026-08-23 22:16:16 +10:00
unkin-agent c1eea2d441 Merge remote-tracking branch 'origin/main' into benvin/traefik-oidc
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
# Conflicts:
#	config/roles/akR-global-admin.yaml
2026-08-23 22:14:06 +10:00
benvin 5c136dfb96 Merge pull request 'Add Jellyfin OIDC provider, application and RBAC groups' (#19) from benvin/jellyfin-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #19
2026-08-23 22:10:35 +10:00
unkin-agent 43d325146c Add logviewer OAuth2 provider/application and akP-logviewer-admin permission
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
The ClickHouse log UI (logviewer) is being exposed at
https://logviewer.unkin.net behind oauth2-proxy in the logging namespace;
this adds the Authentik side as the prerequisite.

- Adds config/providers_oauth2/logviewer.yaml mirroring traefik: confidential
  client, client_id logviewer, secret from Vault kv
  kubernetes/namespace/logging/default/oauth-credentials,
  openid/email/profile scopes (ak_groups is attached to every oauth2
  provider by the module), strict redirect URI for the
  logviewer oauth2 callback.
- Adds config/permissions/akP-logviewer-admin.yaml bound to the logviewer
  application and nests it under akR-global-admin.
2026-08-23 17:24:18 +10:00
unkin-agent 1872b82550 Add traefik OAuth2 provider/application and akP-traefik-admin permission
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
The traefik dashboards (internal + external ingress classes) are being
exposed behind oauth2-proxy; this adds the Authentik side as the
prerequisite.

- Adds config/providers_oauth2/traefik.yaml mirroring arrstack: confidential
  client, client_id traefik, secret from Vault kv
  kubernetes/namespace/traefik-system/default/oauth-credentials,
  openid/email/profile scopes (ak_groups is attached to every oauth2
  provider by the module), strict redirect URIs for
  traefik-internal/traefik-external oauth2 callbacks.
- Adds config/permissions/akP-traefik-admin.yaml bound to the traefik
  application and nests it under akR-global-admin.
2026-08-23 12:35:17 +10:00
unkin-agent bbbb61777c Add Jellyfin OIDC provider, application and RBAC groups
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Jellyfin moves to Authentik SSO via jellyfin-plugin-sso (OIDC), keeping
native clients on Jellyfin local/API auth. Adds the oauth2 provider and
application for jellyfin.k8s.syd1.au.unkin.net plus the akP permission
groups gating access, wired into the standard-user and global-admin
roles per the two-tier RBAC model.

- Adds providers_oauth2/jellyfin.yaml: confidential client, secret read
  from kv/kubernetes/namespace/jellyfin/default/oauth-credentials,
  redirect URIs for the SSO plugin callback paths
- Adds akP-jellyfin-admin and akP-jellyfin-user bound to the app
- Nests akP-jellyfin-user under akR-standard-user and
  akP-jellyfin-admin under akR-global-admin
2026-08-23 12:33:55 +10:00
benvin 5f4b3557c1 Merge pull request 'add arrstack oauth app + per-app access groups' (#18) from benvin/arrstack-oauth into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #18
2026-08-16 16:11:18 +10:00
unkin-agent 547cad6542 ci: re-run plan after oauth-credentials seed
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-08-16 15:41:33 +10:00
unkin-agent e7c1f561f1 add arrstack oauth app + per-app access groups
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline failed
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.
2026-08-16 15:00:05 +10:00
benvin 132da3cfc8 Merge pull request 'Set explicit launch URL for the LiteLLM application' (#16) from benvin/litellm-app-visibility into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #16
2026-07-31 22:00:02 +10:00
benvin 819996b0c7 Merge pull request 'Default OAuth2 providers to RS256 ID token signing' (#15) from benvin/oidc-rs256-signing into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #15
2026-07-31 21:19:46 +10:00
unkinben a93205bc82 Set explicit launch URL for the LiteLLM application
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Ben (akR-global-admin) does not see the LiteLLM tile on the Authentik user
dashboard, while ArgoCD/Grafana/Rancher appear normally. The live API shows
LiteLLM is configured identically to those apps: the app exists, its access
binding akP-litellm-admin -> litellm is present, and akR-global-admin nests
akP-litellm-admin (bidirectionally, same as the others). A CI-style plan against
live state reports "No changes" -- so this is not terraform-correctable drift,
and a plain re-apply fixes nothing. Yet check_access for Ben returns
passing=false for litellm and passing=true for the rest: a stale cached access
policy result inside Authentik.

Add an optional per-app launch_url to the providers_oauth2 config (default null,
which keeps Authentik's redirect-derived URL) and wire it to the application's
meta_launch_url. Set it for LiteLLM to its UI. This makes the dashboard tile
deterministic and, on apply, re-saves the application -- invalidating the stale
access-policy cache so Ben's (already-correct) access re-evaluates and the tile
appears.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-31 20:46:35 +10:00
unkinben b6e9b6b6b9 Default OAuth2 providers to RS256 ID token signing
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
OAuth2 providers with no signing_key fall back to HS256, which RS256-only
RP clients (argocd confirmed, and the rest) reject with "unexpected
signature algorithm HS256; expected [RS256]", breaking OIDC login.

- Add data.authentik_certificate_key_pair.signing, resolving the estate's
  RSA keypair by name (var.oauth2_signing_key_name, default the built-in
  "authentik Self-signed Certificate").
- Default every provider's signing_key to that keypair via coalesce, so all
  providers sign with RS256 while keeping the per-yaml signing_key override.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-31 20:28:07 +10:00
benvin d85d7afc97 Merge pull request 'Update Gitea OIDC redirect URIs to canonical + admin route' (#14) from benvin/gitea-oidc-hosts into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #14
2026-07-31 20:09:16 +10:00
unkinben 1922014ab9 Update Gitea OIDC redirect URIs to canonical + admin route
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
The k8s Gitea drops SSH and serves git.unkin.net (canonical) plus
git.k8s.syd1.au.unkin.net (admin/backup route, live now via external-dns).
Replace the old git2 validation host in the OAuth2 redirect URIs to match
argocd-apps#309.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-31 00:02:48 +10:00
benvin ecfdf69d52 Merge pull request 'Add Gitea OAuth2/OIDC provider' (#13) from benvin/gitea-oidc into main
ci/woodpecker/push/apply Pipeline was successful
Reviewed-on: #13
2026-07-30 21:09:05 +10:00