## 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
89 lines
3.3 KiB
Markdown
89 lines
3.3 KiB
Markdown
---
|
|
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
|