feat(admin): add system administration panel #39

Merged
ryan.mcgee merged 1 commit from feat/admin-panel-shell into main 2026-10-22 13:23:05 +00:00
Owner

Summary

  • Phase 1 of the system administration panel: a place for system administrators (users.server_admin) to see the version and health of the server and to configure it, separate from any organization.
  • Changing the server needs a second factor; a session signed in through an enabled OIDC provider counts as having one, because the provider is assumed to enforce its own.

Changes

  • /admin with a menu: Overview, Settings, Identity providers (moved under it), Live dashboard. The navigation link is now "System administration".
  • Overview: version, commit and build time (new COMMIT / BUILD_TIME build args from scripts/images.sh), Elixir/OTP, database backend, uptime; health of the database and each background service; email, GeoIP and provider status; node counts per organization (counts and organization names only, no tenant data); VM stats. Refreshes every 10 seconds.
  • Settings: read-only view of the effective TRAEFIK_CONTROL_* configuration; secrets are never shown.
  • LiveDashboard moves from /dev/dashboard to /admin/dashboard (destructive actions off), behind the same guards.
  • Gate: every change needs a second factor and a login from the last 10 minutes (TraefikControl.Admin.authorize_change/1), re-checked on each event; otherwise the pages are read-only with a link to fix it. Viewing the identity provider page no longer needs a recent login.
  • Sessions record how they were signed in (users_tokens.authenticated_via, identity_provider_id; reversible migration, no foreign key because SQLite cannot drop one portably). A password sign-in never counts as a provider sign-in, and turning a provider off ends the bypass at once.
  • Signing in again while signed in sends prompt=login and max_age=0 to the provider and refuses an auth_time older than the request.

Verification

  • mix precommit: exit 0 (format, compile with warnings as errors, test).
  • mix credo --strict: no issues. mix dialyzer: passed.
  • mix test: 1582 passed on SQLite and on PostgreSQL; migration rollback and re-apply clean on both.
  • Built the production image with the build args and ran it: registered the first account, saw the overview with commit and build time, saw the pages read-only and a hand-sent provider form refused, enrolled TOTP in the UI and then added a provider successfully; /admin/dashboard loads in production and /dev/dashboard is 404.
  • Not exercised against a real OIDC provider: the provider-session bypass and prompt=login re-authentication are covered by tests against the in-repo fake provider only.

Notes

  • Later phases (separate PRs): organizations (create with designated owner, suspend, delete), break-glass join, system administrator management, server audit log.
## Summary - Phase 1 of the system administration panel: a place for system administrators (`users.server_admin`) to see the version and health of the server and to configure it, separate from any organization. - Changing the server needs a second factor; a session signed in through an enabled OIDC provider counts as having one, because the provider is assumed to enforce its own. ## Changes - `/admin` with a menu: Overview, Settings, Identity providers (moved under it), Live dashboard. The navigation link is now "System administration". - Overview: version, commit and build time (new `COMMIT` / `BUILD_TIME` build args from `scripts/images.sh`), Elixir/OTP, database backend, uptime; health of the database and each background service; email, GeoIP and provider status; node counts per organization (counts and organization names only, no tenant data); VM stats. Refreshes every 10 seconds. - Settings: read-only view of the effective `TRAEFIK_CONTROL_*` configuration; secrets are never shown. - LiveDashboard moves from `/dev/dashboard` to `/admin/dashboard` (destructive actions off), behind the same guards. - Gate: every change needs a second factor and a login from the last 10 minutes (`TraefikControl.Admin.authorize_change/1`), re-checked on each event; otherwise the pages are read-only with a link to fix it. Viewing the identity provider page no longer needs a recent login. - Sessions record how they were signed in (`users_tokens.authenticated_via`, `identity_provider_id`; reversible migration, no foreign key because SQLite cannot drop one portably). A password sign-in never counts as a provider sign-in, and turning a provider off ends the bypass at once. - Signing in again while signed in sends `prompt=login` and `max_age=0` to the provider and refuses an `auth_time` older than the request. ## Verification - `mix precommit`: exit 0 (format, compile with warnings as errors, test). - `mix credo --strict`: no issues. `mix dialyzer`: passed. - `mix test`: 1582 passed on SQLite and on PostgreSQL; migration rollback and re-apply clean on both. - Built the production image with the build args and ran it: registered the first account, saw the overview with commit and build time, saw the pages read-only and a hand-sent provider form refused, enrolled TOTP in the UI and then added a provider successfully; `/admin/dashboard` loads in production and `/dev/dashboard` is 404. - Not exercised against a real OIDC provider: the provider-session bypass and `prompt=login` re-authentication are covered by tests against the in-repo fake provider only. ## Notes - Later phases (separate PRs): organizations (create with designated owner, suspend, delete), break-glass join, system administrator management, server audit log.
feat(admin): add system administration panel
All checks were successful
CI / format, compile, credo, dialyzer (pull_request) Successful in 1m40s
CI / tests (SQLite) (pull_request) Successful in 2m27s
Development images / images (push) Successful in 5m35s
CI / dependency audit (pull_request) Successful in 46s
CI / tests (PostgreSQL) (pull_request) Successful in 2m27s
0dfe35d6ac
- add /admin for system administrators: overview (version, build
  commit and time, health of the database and background services,
  email/GeoIP/provider status, node counts per organization, VM stats),
  read-only settings, and identity providers moved under it
- serve LiveDashboard at /admin/dashboard behind the same guards,
  replacing /dev/dashboard
- changes need a second factor and a login from the last 10 minutes,
  re-checked on every event; otherwise pages are read-only
- record how each session signed in (users_tokens.authenticated_via,
  identity_provider_id); a session from an enabled OIDC provider counts
  as having a second factor, a password session never does
- re-authenticate OIDC sessions with prompt=login and max_age=0 and
  refuse a stale auth_time
- pass COMMIT and BUILD_TIME build args from images.sh to the image
ryan.mcgee deleted branch feat/admin-panel-shell 2026-10-22 13:23:05 +00:00
Sign in to join this conversation.
No reviewers
No labels
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
White_Ghost_Cyber_Systems/traefik-control!39
No description provided.