Document Dex OIDC and add services-check integration (#223)
## Summary - Create Dex reference card (`docs/reference/services/dex.md`) with quick reference, architecture, identity source, storage, OIDC clients, secrets, and endpoints - Write federated login explanation article (`docs/explanation/federated-login.md`) covering the Dex + Forgejo two-layer auth model, login flow, and break-glass access - Add Dex to `services-check` (HTTP health endpoint + k3s pod check) - Update Grafana docs with new Authentication section documenting SSO via Dex - Update Forgejo docs with OAuth2 Provider section documenting its role as upstream identity source - Add Dex to ringtail workloads table and reference service index - Move `adopt-oidc-provider` plan to `completed/` with final design reflecting actual implementation ## Test plan - [ ] `mise run services-check` passes (includes new Dex checks) - [ ] `docs-check-links` passes (all wiki-links resolve) - [ ] `docs-check-index` passes (new docs are indexed) Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/223
This commit is contained in:
parent
0cdc143227
commit
d21798b1f3
13 changed files with 306 additions and 209 deletions
|
|
@ -68,6 +68,7 @@ Sync order: `1password-connect-ringtail` -> `external-secrets-crds-ringtail` ->
|
|||
| [[frigate]] | `frigate` | NVR with GPU-accelerated detection (RTX 4080) |
|
||||
| [[frigate]]-notify | `frigate` | MQTT-to-ntfy alert bridge |
|
||||
| Mosquitto | `mqtt` | MQTT broker for Frigate events |
|
||||
| [[dex]] | `dex` | OIDC identity provider (Forgejo-backed) |
|
||||
| [[ntfy]] | `ntfy` | Push notification server |
|
||||
| nvidia-device-plugin | `nvidia-device-plugin` | Exposes GPU to pods via CDI + nvidia RuntimeClass |
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ Individual service reference cards with URLs and configuration details.
|
|||
| [[zot]] | Container registry | indri |
|
||||
| [[devpi]] | PyPI caching proxy | k8s |
|
||||
| [[cv]] | Resume / CV site | k8s |
|
||||
| [[dex]] | OIDC identity provider | k8s (ringtail) |
|
||||
| [[docs]] | Documentation site (Quartz) | k8s |
|
||||
| [[flyio-proxy]] | Public reverse proxy (Fly.io + Tailscale) | Fly.io |
|
||||
| [[automounter]] | SMB share automounter | indri |
|
||||
|
|
|
|||
89
docs/reference/services/dex.md
Normal file
89
docs/reference/services/dex.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
title: Dex
|
||||
modified: 2026-02-19
|
||||
tags:
|
||||
- service
|
||||
- security
|
||||
- oidc
|
||||
---
|
||||
|
||||
# Dex
|
||||
|
||||
OIDC identity provider for BlumeOps. Dex federates authentication — downstream services (Grafana, future ArgoCD, etc.) delegate login to Dex, and Dex delegates to [[forgejo]] as the upstream OAuth2 provider.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **URL** | https://dex.ops.eblu.me |
|
||||
| **Tailscale URL** | https://dex.tail8d86e.ts.net |
|
||||
| **Namespace** | `dex` |
|
||||
| **Cluster** | k3s (ringtail) |
|
||||
| **Image** | `registry.ops.eblu.me/blumeops/dex:v1.0.0-nix` |
|
||||
| **Upstream** | https://github.com/dexidp/dex |
|
||||
| **Manifests** | `argocd/manifests/dex/` |
|
||||
| **Container build** | `containers/dex/default.nix` |
|
||||
|
||||
## Architecture
|
||||
|
||||
Dex runs on [[ringtail]]'s k3s cluster, isolated from the main services on indri's minikube. This means the IdP is independent of the minikube cluster lifecycle — if minikube goes down, Dex stays up and services can still authenticate once restored.
|
||||
|
||||
```
|
||||
User Browser
|
||||
|
|
||||
v
|
||||
Grafana (indri/minikube) --OIDC--> Dex (ringtail/k3s) --OAuth2--> Forgejo (indri/native)
|
||||
^ |
|
||||
| |
|
||||
+---------------------- redirect back with token -------------------+
|
||||
```
|
||||
|
||||
Cross-cluster communication works because Grafana reaches Dex via `https://dex.ops.eblu.me` (Caddy → Tailscale → ringtail), not k8s-internal DNS.
|
||||
|
||||
## Identity Source
|
||||
|
||||
Dex uses a **Gitea connector** pointed at [[forgejo]] (`https://forge.ops.eblu.me`). Users authenticate with their Forgejo credentials. There are no static passwords — user management happens entirely in Forgejo.
|
||||
|
||||
This means adding a new user to BlumeOps SSO is just creating a Forgejo account.
|
||||
|
||||
## Storage
|
||||
|
||||
SQLite3 with an `emptyDir` volume. This stores refresh tokens and auth codes. A pod restart invalidates active sessions (users re-login), which is acceptable for a homelab. No PVC needed.
|
||||
|
||||
## OIDC Clients
|
||||
|
||||
| Client | Redirect URIs | Status |
|
||||
|--------|---------------|--------|
|
||||
| [[grafana]] | `grafana.ops.eblu.me/login/generic_oauth`, `grafana.tail8d86e.ts.net/login/generic_oauth` | Active |
|
||||
|
||||
Future clients: [[argocd]], [[forgejo]], [[miniflux]], [[zot]]
|
||||
|
||||
## Secrets
|
||||
|
||||
All sensitive configuration is injected via [[external-secrets]] from the "Dex (blumeops)" 1Password item. The entire `config.yaml` is templated in the ExternalSecret — nothing sensitive is committed to git.
|
||||
|
||||
| 1Password Field | Purpose |
|
||||
|-----------------|---------|
|
||||
| `forgejo-client-id` | OAuth2 app client ID from Forgejo |
|
||||
| `forgejo-client-secret` | OAuth2 app client secret from Forgejo |
|
||||
| `grafana-client-secret` | OIDC client secret for Grafana |
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `/.well-known/openid-configuration` | OIDC discovery |
|
||||
| `/auth` | Authorization (browser redirect) |
|
||||
| `/token` | Token exchange |
|
||||
| `/userinfo` | User info |
|
||||
| `/keys` | JWKS (public keys) |
|
||||
| `/callback` | OAuth2 callback from Forgejo |
|
||||
| `/healthz` | Health check |
|
||||
|
||||
## Related
|
||||
|
||||
- [[federated-login]] - How authentication works across BlumeOps
|
||||
- [[forgejo]] - Upstream OAuth2 provider
|
||||
- [[grafana]] - First OIDC client
|
||||
- [[routing]] - How Dex is exposed via Caddy
|
||||
- [[external-secrets]] - Secrets injection from 1Password
|
||||
|
|
@ -77,6 +77,12 @@ The Ansible role authenticates to the Forgejo API using a Personal Access Token
|
|||
|
||||
This is a bootstrapping requirement - the PAT enables IaC for all other secrets.
|
||||
|
||||
## OAuth2 Provider for Dex
|
||||
|
||||
Forgejo acts as the upstream OAuth2 provider for [[dex]], the BlumeOps OIDC identity provider. An OAuth2 application is registered in Forgejo's Site Administration with a redirect URI pointing to Dex's callback (`https://dex.ops.eblu.me/callback`). Client credentials are stored in 1Password ("Dex (blumeops)").
|
||||
|
||||
This means Forgejo accounts are the source of truth for BlumeOps SSO identity. Adding a user to any Dex-integrated service (currently [[grafana]]) is just creating a Forgejo account.
|
||||
|
||||
## Future: Public Access
|
||||
|
||||
Forgejo can be exposed publicly at `forge.eblu.me` via [[flyio-proxy]]. Since Forgejo runs natively on [[indri]] (not in k8s), the pattern is:
|
||||
|
|
@ -98,4 +104,5 @@ See [[expose-service-publicly]] for the full howto and dynamic service checklist
|
|||
## Related
|
||||
|
||||
- [[argocd]] - Uses Forgejo as git source
|
||||
- [[dex]] - OIDC identity provider (Forgejo is the upstream OAuth2 source)
|
||||
- [[zot]] - Container registry for built images
|
||||
|
|
|
|||
|
|
@ -20,6 +20,15 @@ Dashboards and visualization for BlumeOps observability.
|
|||
| **Helm Chart** | grafana (mirrored to forge) |
|
||||
| **Values** | `argocd/manifests/grafana/values.yaml` |
|
||||
|
||||
## Authentication
|
||||
|
||||
Grafana supports two login methods:
|
||||
|
||||
- **SSO via [[dex]]** — federated login through [[forgejo]] (`auth.generic_oauth`). Users click "Sign in with Dex", authenticate at Forgejo, and are redirected back as Admin.
|
||||
- **Local admin** — break-glass login using the password from 1Password ("Grafana (blumeops)"). Always available if Dex is down.
|
||||
|
||||
The OIDC client secret is injected via [[external-secrets]] (`grafana-dex-oauth` secret in monitoring namespace).
|
||||
|
||||
## Datasources
|
||||
|
||||
| Name | Type | Target |
|
||||
|
|
@ -48,6 +57,7 @@ Optional annotation: `grafana_folder: "FolderName"`
|
|||
|
||||
## Related
|
||||
|
||||
- [[dex]] - OIDC identity provider for SSO
|
||||
- [[prometheus]] - Metrics datasource
|
||||
- [[loki]] - Logs datasource
|
||||
- [[alloy|Alloy]] - Data collector
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue