Saltar a contenido

Login con OIDC (SSO)

Con un proveedor de OpenID Connect, las personas entran en kubelatch con la cuenta de la empresa: Google Workspace, Microsoft Entra ID, Okta, Keycloak, Authentik, Auth0 o cualquier otro que publique su documento de descubrimiento. Esta guía registra kubelatch en tu proveedor, conecta los dos y explica cómo da kubelatch con la cuenta de cada persona.

Si tu cluster ya tiene SSO

Muchos clusters ya dejan entrar a la gente con el proveedor de identidad de la empresa: EKS con IAM Identity Center o con un proveedor OIDC propio, AKS con Entra ID, GKE con Google, DOKS con su inicio de sesión único. kubelatch no lo sustituye ni pone otro SSO encima: se suma al mismo proveedor como una aplicación más, igual que Argo CD o Grafana, y cada persona entra con la sesión que ya tiene abierta en el navegador. La excepción es el directorio propio de IAM Identity Center: a las aplicaciones les ofrece SAML, y kubelatch no es compatible con SAML, así que en EKS kubelatch se da de alta en el proveedor que tenga Identity Center detrás (Okta, Entra ID, Google Workspace), y si no hay ninguno se entra con GitHub o con cuentas locales.

El cluster sigue sin ver a la persona. Ve a kubelatch, que entra con su ServiceAccount y suplanta a la persona como user:<login>, con los grupos kubelatch:* de sus permisos, igual que sin OIDC (Arquitectura). Lo que kubelatch añade al SSO del cluster es lo que añade en cualquier sitio: permisos por niveles que caducan, un inventario de credenciales y una fila de auditoría por petición.

Lo que de momento queda aparte es la identidad dentro del cluster: los bindings que tus clusters dan a los usuarios y grupos del proveedor van por un lado y los permisos de kubelatch, por otro. Unirlos es un paso posterior, y kubelatch ya guarda lo que hará falta: la identidad de cada cuenta en el proveedor y su correo verificado.

Qué cambia al activarlo

  • La pantalla de login ofrece «Entrar con {name}», donde {name} es OIDC_DISPLAY_NAME. Si también está activo el login con GitHub, salen los dos botones, primero el del proveedor, y cada persona puede tener una identidad, la otra o las dos.
  • Cada cuenta existente se vincula sola en el primer acceso de su titular, cuando el proveedor garantiza su dirección de correo: lo explica Cómo se vinculan las cuentas. Su login de kubelatch, el que ven los clusters como user:<login>, no cambia.
  • Las contraseñas dejan de valer, salvo las de las cuentas break-glass, que se marcan desde la CLI.
  • No hay alta automática. A quien no tiene cuenta con su correo se le rechaza, y la pantalla de login le dice a quién pedirla, según KUBELATCH_ACCESS_CONTACT. Las cuentas se siguen creando en «Usuarios» (Usuarios y bots).
  • No hay bajas automáticas. Un proveedor de OpenID Connect no le da a kubelatch ninguna lista de miembros. Cuando alguien se va, pulsa «Deshabilitar» en su cuenta, en «Usuarios»: cierra sus sesiones y revoca sus credenciales al momento. Mientras no lo hagas, lo que ya tiene sigue valiendo hasta que caduque, aunque el proveedor haya cerrado su cuenta: la sesión web (12 h), la sesión de la CLI (12 h por defecto) y cada credencial (hasta 30 días por defecto).
  • El doble factor es cosa de tu proveedor. kubelatch apunta cómo se autenticó la persona (los claims amr y acr, si el proveedor los manda) en el evento de cada acceso, pero no exige nada.
  • Funciona igual en Free y en Pro. Vincular no crea cuentas, así que nunca cuenta para el límite de cinco personas de Free.

Antes de empezar

  • Permisos para registrar una aplicación en tu proveedor.
  • kubelatch instalado con https y un administrador que pueda entrar (Instalar).
  • Un correo en cada cuenta de «Usuarios»: la dirección que tiene el proveedor para esa persona, porque es la que usa su primer acceso para vincular la cuenta. Una cuenta sin correo no se vincula sola (Otras formas de vincular).
  • Los comandos usan $MGMT_KUBECONFIG, la ruta al kubeconfig del cluster de gestión (ver Instalar).

Después, prepara una cuenta break-glass.

Hazlo antes de reiniciar con las variables OIDC_*

Desde ese momento ninguna contraseña vale salvo las de las cuentas break-glass. Sin una, nadie podrá entrar hasta que marques una desde la CLI (kubelatch-server user set-break-glass).

Marca a tu administrador actual, o crea una cuenta break-glass solo para emergencias:

kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch exec -it deploy/kubelatch -- /kubelatch-server user set-break-glass admin
# o una cuenta nueva:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch exec -it deploy/kubelatch -- /kubelatch-server user create rescate --admin --break-glass

También es tu forma de entrar cuando el proveedor se cae o su configuración se rompe; la CLI nunca habla con el proveedor. Las cuentas break-glass no tienen doble factor: que sean pocas, con contraseñas largas en el gestor de secretos. Más en Cuentas y recuperación.

Registra kubelatch en tu proveedor

Sea cual sea el proveedor, kubelatch necesita una aplicación de OpenID Connect (según el proveedor, un «cliente» o una «integración») con estos ajustes:

Ajuste Valor
Tipo Una aplicación web con el flujo de código de autorización (authorization code).
URI de redirección <KUBELATCH_BASE_URL>/api/auth/oidc/callback, por ejemplo https://kubelatch.example.com/api/auth/oidc/callback. Hay proveedores que la llaman callback URL o sign-in redirect URI. Tiene que coincidir exactamente.
Scopes openid email profile.
Autenticación del cliente Un secreto para un cliente confidencial, o ninguno para uno público (Cliente público o confidencial).
Firma del ID token RS256, el valor por defecto habitual. kubelatch rechaza cualquier otro algoritmo. Un token sin identificador de clave solo se acepta mientras el proveedor publique una sola clave de firma.

kubelatch manda siempre PKCE (S256), un state y un nonce, y no pide nada más: ni refresh tokens, ni URL de cierre de sesión, ni más permisos de API que los scopes del login. Apunta tres datos para el paso siguiente: el issuer, el client ID y, para un cliente confidencial, el secreto.

El issuer es la URL que identifica al proveedor. kubelatch la compara carácter a carácter con el campo issuer del documento de descubrimiento del proveedor, barra final incluida, así que cópiala de ahí en vez de escribirla a mano. La sección de cada proveedor dice dónde está ese documento; con Google:

curl -s https://accounts.google.com/.well-known/openid-configuration | jq -r .issuer

Configura kubelatch

Variable Valor
OIDC_ISSUER El issuer, tal cual aparece en el documento de descubrimiento. En Entra ID lleva el id de tu tenant (Microsoft Entra ID).
OIDC_CLIENT_ID El client ID.
OIDC_CLIENT_SECRET El secreto del cliente. Déjalo sin definir para un cliente público.
OIDC_ALLOWED_DOMAINS Los dominios de correo de las personas que pueden entrar, separados por comas: acme.com,acme.org. Dominios exactos, sin comodines: un subdominio es otro dominio.
OIDC_DISPLAY_NAME El nombre del proveedor en el botón, hasta 40 caracteres: con Google se lee «Entrar con Google». SSO por defecto.
OIDC_SCOPES openid email profile por defecto. kubelatch no arranca sin openid y email.
OIDC_SUBJECT_CLAIM El claim que identifica a la persona: sub por defecto, oid en Entra ID. Tiene que ser de una sola persona, y el proveedor nunca debe cambiarlo ni pasarlo a otra. Así que kubelatch no arranca con un claim que guarde una dirección o un nombre (email, upn, preferred_username, unique_name, name, phone_number…), uno que compartan muchas personas (tid, hd, iss, aud, idp, locale, groups…), uno del token o de la sesión (nonce, sid, jti…) ni con el claim de OIDC_EMAIL_VERIFIED_CLAIM: una dirección que hereda alguien recién contratado abriría la cuenta de quien la tenía antes, y un valor que comparten todos les abriría a todos la primera cuenta vinculada.
OIDC_EMAIL_VERIFIED_CLAIM El claim que dice que el proveedor ha verificado el correo: email_verified por defecto, xms_edov en Entra ID.
OIDC_AUTOLINK Qué cuentas vincula por correo un primer acceso: all (por defecto), invited u off (La política de vinculación).

Las cuatro primeras activan el login con OIDC. Basta con definir una para que kubelatch exija el issuer, el client ID y los dominios: no arranca mientras falte alguno, y el error enumera todas las variables que faltan. Un secreto suelto también cuenta, para que no pase desapercibido. Las otras cinco, por sí solas, no hacen nada. Todas, con sus formatos, están en Configuración.

En Kubernetes, el cliente va en un Secret y lo demás en el config.oidc del chart:

  1. Pon el cliente en un Secret:

    kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch create secret generic kubelatch-oidc \
      --from-literal=OIDC_CLIENT_ID='<client-id>' \
      --from-literal=OIDC_CLIENT_SECRET='<secreto>'
    

    O añade esas claves a kubelatch-secrets, que el pod ya carga entero. Nunca escribas el secreto como value literal en extraEnv: quedaría en claro en el Deployment. Si tiene que pasar por extraEnv, usa valueFrom.secretKeyRef.

  2. En tus values, carga el Secret y describe el proveedor:

    extraEnvFrom:
      - secretRef:
          name: kubelatch-oidc
    config:
      oidc:
        issuer: https://accounts.google.com
        allowedDomains: [acme.com]
        displayName: Google
    

    config.oidc admite además scopes, subjectClaim, emailVerifiedClaim y autolink (en minúsculas: all, invited u off), y el chart rechaza un issuer sin allowedDomains y al revés. Todos los values están en Valores de Helm.

  3. Ejecuta helm upgrade con esos values, con el Secret y config.oidc en la misma actualización: el client ID por sí solo activa el login con OIDC, y kubelatch no arranca sin el issuer y los dominios. Si añadiste las claves a kubelatch-secrets, actualiza enseguida, porque un reinicio entre medias fallaría. Si cambias el Secret más adelante, el pod no se reinicia solo: hazlo con kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch rollout restart deploy/kubelatch.

  4. Mira el log. Al arrancar, la línea OIDC login enabled muestra el issuer, public_client (true sin secreto), los domains y autolink. Poco después llega OIDC discovery fetched, o el aviso OIDC discovery failed; sign-ins will retry it con el error: kubelatch no espera al proveedor para arrancar, y si aún no tiene el documento, lo pide el siguiente acceso. Si ningún administrador puede entrar, kubelatch arranca igualmente pero registra un error con el comando que lo arregla.
  5. En «Usuarios», una línea dice si kubelatch ha leído el documento de descubrimiento del proveedor: «{name}: descubrimiento leído el {date}.», «{name}: descubrimiento aún sin leer.» o «{name}: la última lectura del descubrimiento falló ({error}).». Un fallo sale también en «Avisos», la campana de la barra superior: «kubelatch no ha podido leer el documento de descubrimiento de {name}: míralo en Usuarios.». Aparece además como comprobación fallida en «Salud de la instalación», dentro de «Edición» (Ediciones y licencia). GET /api/oidc/status (admin) responde lo mismo en JSON.

Cómo se vinculan las cuentas

Una cuenta queda vinculada a una identidad del proveedor: el issuer, el nombre del claim de identidad y su valor (sub, u oid en Entra ID). El correo solo sirve para encontrar la cuenta en el primer acceso. A partir de ahí manda la identidad, y el correo nunca sirve para cambiar una identidad del proveedor por otra.

En el primer acceso de una persona, kubelatch solo acepta el correo si el proveedor lo garantiza (el claim de OIDC_EMAIL_VERIFIED_CLAIM vale true) y su dominio está en OIDC_ALLOWED_DOMAINS. Después busca las cuentas de personas con esa dirección, sin tener en cuenta los espacios de los extremos ni distinguir mayúsculas de minúsculas en las letras de la A a la Z, aunque sí en las demás, como la ñ o las vocales con tilde: una cuenta con Álvaro@acme.com nunca coincide con el álvaro@acme.com del proveedor. Escribe las direcciones de las cuentas en minúsculas, o manda a esa cuenta un enlace de vinculación (Otras formas de vincular). Un bot no se vincula nunca.

Cuentas con ese correo Resultado
Una habilitada Se vincula, si la política lo permite, y entra. Las deshabilitadas con la misma dirección no cuentan.
Ninguna unknown_account: la pantalla de login dice a quién pedir cuenta. No se crea nada.
Dos o más habilitadas ambiguous_account. El evento login.failure trae los logins candidatos en candidates.
Solo deshabilitadas disabled.

Cada vinculación por correo deja un evento oidc.link con via: email, la identidad y cuántos enlaces pendientes de invitación o de restablecimiento de la cuenta ha revocado (invites_revoked), y después el login.success. Una cuenta sin nombre toma el name del proveedor. Una cuenta vinculada a GitHub también se vincula y conserva las dos identidades; una cuenta break-glass se vincula y conserva su contraseña.

Si el correo cambia en el proveedor para la misma identidad, kubelatch actualiza el correo de la identidad y deja oidc.email_changed con from y to. El correo de la cuenta, el que puso un administrador, no cambia.

La política de vinculación

OIDC_AUTOLINK decide qué cuentas puede vincular por correo un primer acceso:

Política Vincula por correo
all (por defecto) Cualquier cuenta habilitada que encuentre la dirección. Es lo que permite apagar las contraseñas sin mandar un enlace a cada persona.
invited Solo las cuentas que nunca han entrado o que tienen un enlace vivo de invitación o de restablecimiento: ambas cosas indican que un administrador espera a esa persona.
off Ninguna: cada cuenta se vincula con un enlace o desde «Mi cuenta» (Otras formas de vincular). Quien no esté vinculado recibe unknown_account.

La red de seguridad de all está en «Avisos»: cada semana avisa a los administradores con «{n} personas han entrado por primera vez con {name} y se han vinculado por su correo esta semana.» y lleva a «Usuarios». Allí, la columna «Entrada» muestra «{name} · {email}» en cada cuenta vinculada y «{name} · aún no ha entrado» en las que no, y la cifra «Vinculadas a {name}» las cuenta. Una vinculación que no esperabas se ve esa misma semana.

Otras formas de vincular

  • El enlace de invitación de una cuenta nueva, o el «Enlace de vinculación» de una existente (en el menú de su ficha en «Usuarios»), lleva a «Vincular con {name} y entrar». Vincula la identidad con la que entre la persona, aunque su dirección no coincida con la de la cuenta (el evento link.complete lleva entonces email_mismatch: true), y sustituye la identidad que tuviera la cuenta: así se cambia la identidad de alguien. Eso sí, la dirección tiene que estar verificada y en un dominio permitido.
  • «Mi cuenta» → «Identidades» → «Vincular con {name}»: para quien ya puede entrar (con GitHub o con una contraseña break-glass) y aún no tiene identidad del proveedor.
  • Una cuenta sin correo, como muchas de las creadas para GitHub, nunca se encuentra por la dirección: usa una de las dos vías anteriores, o ponle el correo por la API (PATCH /api/subjects/{id}, ver API HTTP).

Bajas y direcciones reutilizadas

  • Deshabilita siempre a quien se va: el proveedor no se lo cuenta a kubelatch.
  • Si el proveedor vuelve a crear a alguien (una cuenta nueva para la misma persona, y por tanto otro sub u oid), su siguiente acceso encuentra la identidad antigua en la cuenta y recibe identity_mismatch. Cuando tengas claro que es la misma persona, usa «Desvincular {name}» en el menú de la ficha de la cuenta en «Usuarios»: cierra sus sesiones, y su siguiente acceso la vuelve a vincular por correo, según la política.
  • Si la dirección es ahora de otra persona, no desvincules: deshabilita la cuenta antigua y crea una nueva. Desvincular le entregaría al recién llegado la cuenta antigua con sus permisos.
  • Una cuenta que nunca se vinculó y cuya dirección pasa a otra persona es lo que all no puede distinguir: el primer acceso del recién llegado la vincularía. Deshabilitar las cuentas cuando la gente se va cierra ese hueco; invited lo reduce a las cuentas que nunca han entrado o tienen un enlace vivo.

Cambiar de proveedor o de claim de identidad

Una identidad pertenece al proveedor por su issuer y por el nombre de su claim. Cambiar OIDC_ISSUER (pasar a otro proveedor) u OIDC_SUBJECT_CLAIM (de sub a oid, por ejemplo) convierte las identidades guardadas en identidades de otro proveedor: el siguiente acceso de cada cuenta sustituye su identidad por correo, según la política, y el evento oidc.link dice qué sustituyó (replaced_issuer o replaced_claim). Con invited u off, las cuentas que ya habían entrado necesitan un enlace de vinculación; pasar a all durante el cambio te ahorra uno por persona.

Una identidad del mismo proveedor con otro valor nunca se sustituye por correo: es el identity_mismatch de arriba.

Si apagas el login con OIDC, las identidades se conservan sin uso, y las contraseñas vuelven a valer salvo que esté activo el login con GitHub.

Cliente público o confidencial

  • Confidencial, con OIDC_CLIENT_SECRET: lo normal cuando el cliente es solo de kubelatch. El secreto vive en el Secret y en la memoria de kubelatch, en ningún otro sitio.
  • Público, sin secreto: kubelatch manda solo su client ID y el verificador PKCE, como hacen kubelogin o doctl. Sirve para compartir el cliente con un cluster que confía en el mismo client ID: DOKS, que pide un cliente público, o cualquier apiserver con las opciones --oidc-* o con una AuthenticationConfiguration. Añade la URI de redirección de kubelatch a esa misma aplicación.

En los dos casos, PKCE protege el intercambio del código, y kubelatch nunca guarda los tokens del proveedor: el ID token y el access token viven solo durante la petición del callback y nunca llegan a un log, a un evento ni a la base de datos. Con un cliente compartido con el cluster, ese ID token abriría el apiserver.

No todos los proveedores admiten las dos opciones:

Proveedor Confidencial Público
Google Workspace Siempre. No se puede: un cliente Web application necesita su secreto, aunque haya PKCE.
Microsoft Entra ID Un secreto de cliente, con el callback en Web. El callback en Mobile and desktop applications, con Allow public client flows en No: mira su sección.
Okta Client authentication: Client secret. Una Single-Page Application, el tipo que documenta DigitalOcean para DOKS.
Keycloak Client authentication activado. Client authentication desactivado.
Authentik Client type: Confidential. Client type: Public.
Auth0 Una Regular Web Application. Una Single Page Application, el tipo que documenta DigitalOcean para DOKS.

Sin inicio de sesión desde el proveedor

kubelatch solo acepta los accesos que inicia él mismo: el callback tiene que traer el state y el nonce de un acceso iniciado en kubelatch, así que un inicio de sesión lanzado desde el lado del proveedor, sin petición de kubelatch, no puede completarse. Para poner kubelatch en el portal de aplicaciones del proveedor, haz que su icono apunte al inicio del acceso de kubelatch, que después pasa por el proveedor como siempre:

<KUBELATCH_BASE_URL>/api/auth/oidc/login
  • Entra ID (My Apps): ponla como Home page URL en Branding & properties del registro de la aplicación. Para que aparezca el icono, marca Visible to users? como Yes en Enterprise apps → la aplicación → Properties.
  • Okta (el dashboard): en los ajustes General de la aplicación, Login initiated by: Either Okta or App; Application visibility: Display application icon to users; Login flow: Redirect to app to initiate login (OIDC Compliant); Initiate login URI: la URL de arriba.
  • Cualquier otro portal o marcador funciona igual con esa URL.

Proveedores

Google Workspace

El issuer es https://accounts.google.com, y su documento de descubrimiento, https://accounts.google.com/.well-known/openid-configuration.

  1. En la consola de Google Cloud, usa un proyecto de tu organización y abre Google Auth Platform. Si aún no está configurada, dale a la aplicación un nombre (lo verán las personas al entrar) y un correo de soporte, y elige Internal como audiencia: así solo entran las cuentas de tu organización, y Google rechaza cualquier otra con el error org_internal. Puedes comprobarlo después en Audience.
  2. Clients → Create client → Application type: Web application. En Authorized redirect URIs, añade <KUBELATCH_BASE_URL>/api/auth/oidc/callback y pulsa Create. Google avisa de que una URI nueva puede tardar desde cinco minutos hasta unas horas en funcionar.
  3. Copia el Client ID y el Client secret. Google solo enseña el secreto en ese momento (puedes descargarlo en JSON); después solo muestra sus cuatro últimos caracteres, y si se pierde hay que rotarlo.

En kubelatch:

config:
  oidc:
    issuer: https://accounts.google.com
    allowedDomains: [acme.com]
    displayName: Google

Con Google, además, kubelatch comprueba el claim hd del token, el dominio del Workspace: tiene que venir, estar en OIDC_ALLOWED_DOMAINS y coincidir con el dominio de la dirección. Una cuenta personal de Gmail no trae hd y recibe domain_not_allowed, con «Probar con otra cuenta» para elegir la del trabajo. Con un solo dominio permitido, kubelatch se lo pasa también a Google como pista hd, que orienta el selector de cuentas; lo que decide es el claim del token. Si tu Workspace tiene varios dominios, ponlos todos y prueba una cuenta de cada uno. Un cliente de Google es siempre confidencial.

Microsoft Entra ID

El issuer es https://login.microsoftonline.com/<tenant-id>/v2.0, y su documento de descubrimiento, esa URL seguida de /.well-known/openid-configuration.

  1. En el centro de administración de Microsoft Entra: Entra ID → App registrations → New registration. Ponle un nombre y, en Supported account types, elige la opción de un solo tenant (Single tenant only - <tu tenant>). Register.
  2. En su Overview, copia el Application (client) ID, que es OIDC_CLIENT_ID, y el Directory (tenant) ID, un GUID que va en el issuer. kubelatch no arranca con otra cosa en su lugar: ni common, ni organizations, ni consumers, ni un nombre de dominio como contoso.onmicrosoft.com. Pasa lo mismo con los demás issuers de Microsoft, en login.microsoftonline.us, login.partner.microsoftonline.cn o sts.windows.net.
  3. Authentication → Add Redirect URI → Web: <KUBELATCH_BASE_URL>/api/auth/oidc/callback → Configure.
  4. Certificates & secrets → Client secrets → New client secret: elige su caducidad (24 meses como mucho) y copia su Value, que Entra no vuelve a enseñar. Apunta la fecha: cuando caduque, todos los accesos fallarán con oidc hasta que kubelatch tenga un secreto nuevo.
  5. Token configuration → Add optional claim → ID → email y xms_edov → Add. Si el portal pide activar el permiso email de Microsoft Graph, acepta. xms_edov dice que el dominio de la dirección está verificado, y Entra solo lo manda junto con email. Puedes añadir también amr: kubelatch lo apunta en el evento de cada acceso.

En kubelatch:

config:
  oidc:
    issuer: https://login.microsoftonline.com/<tenant-id>/v2.0
    allowedDomains: [acme.com]
    displayName: Microsoft
    subjectClaim: oid
    emailVerifiedClaim: xms_edov
  • oid identifica a la persona en tu tenant y es el mismo para todas las aplicaciones, mientras que sub cambia con cada registro: volver a registrar la aplicación dejaría huérfanas todas las identidades. Entra solo manda oid con el scope profile, así que mantenlo en OIDC_SCOPES.
  • Entra no manda email_verified. Sin xms_edov, todos los accesos reciben email_unverified, y kubelatch no tiene forma de saltarse esa comprobación.
  • Los invitados (B2B) se quedan fuera solo por OIDC_ALLOWED_DOMAINS: su dirección es del dominio de otra organización, así que reciben domain_not_allowed. xms_edov no los frena, porque Entra también lo manda en true para invitados, por ejemplo los que entran con una cuenta Microsoft, una cuenta de Google o un código de un solo uso. Añade el dominio de otra organización solo si sus invitados deben poder entrar.
  • Para que solo entren algunas personas, pon Assignment required? en Yes en Enterprise apps → la aplicación → Properties, y asígnalas en Users and groups. Microsoft frena al resto antes de que llegue a kubelatch.
  • Si tu tenant no deja que los usuarios den su consentimiento a las aplicaciones, un administrador lo concede una vez para todos: API permissions → Grant admin consent for <tenant>.
  • En un cliente público decide la plataforma de la URI de redirección: Microsoft trata una URI de la plataforma Web como la de una aplicación web confidencial y le pide un client_secret. Así que un cliente público registra el callback en el paso 3 como URI de redirección personalizada en Mobile and desktop applications, y se salta el paso 4. Deja Allow public client flows, en Authentication, en No: ese ajuste (isFallbackPublicClient en el manifiesto) es el tipo de cliente que Entra supone cuando un flujo no lleva URI de redirección, y con Yes se activan para todo el registro la concesión por contraseña (ROPC), el flujo de código de dispositivo y la autenticación integrada de Windows. Un cliente público existe para compartirlo con un cluster que acepta sus ID tokens, así que cada uno de esos flujos sería una forma más de conseguir un token que ese cluster acepta. Esta configuración aún no se ha probado en un tenant real: consulta las guías de Microsoft sobre URIs de redirección y sobre el manifiesto de la aplicación (isFallbackPublicClient, publicClient), y quédate con un cliente confidencial si puedes.

Okta

El issuer es tu dominio de Okta, https://<tu-org>.okta.com, o un servidor de autorización propio, como https://<tu-org>.okta.com/oauth2/default. Los dos publican su documento de descubrimiento en el issuer seguido de /.well-known/openid-configuration.

  1. En la Admin Console: Applications → Applications → Create App Integration (en las consolas nuevas, dentro de Applications and Resources; si pregunta, elige la experiencia clásica). Sign-in method: OIDC - OpenID Connect; Application type: Web Application; Next.
  2. Sign-in redirect URIs: <KUBELATCH_BASE_URL>/api/auth/oidc/callback. Grant type: Authorization Code. En Assignments, elige quién puede usarla. Save.
  3. En Client Credentials, copia el Client ID y, con Client authentication en Client secret, el secreto.

En kubelatch basta con issuer, tal cual aparece en el documento de descubrimiento, allowedDomains y displayName.

En el flujo de código de autorización, Okta emite un ID token reducido: deja fuera claims como email_verified, que da a través de userinfo. kubelatch lo resuelve solo: cuando al ID token le falta el correo o su verificación, consulta userinfo con el access token, comprueba que la respuesta es del mismo sub y toma de ahí el correo y su verificación. No hay nada que configurar, siempre que el scope email esté concedido; con un servidor de autorización propio, su política de acceso tiene que permitir openid, email y profile.

Okta rechaza a quien no está asignado a la aplicación, y kubelatch le muestra el mensaje de denied.

Keycloak

El issuer es https://<host-de-keycloak>/realms/<realm>, y su documento de descubrimiento, esa URL seguida de /.well-known/openid-configuration.

  1. En la consola de administración del realm: Clients → Create client → Client type: OpenID Connect, con un Client ID como kubelatch → Next. Activa Client authentication para un cliente confidencial y deja marcado Standard flow → Next. Valid redirect URIs: <KUBELATCH_BASE_URL>/api/auth/oidc/callback → Save.
  2. Copia el secreto de la pestaña Credentials del cliente.
  3. Deja el scope email entre los Client scopes del cliente, donde está por defecto: es el que trae email y email_verified.

Keycloak tiene que dar las direcciones por verificadas:

  • Un usuario creado a mano necesita Email verified activado.
  • Para los usuarios de LDAP o Active Directory, activa Trust Email en el proveedor de federación de usuarios (viene desactivado), y comprueba después Email verified en un usuario importado. Si no, sus direcciones nunca cuentan como verificadas y todos sus accesos reciben email_unverified.

Trust Email da por verificado lo que contenga el atributo mail del directorio, así que solo es seguro si nadie más que los administradores puede escribir mail. Si cada persona puede editar su propia entrada, alguien podría poner en la suya la dirección de un administrador y, con OIDC_AUTOLINK=all, quedar vinculado a la cuenta de ese administrador en su primer acceso. En ese caso pon OIDC_AUTOLINK en off, como con un True fijo en Authentik.

Si tu Keycloak usa una CA privada, como pasa en muchas instalaciones propias, kubelatch tiene que confiar en ella: pon la CA en un ConfigMap y apunta SSL_CERT_FILE a ella con extraEnv. kubelatch sigue confiando también en las CA públicas.

kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch create configmap idp-ca --from-file=ca.crt=<tu-ca>.pem
extraEnv:
  - name: SSL_CERT_FILE
    value: /etc/kubelatch/idp-ca/ca.crt
extraVolumes:
  - name: idp-ca
    configMap:
      name: idp-ca
extraVolumeMounts:
  - name: idp-ca
    mountPath: /etc/kubelatch/idp-ca
    readOnly: true

extraEnv es para ajustes sin secreto como este. Un secreto como OIDC_CLIENT_SECRET va en el Secret, o en extraEnv solo mediante valueFrom.secretKeyRef: un value literal quedaría en claro en el Deployment. Sin la CA, kubelatch no puede traer el documento de descubrimiento: la línea de «Usuarios» muestra el error del certificado y los accesos fallan con provider_unavailable.

Authentik

El issuer es https://<host-de-authentik>/application/o/<slug-de-la-aplicación>/, con su barra final, y el documento de descubrimiento cuelga de él, en .well-known/openid-configuration.

  1. Applications → Applications → New Application. Ponle un nombre y apunta su Slug, que va en el issuer.
  2. Tipo de proveedor: OAuth2/OpenID Connect. Client type: Confidential. Copia el Client ID y el Client Secret. Añade una Redirect URI de tipo Strict (y Authorization, en las versiones que lo piden): <KUBELATCH_BASE_URL>/api/auth/oidc/callback.
  3. Signing Key: elige un certificado con clave RSA, como el autofirmado que crea authentik. Sin clave de firma, authentik firma con HS256, y con una clave ECDSA tampoco firma con RS256: kubelatch rechaza los dos casos (token).
  4. Deja el Issuer mode del proveedor en su valor por defecto, un issuer por proveedor: kubelatch busca el documento de descubrimiento debajo del issuer.

Desde authentik 2025.10, el mapeo por defecto del scope email manda email_verified en false, porque authentik no verifica las direcciones, así que todos los accesos recibirían email_unverified. La guía de authentik da dos formas de garantizarlas, y las dos acaban en un mapeo de scope propio (Customization → Property Mappings → New Property Mapping → Scope Mapping, con Scope name email) que sustituye al mapeo email por defecto entre los scopes del proveedor:

  • Si tus usuarios llevan su verificación en un atributo booleano email_verified, pásalo tal cual, y quita ese atributo cada vez que cambie la dirección, como pide la guía:

    return {
        "email": request.user.email,
        "email_verified": request.user.attributes.get("email_verified", False),
    }
    
  • Si todavía nadie verifica las direcciones, haz que authentik las verifique con una etapa de correo: la guía trae la etapa, la política y el mapeo.

El otro mapeo de la guía fija "email_verified": True. Úsalo solo con OIDC_AUTOLINK=off o, como mínimo, invited. El propio authentik lo desaconseja si una dirección puede quedarse sin verificar o cambiarse sin verificación, y ese claim es la única prueba que tiene kubelatch de que la dirección es de la persona: con all, cualquiera que pueda elegir su propia dirección en authentik, en un flujo de registro o en sus ajustes de usuario, podría darse de alta como admin@acme.com y quedar vinculado a la cuenta de ese administrador en su primer acceso. Con off, una cuenta solo se vincula con un enlace que mandas tú o desde «Mi cuenta», donde su titular ya ha entrado; invited sigue dejando expuestas las cuentas que nunca han entrado o que tienen un enlace vivo.

Auth0

El issuer es https://<tenant>.<región>.auth0.com/, con su barra final: https://, el Domain de la aplicación y /. Con un dominio propio, es https://<tu-dominio>/. El documento de descubrimiento cuelga de él, en .well-known/openid-configuration.

  1. Applications → Applications → Create Application → Regular Web Applications.
  2. En Settings, copia el Domain, el Client ID y el Client Secret, y añade <KUBELATCH_BASE_URL>/api/auth/oidc/callback a Allowed Callback URLs. Save.
  3. Mantén el ID token firmado con RS256, el valor por defecto, en Advanced Settings → OAuth.

Auth0 solo da una dirección por verificada cuando la persona la ha confirmado (una conexión de base de datos le manda un correo para eso) o cuando la garantiza un proveedor social. Las altas sin verificar reciben email_unverified, y kubelatch no tiene forma de aceptarlas.

Cuando un acceso falla

Un acceso que falla devuelve a la persona a la pantalla de login con un mensaje y deja una fila login.failure en «Auditoría» → «Plano de control» con via: oidc, el código como reason, y el correo y el identificador de la persona en el proveedor cuando se conocen. Hay tres excepciones que no dejan fila: server; state cuando el navegador no trae una cookie de estado válida (ausente, caducada a los diez minutos o de otra sesión); y pulsar «Entrar con {name}» mientras kubelatch no puede conseguir el documento de descubrimiento, que vuelve al momento con provider_unavailable. Los textos nombran al proveedor como lo hace OIDC_DISPLAY_NAME ({name} en la tabla).

Código Lo que lee la persona Qué hacer
rate_limited Demasiados intentos desde esta dirección. Espera un minuto y vuelve a intentarlo. Aquí se aplica también el límite por IP del login con contraseña. Si lo alcanza todo el mundo a la vez detrás de un Ingress, kubelatch ve a todos como una sola IP: configura KUBELATCH_TRUSTED_PROXIES.
state La sesión de inicio con {name} ha caducado o no es válida. Vuelve a intentarlo. El acceso tardó más de 10 minutos o volvió a otro navegador. Si le pasa a todo el mundo, la gente abre kubelatch en un host distinto del de KUBELATCH_BASE_URL, y la cookie del acceso se queda en ese host.
denied Has cancelado el acceso en {name}. La persona canceló en el proveedor, o el proveedor la rechazó (en Okta, alguien no asignado a la aplicación).
oidc {name} no ha respondido como se esperaba. Vuelve a intentarlo en un momento. El proveedor devolvió otro error o se negó a canjear el código: un client ID o un secreto equivocados, un secreto caducado, un cliente público que el proveedor no acepta. El idp_error del evento recoge el error con el que el proveedor devolvió a la persona, y el registro de accesos del proveedor suele dar más detalle.
provider_unavailable kubelatch no puede contactar con {name} ahora mismo. Vuelve a intentarlo en unos minutos; si sigue igual, avisa a un administrador. kubelatch no ha podido llegar al proveedor (el documento de descubrimiento, el endpoint de tokens, las claves o userinfo), o el documento de descubrimiento no es válido. Mira la línea de «Usuarios» y el log: un error de red, una CA en la que kubelatch no confía (Keycloak) o un issuer en el documento distinto de OIDC_ISSUER.
token kubelatch no ha podido verificar la respuesta de {name}. Vuelve a intentarlo; si sigue igual, avisa a un administrador. El ID token no pasó una comprobación (la firma, que tiene que ser RS256; el issuer, la audiencia, azp, la caducidad, el nonce) o le falta el claim de identidad. Causas habituales: un token firmado con HS256 (Authentik sin clave de firma), OIDC_SUBJECT_CLAIM=oid sin el scope profile o un reloj del servidor muy desfasado.
no_email {name} no ha compartido tu dirección de correo con kubelatch. Pide a un administrador que revise la configuración. Ni el ID token ni userinfo traían correo: comprueba que email está en OIDC_SCOPES y concedido a la aplicación (en Entra ID, el claim opcional email) y que la persona tiene dirección en el proveedor.
email_unverified {name} no garantiza tu dirección de correo, así que kubelatch no puede emparejarla con una cuenta. El claim de OIDC_EMAIL_VERIFIED_CLAIM no vale true. Entra ID: el claim opcional xms_edov y la variable. Keycloak: Email verified, o Trust Email para LDAP. Authentik 2025.10 o posterior: el mapeo de email. Auth0: la persona no ha confirmado su dirección.
domain_not_allowed Esa cuenta de {name} no es de un dominio que este kubelatch acepte. ¿Has elegido una cuenta personal? El dominio de la dirección no está en OIDC_ALLOWED_DOMAINS o, en Google, la cuenta no trae hd (una cuenta personal) o trae otro. La pantalla ofrece «Probar con otra cuenta», que pide al proveedor su selector de cuentas. Si el dominio es tuyo, añádelo.
unknown_account Ninguna cuenta de kubelatch tiene la dirección de correo de esa cuenta de {name}. Ninguna cuenta tiene esa dirección, o la política no deja vincularla. Fuera de las letras de la A a la Z, sí se distinguen mayúsculas y minúsculas: Álvaro@acme.com no coincide con álvaro@acme.com (Cómo se vinculan las cuentas). Crea la cuenta en «Usuarios» con ese correo en minúsculas, o manda un enlace de vinculación. La pantalla añade «Para tener cuenta, pídela a {contact}.» si está definido KUBELATCH_ACCESS_CONTACT, y «Probar con otra cuenta».
ambiguous_account Hay más de una cuenta de kubelatch con tu dirección de correo. Pide a un administrador que lo resuelva. El campo candidates del evento enumera las cuentas. Deja la dirección en una sola cuenta habilitada: deshabilita la otra o cámbiale el correo.
disabled Tu cuenta está deshabilitada. La cuenta, o todas las que tienen esa dirección, están deshabilitadas. Pulsa «Habilitar» si la persona debe entrar.
identity_mismatch Tu cuenta de kubelatch está vinculada a otra identidad de {name}. Pide a un administrador que la desvincule. La cuenta que encuentra la dirección ya tiene otra identidad de este proveedor. Si es la misma persona, recreada en el proveedor: «Desvincular {name}». Si es otra persona con una dirección reutilizada, no lo hagas (Bajas y direcciones reutilizadas).
oidc_taken Esa cuenta de {name} ya está vinculada a otra cuenta de kubelatch. Esa identidad ya abre otra cuenta. Búscala en «Usuarios», donde «Entrada» muestra la dirección, y desvincúlala antes si la vinculación está mal.
already_linked Tu cuenta de kubelatch ya está vinculada a otra identidad de {name}. Pide a un administrador que la desvincule primero. Desde «Mi cuenta»: la cuenta ya tiene una identidad de este proveedor. Usa antes «Desvincular {name}», si el cambio es intencionado.
link_gone El enlace ha caducado o ya se ha usado; pide uno nuevo a un administrador. Genera otro enlace de invitación o de vinculación.
server Error interno al completar el acceso con {name}. Vuelve a intentarlo. Un error interno: mira el log del servidor.

Comprueba que funciona

Con la aplicación registrada y kubelatch reiniciado con las variables:

  • GET /api/auth/methods responde "oidc": true con tu oidc_name, y el login muestra «Entrar con {name}».
  • En «Usuarios», la línea del proveedor dice «{name}: descubrimiento leído el {date}.».
  • La cuenta break-glass entra desde «Entrar con contraseña». La contraseña de una cuenta normal ya no entra (401 genérico y login.failure con reason: password_disabled).
  • En una ventana privada, alguien que tiene cuenta con su dirección pulsa «Entrar con {name}» y acaba en «Inicio» con la sesión iniciada. En «Auditoría» → «Plano de control» hay un oidc.link con via: email y un login.success con via: oidc; en «Usuarios», su «Entrada» dice «{name} · {email}».
  • Esa persona cierra sesión y vuelve a entrar: un login.success nuevo, y ningún segundo oidc.link.
  • En su ordenador, kubelatch login abre el navegador, pasa por el proveedor si hace falta y acaba en la aprobación de siempre (La CLI).
  • Con una cuenta de fuera de tus dominios, como un Gmail personal, la pantalla dice «Esa cuenta de {name} no es de un dominio que este kubelatch acepte. ¿Has elegido una cuenta personal?» y ofrece «Probar con otra cuenta»; con alguien sin cuenta, «Ninguna cuenta de kubelatch tiene la dirección de correo de esa cuenta de {name}.». Los dos casos dejan un login.failure con su reason.
  • GET /api/oidc/status (admin) muestra configured, issuer, domains, autolink, public_client y discovery con su fetched_at.

Si falla otra cosa, mira Solución de problemas.