Files
Portainer/PROMPT-SSO-ISSUE.md
2026-07-25 11:20:27 +00:00

7.6 KiB

Prompt: SSO OIDC + Forward Auth — Diagnostico y alternativas

Contexto

Proyecto en /home/felidae/Portainer_repo/. Infraestructura Docker Compose con:

  • Traefik v3.6.13 como reverse proxy (red proxy)
  • Authentik como SSO via Forward Auth (ths-authentik@docker)
  • CrowdSec como IPS/IDS via plugin Traefik (crowdsec-bouncer@file)
  • Homepage como dashboard (descubre labels Docker)

Se han levantado dos nuevos servicios que necesitan SSO con Authentik + enlaces compartidos publicos (sin login):

Servicio Dominio Imagen
OpenGist opengist.sherlockhomeless.net ghcr.io/thomiceli/opengist:latest (puerto 6157)
OneTimeSecret ots.sherlockhomeless.net onetimesecret/onetimesecret:latest (puerto 3000, necesita Redis)

Que funciona

  1. DNS: registros A creados con cloudflared/add-domain.sh apuntando a 193.70.84.224
  2. Traefik: rutas TLS con Let's Encrypt para ambos dominios
  3. CrowdSec: bouncer activo, bloqueando IPs en todos los routers
  4. Forward Auth: redirige a Authentik al visitar las URLs raiz (302 a /application/o/authorize/)
  5. Enlaces compartidos publicos: las rutas de gist (/{user}/{gist}) y secretos (/secret/*, /private/*) evitan Authentik correctamente
  6. Callbacks OIDC: las rutas /auth/* (OTS) y /oauth/* (OpenGist) evitan Authentik, llegan al backend
  7. Homepage: labels Docker puestos, descubre ambos servicios

Routers Traefik configurados

OpenGist (opengist/docker-compose.yml):

Router 1 (prio 20, SIN Authentik):
  Host(opengist.sherlockhomeless.net) && (PathRegexp(^/[a-z...]+/[a-z0-9]+) || PathPrefix(/oauth/))
  → crowdsec-bouncer@file

Router 2 (prio 10, CON Authentik):
  Host(opengist.sherlockhomeless.net)
  → crowdsec-bouncer@file, ths-authentik@docker

OTS (onetimesecret/docker-compose.yml):

Router 1 (prio 20, SIN Authentik):
  Host(ots.sherlockhomeless.net) && (PathPrefix(/secret/) || PathPrefix(/private/) || PathPrefix(/auth/))
  → crowdsec-bouncer@file

Router 2 (prio 10, CON Authentik):
  Host(ots.sherlockhomeless.net)
  → crowdsec-bouncer@file, ths-authentik@docker

Donde se rompe

Problema principal

El usuario visita la URL, Authentik pide login (Forward Auth funciona), pero tras autenticarse en Authentik la app no reconoce al usuario como logueado. La app muestra su propio formulario/boton de login.

La causa raiz es la diferencia entre Forward Auth y reconocimiento de sesion dentro de la app:

  • Forward Auth: protege la RUTA a nivel HTTP. Authentik verifica si la peticion tiene sesion valida. Si no, redirige al login. Si si, deja pasar la peticion y añade headers (X-Authentik-Username, etc.).
  • La app: tiene su propio sistema de sesiones. No sabe leer los headers X-Authentik-*. Necesita su propio flujo OIDC/OAuth para crear una sesion interna.

Para cerrar ese gap se configuro OIDC en ambos servicios apuntando a Authentik:

App OIDC Provider (Authentik) Redirect URI Config en la app
OpenGist pk=45, client_id=MZb3LrTP... /oauth/callback OG_OIDC_CLIENT_ID, OG_OIDC_CLIENT_SECRET, OG_OIDC_ISSUER
OTS pk=46, client_id=Bqd0erWf... /auth/oidc/callback OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_ISSUER, AUTH_SSO_ENABLED=true, AUTHENTICATION_MODE=full, AUTH_SECRET=...

Sintoma actual reportado por el usuario

En https://ots.sherlockhomeless.net/signin aparece el boton "Sign in with Authentik". Al hacer clic estando ya logueado en Authentik, no cambia nada, sigue pidiendo sign in. El flujo OIDC aparentemente no completa la creacion de sesion en OTS.

Posibles causas:

  1. La cookie de sesion de Authentik no se envia en el callback (problema de dominio/cookie SameSite)
  2. El callback OIDC falla en OTS (error de configuracion Rodauth/OmniAuth)
  3. Forward Auth interfiere en alguna parte del flujo (aunque las rutas de callback ya se excluyeron)
  4. La sesion de Authentik no persiste entre Forward Auth y OIDC

Otros detalles tecnicos

  • Authentik: el dominio es auth.sherlockhomeless.net. Los providers OIDC usan issuer por provider (issuer_mode: per_provider). Issuer OpenGist: https://auth.sherlockhomeless.net/application/o/MZb3LrTP.../ Issuer OTS: https://auth.sherlockhomeless.net/application/o/Bqd0erWf.../

  • OTS healthcheck: la imagen oficial tiene un healthcheck built-in (bin/healthcheck.sh) que falla en nuestro entorno. Se deshabilito con healthcheck: { disable: true } porque Traefik se niega a rutear contenedores unhealthy.

  • OTS full auth: requiere AUTH_SECRET (valor generado con openssl rand -hex 48), SQLite en /app/data/auth.db (montado en /opt/onetimesecret/data:Z, uid 1001), y Redis para los datos de la app.

  • OpenGist: usa OG_OPENGIST_HOME=/opengist con SQLite interno. No requiere base de datos externa.


Archivos clave

Portainer_repo/
├── opengist/
│   ├── docker-compose.yml
│   └── .env
├── onetimesecret/
│   ├── docker-compose.yml
│   └── .env
├── authentik/
│   ├── docker-compose.yml
│   ├── create-auth-app.sh
│   └── .env
├── Traefik/docker-compose.yml
├── crowdsec/docker-compose.yml
├── cloudflared/
│   ├── add-domain.sh
│   └── .env
└── NUEVA-APP.md         (guia de despliegue de nuevas apps)

Credenciales OIDC en Authentik

Obtenibles via API con token generado desde docker exec ths-authentik-server:

# OpenGist OIDC provider (pk=45)
curl -sk -H "Authorization: Bearer $TOKEN" \
  https://auth.sherlockhomeless.net/api/v3/providers/oauth2/45/

# OTS OIDC provider (pk=46)
curl -sk -H "Authorization: Bearer $TOKEN" \
  https://auth.sherlockhomeless.net/api/v3/providers/oauth2/46/

Objetivo para el siguiente agente

Conseguir que el flujo SSO funcione de extremo a extremo:

  1. Usuario visita https://opengist.sherlockhomeless.net/ o https://ots.sherlockhomeless.net/
  2. Authentik muestra su pagina de login (Forward Auth) — esto YA funciona
  3. Usuario se autentica en Authentik
  4. Al volver a la app, el usuario aparece logueado automaticamente (la app reconoce al usuario via OIDC sin requerir clic extra)
  5. Los enlaces compartidos (/{user}/{gist}, /secret/*) siguen siendo publicos (sin login) — esto YA funciona

Ideas a explorar

  • Alternativa A — Quitar Forward Auth, usar solo OIDC: si las apps soportan auto-redirect al provider OIDC cuando no hay sesion, se elimina la doble autenticacion. El login seria "clic en boton" en vez de "automatico al entrar", pero el SSO seria mas limpio.

  • Alternativa B — Authentik en modo proxy (no forward auth): configurar Authentik como reverse proxy real en vez de forward auth. Authentik manejaria todo el flujo OIDC y pasaria el usuario autenticado al backend.

  • Alternativa C — Header auth nativo: investigar si OpenGist u OTS soportan autenticacion por headers de proxy inverso (tipo Remote-User). Si es asi, se puede usar solo Forward Auth sin OIDC, pasando el header X-Authentik-Username como Remote-User.

  • Alternativa D — Autentik OAuth2 en vez de OIDC: probar si el flujo OAuth2 simple (sin OpenID Connect) funciona mejor con estas apps.

  • Alternativa E — Debug del flujo OIDC actual: revisar logs de OTS (docker logs onetimesecret) y de Authentik durante el flujo OIDC para identificar exactamente donde falla el callback. Puede ser un problema de SameSite cookie, CORS, o redirect_uri mismatch.