blumeops/docs/reference/services/dex.md
Erich Blume cdb0c923f8 Add Dex OIDC documentation and services-check integration
- Create Dex reference card (docs/reference/services/dex.md)
- Write federated login explanation article
- Add Dex to services-check (HTTP health + k3s pod)
- Update Grafana docs with SSO authentication section
- Update Forgejo docs with OAuth2 provider role
- Add Dex to ringtail workloads table and reference index
- Move adopt-oidc-provider plan to completed with final design

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:43:08 -08:00

3.3 KiB

title modified tags
Dex 2026-02-19
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