Saltar a contenido

Solución de problemas

Síntomas habituales al operar kubelatch, su causa y cómo arreglarlos. Los problemas de quien usa una credencial están en Si algo falla, y todos los mensajes de error en Errores.

Para localizar una petición concreta, usa la cabecera Audit-ID de la respuesta (kubectl -v=8 la muestra). Es el id de la fila en «Auditoría», el audit_id de cada línea que kubelatch escribe en el log sobre esa petición y el que recibe el cluster en su propia auditoría. Para la API y la interfaz web, la cabecera es X-Request-Id: ver El log del servidor.

Instalación y arranque

Síntoma Causa Solución
El pod no arranca y el log lista errores de configuración kubelatch valida todas las variables al arrancar y muestra todos los errores juntos. Corrígelos en values.yaml (config) o en los Secrets, y ejecuta helm upgrade. Detalle de cada variable en Configuración.
helm install falla con postgres.mode=cnpg needs the CloudNativePG operator (o needs cert-manager, needs the Barman Cloud Plugin) El chart comprueba que existe la API del operador antes de crear nada. Instala lo que nombra el mensaje: CloudNativePG (Instalar el operador), cert-manager (su guía de instalación; o usa un certificado propio, ver Instalar) o el Barman Cloud Plugin (Copias de seguridad). Con helm template, pasa --api-versions con la API que nombra el mensaje.
helm install o helm upgrade falla con postgres.cnpg.bootstrap.<method>.database must be kubelatch (or left out) (o .owner), o con postgres.cnpg.bootstrap.<method>.secret is not supported La restauración o la importación nombra otra base de datos, otro dueño o su propio Secret. kubelatch conecta con el Secret kubelatch-db-app, que CloudNativePG solo escribe para la base de datos y el dueño del bootstrap, y no escribe en absoluto cuando el bootstrap nombra su propio secret. Deja fuera database, owner y secret: el chart pone kubelatch. Ver Restaurar desde una copia.
helm install o helm upgrade falla con secrets.existingSecret … already has KUBELATCH_ENCRYPTION_KEY: secrets.generateEncryptionKey is only for new installs; keep using the key in secrets.existingSecret (removing it would make the chart generate a different key and seal every cluster token) secrets.generateEncryptionKey está activado, pero kubelatch ya tiene una clave en su Secret. Una clave generada la sustituiría, y los tokens de los clusters sellados con ella dejarían de funcionar. Desactiva secrets.generateEncryptionKey y conserva la clave en secrets.existingSecret. No la quites del Secret. Ver La clave de cifrado.
postgres.cnpg.bootstrap takes exactly one method o the method must be one of initdb, recovery or pg_basebackup postgres.cnpg.bootstrap tiene más de un método, o uno desconocido. Deja uno solo: initdb, recovery o pg_basebackup.
El Cluster de la base de datos se queda en la fase Unable to create required cluster objects e ignora los cambios de su spec, y el operador CloudNativePG registra cannot create Cluster auxiliary objects y ValidatingAdmissionPolicy 'kubelatch-bindings' … denied request La política de endurecimiento de la 0.59.0 o anterior rechaza el RoleBinding del operador a su Role kubelatch-db. La base de datos sigue funcionando. Instala la política actual: La política de endurecimiento y CloudNativePG.
KUBELATCH_KUBECONFIG_CA: … contains a … block El fichero tiene algo más que certificados, por ejemplo una clave privada. Apunta solo al ca.crt (o al tls.crt si es autofirmado).
KUBELATCH_TRUSTED_PROXIES: … is not a CIDR o … is broader than the minimum Una IP suelta, o un prefijo más amplio que /8 (IPv4) o /16 (IPv6). Usa CIDR (10.0.0.1/32) y el rango más estrecho posible.
GITHUB_APP_PRIVATE_KEY: not a PEM private key La variable no tiene el PEM completo, con sus cabeceras, o se perdieron los saltos de línea. Crea el Secret con --from-file=GITHUB_APP_PRIVATE_KEY=<fichero>.pem.
… is required when GitHub login is configured Hay alguna variable GITHUB_* pero faltan otras. Pon las cinco obligatorias, o quita todas. Ver Login con GitHub.
El pod no arranca y los errores de configuración nombran variables OIDC_* Hay alguna de OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET y OIDC_ALLOWED_DOMAINS pero falta una obligatoria, o un valor incumple su regla: un issuer http fuera de loopback, un issuer de Microsoft Entra ID sin el id del tenant (common, organizations, consumers o un nombre de dominio), un dominio con comodín, scopes sin openid o sin email, un claim de identidad que puede cambiar, como email o upn. Pon OIDC_ISSUER, OIDC_CLIENT_ID y OIDC_ALLOWED_DOMAINS (y OIDC_CLIENT_SECRET para un cliente confidencial), o quita las cuatro. Cada regla está en Configuración.
/readyz responde 503 database unavailable Postgres no responde. Revisa DATABASE_URL y la red hasta Postgres. Mientras tanto, el proxy responde 503; las sesiones abiertas no se cortan.
tls: reload failed tras renovar el certificado El par certificado-clave nuevo es inconsistente, o cert-manager aún no ha escrito los dos ficheros. kubelatch sigue con el anterior. Espera a la siguiente comprobación (10 s). Si persiste, revisa el Secret kubelatch-tls.
tls: the served certificate expires soon Quedan menos de 30 días. Renueva el certificado; kubelatch lo recarga sin reiniciar.
… but no admin can log in Activaste el login con GitHub u OIDC sin cuenta break-glass ni un admin que pueda entrar con él. Con OIDC, sale también hasta que un admin entra por primera vez y queda vinculado. kubelatch-server user set-break-glass <login>: ver Cuentas y recuperación.

Ingress y red

Síntoma Causa Solución
kubectl get pods -w, logs -f o exec se cortan a los 60 s detrás de un Ingress Faltan los timeouts del controlador: otro controlador, o las anotaciones del chart sustituidas en ingress.annotations. Usa exposure: ingress con ingress-nginx, o los ajustes equivalentes de tu controlador: Ingress. Con un LoadBalancer L4 no ocurre.
helm install o helm upgrade falla con exposure=ingress needs networkPolicy.enabled: kubelatch serves plain HTTP on 8080 and trusts X-Forwarded-For from config.trustedProxies, so only the Ingress controller may reach it exposure: ingress con networkPolicy.enabled: false. Detrás del Ingress, kubelatch escucha en HTTP plano y acepta el X-Forwarded-For de config.trustedProxies: sin la NetworkPolicy, cualquier pod de ese rango podría llegar a él y falsificar la IP de la auditoría. Pon networkPolicy.enabled: true y networkPolicy.ingressControllerNamespace con el namespace de tu controlador. Ver Ingress.
helm install o helm upgrade falla con ingress.host (…) must match the host of config.baseURL (…): kubelatch only knows one public host ingress.host y el host de config.baseURL no coinciden. Pon en ingress.host exactamente el host de config.baseURL. Ver Ingress.
helm install o helm upgrade falla con tls.certManager.enabled and an ingress cert-manager annotation both request a Certificate for the same secretName: keep only one source of the TLS secret Tanto el Certificate del chart como una anotación cert-manager.io/…issuer en ingress.annotations rellenarían kubelatch-tls. Deja solo una: desactiva tls.certManager.enabled o quita la anotación. Ver Ingress.
kubectl apply de un manifiesto grande responde 413 El límite de cuerpo del controlador (1 MiB por defecto). proxy-body-size: "0".
Toda la auditoría muestra la misma IP, o el login responde 429 a todo el mundo Falta KUBELATCH_TRUSTED_PROXIES con el CIDR del controlador. Ver Proxies de confianza.
La API responde 403 cross-origin request rejected El navegador envía un Origin distinto de KUBELATCH_BASE_URL. Sirve la interfaz desde esa misma URL. Revisa que KUBELATCH_BASE_URL coincida con la URL pública.
Un rollout cortó un exec o un port-forward Es lo esperado: al parar, kubelatch cierra los streams tras 3 s. Relanza el comando. kubectl reintenta solo los watch. Ver Actualizar.

Clusters y reconciliación

Síntoma Causa Solución
El comando de enrolamiento imprime kubelatch: waiting for the token of … (up to a minute)... y, al cabo de un minuto, kubelatch: the token of … does not show up in namespace kubelatch-system Kubernetes no rellenó los Secrets de los tokens en ese cluster. El script imprimió el contexto que usó (enrolling cluster "…" with kubectl context "…"): un KUBECONFIG vacío cae en ~/.kube/config, así que puede ser el cluster equivocado. Vuelve a ejecutar el comando, con el mismo enlace, con el kubeconfig correcto o --context <nombre>.
El one-liner («Hacerlo a mano») imprime waiting for the token of … in kubectl context "…" y, al cabo de un minuto, the token of … does not show up: did you apply the manifest in this context? El bootstrap no está aplicado en el cluster de ese contexto. Aplica el bootstrap y ejecuta el one-liner con el mismo KUBECONFIG.
El comando imprime kubelatch: this enrollment link is invalid or expired; generate a new one in Clusters, o GET /api/enroll/… y la API responden 404 con enrollment.invalid El enlace ya se usó, caducó (dura una hora), se invalidó o lo sustituyó un comando más reciente. También deja de servir cuando el administrador que lo generó queda deshabilitado o pierde el rol de admin, y kubelatch lo revoca tras 10 intentos rechazados (tokens que no pudo validar), para que un enlace filtrado no le haga llamar a otras direcciones sin fin. Abre la página del cluster en «Clusters» y genera otro comando en su tarjeta «Enrolar» («Generar un comando nuevo»); en un cluster enrolado, elige antes «Reenrolar» en su menú, que abre la tarjeta del reenrolamiento.
El comando imprime kubelatch: no terminal to confirm on: rerun with --yes Pide confirmación en /dev/tty y no hay terminal (CI, una sesión remota sin tty). Ejecútalo con --yes: curl … \| sh -s -- --yes.
El comando imprime curl: (60) SSL certificate problem o unable to get local issuer certificate El certificado de kubelatch es de una CA que curl no conoce (una CA privada). Indica a curl la CA: CURL_CA_BUNDLE=/ruta/ca.crt, junto a KUBECONFIG en la subshell.
El comando imprime kubelatch: kubelatch refused the tokens: … API server unreachable … kubelatch no llega a la dirección del API server que envió el script (la de tu kubeconfig, si no pusiste otra). Vuelve a ejecutarlo, con el mismo enlace, con --server <url que kubelatch alcance>, o genera el comando de nuevo con esa dirección en «URL del API server para kubelatch» (bajo «Opciones avanzadas»). Ver Clusters privados.
El comando imprime kubelatch: kubectl has no current context: pass --context <name> El kubeconfig no tiene contexto actual. Añade --context <nombre> después de sh -s --.
400 … el token pertenece a …, se esperaba … Los tokens del JSON están cruzados o son de otro cluster. Vuelve a ejecutar el comando de enrolamiento (o el one-liner) con el kubeconfig correcto.
400 la ServiceAccount … no tiene el permiso …: aplica el manifiesto bootstrap de nuevo al enrolar o pegar el JSON El bootstrap no está aplicado entero, o es de otra versión. Los tokens no se guardaron. Vuelve a ejecutar el comando de enrolamiento (aplica el manifiesto), o, a mano, descarga el bootstrap de nuevo, aplícalo y pega el JSON con «Guardar tokens».
Aplicar el bootstrap falla con no matches for kind "ValidatingAdmissionPolicy" in version "admissionregistration.k8s.io/v1" El cluster tiene un Kubernetes anterior a la 1.30. La política de admisión del manifiesto, que acota al reconciliador, necesita la 1.30. Actualiza el cluster a Kubernetes 1.30 o superior.
Cluster en «Error» con bootstrap incomplete: the cluster has the reconciler's new rights but not the admission policy kubelatch-reconciler-jail: apply the bootstrap manifest again Alguien borró la política kubelatch-reconciler-jail o su binding. kubelatch no escribe ningún rol personalizado en ese cluster, ni borra ninguno, hasta que vuelva. Aplica el bootstrap de nuevo (Actualizar el bootstrap) y pulsa «Reconciliar».
Cluster en «Error» con custom roles are granted on this cluster but it has the previous bootstrap: apply the bootstrap manifest again El cluster tiene el manifiesto anterior, que no admite roles personalizados. Los niveles del sistema siguen funcionando. Actualiza el bootstrap y pulsa «Reconciliar».
Cluster en «Error» con custom role <id> no longer passes validation and was not applied: edit or delete it El rol lleva algo que kubelatch ahora rechaza (una versión posterior endureció una regla). Sus permisos no tienen efecto en ningún cluster. Abre el rol en «Roles» con «Editar»: el constructor muestra qué corregir. O elimínalo. Ver Roles.
Cluster en «Error» con … denies the operation to the kubelatch-reconciler ServiceAccount: apply the bootstrap manifest again Al reconciliador le falta algún permiso del bootstrap. Aplica el bootstrap de nuevo y pulsa «Reconciliar».
El cluster está en «Error» La última reconciliación falló; el motivo sale en la página del cluster, con «Ver el error completo» para el resto (API server unreachable, … apply the bootstrap manifest again, un namespace que ya no existe…). Corrige la causa. kubelatch reintenta con espera creciente; «Reconciliar» fuerza una pasada. Un namespace borrado con permisos vigentes deja el «Error» hasta revocarlos.
«Reconciliar» responde 502 El cluster sigue fallando. El mensaje trae el motivo.
«Reconciliar» responde 409 Ya hay otra pasada en curso, o el cluster está «Sin enrolar». Espera unos segundos, o enrola el cluster (Registrar un cluster).
reconciler: pass failed … terminating connection due to idle-in-transaction timeout El idle_in_transaction_session_timeout de Postgres es menor que una pasada. Súbelo por encima de 3 minutos o desactívalo para el rol de kubelatch.
La etiqueta de Pod Security de un namespace cambió, o el namespace se borró, y sus permisos tardaron minutos en dejar de valer La vigilancia de los namespaces de ese cluster está caída, así que solo se enteró la pasada de cada 10 minutos (La reconciliación). El log de cada réplica dice namespace watch down con la causa: a la ServiceAccount del reconciliador le falta el permiso watch sobre los namespaces (cannot watch resource "namespaces": alguien editó el bootstrap), o un proxy o un balanceador delante del API server corta o retiene las peticiones largas (not opened within 1m0s). namespace watch: cannot build the cluster's client quiere decir que no se pueden leer los tokens del cluster. Aplica el bootstrap de nuevo (Actualizar el bootstrap), o deja pasar las peticiones largas por ese proxy: la vigilancia de kubelatch, como kubectl get -w, se queda abierta hasta 10 minutos. Si son los tokens, rótalos («Reenrolar»). namespace watch up dice que ha vuelto; mientras tanto, «Reconciliar» aplica un cambio al momento.
409 … (¿cambió KUBELATCH_ENCRYPTION_KEY?) …, o rotate the cluster's tokens en el error del cluster La clave de cifrado cambió o se perdió. Rota los tokens de cada cluster («Reenrolar»): Actualizar.

El comando de enrolamiento imprime el texto error del servidor en inglés (kubelatch: kubelatch refused the tokens: …), sea cual sea el idioma de la interfaz; la interfaz web muestra el mensaje traducido.

Enrolar un cluster con tu identidad

El panel muestra estos mensajes en el idioma de la interfaz, bajo «El enrolamiento con tu identidad no terminó» o como error de «Continuar en …» (Enrolar con tu identidad); el «Qué significa este fallo» del fallo lleva aquí. Los mensajes del propio acceso son los del login con OIDC.

Síntoma Causa Solución
La opción «Con mi identidad (…)» aparece desactivada, con «Tu cuenta no está vinculada a …. Vincúlala en Mi cuenta.», o tu cuenta no está vinculada al proveedor de identidad: vincúlala en Mi cuenta, o usa el script Tu cuenta no tiene vinculada ninguna identidad del proveedor configurado: es una cuenta break-glass, o una que nunca ha entrado con el proveedor. Vincúlala en «Mi cuenta», o usa el script.
kubelatch no tiene la CA de este cluster: pégala Elegiste «kubelatch corre dentro de este cluster» y kubelatch no tiene la CA montada: un chart antiguo, clusterCA.mount: false, o un kubelatch fuera de Kubernetes. Pega la CA, o deja clusterCA.mount en true y ejecuta helm upgrade (Qué instala el chart).
este cluster aún no tiene dirección ni CA guardadas: elige dónde está Se pidió «Donde ya está» para un cluster sin URL del API server ni CA guardadas: nunca se enroló, o su registro cambió entretanto. Elige «kubelatch corre dentro de este cluster» u «Otro cluster» y da la CA.
la dirección de este cluster cambió después de que la página la enseñara: comprueba dónde está y vuelve a intentarlo «Donde ya está» nombraba una dirección que el cluster ya no tiene guardada: otra persona administradora la cambió (tokens nuevos pegados, un enrolamiento en otro sitio) después de que cargara tu página. No se creó nada y el token no salió. Comprueba la dirección que el panel enseña ahora en «Donde ya está» y continúa.
con «donde ya está» kubelatch usa la URL y la CA guardadas: no envíes otras Un cliente de la API envió in_place con una URL, una CA o in_cluster. El panel nunca lo hace. Envía in_place solo, o la URL y la CA sin él.
hay un enrolamiento con la identidad de una persona administradora en marcha en este cluster; espera a que termine kubelatch está aplicando el manifiesto con el token de una persona administradora, y un enrolamiento en marcha no se detiene a medias. «Cancelar», «Invalidar», «Generar comando» y un enrolamiento nuevo reciben este 409. Espera: tarda como mucho dos minutos, y el panel dice cómo terminó.
el API server no acepta el token de … para el cliente …: haz que confíe en ese cliente y comprueba que el token lleva los claims que mapea (como un correo verificado), o usa el script El API server respondió 401 a tu ID token: no confía en ese issuer, o no con el client ID de kubelatch como audiencia, o al token le falta un claim que el cluster mapea (el correo, o su email_verified es false). No se escribió nada. Haz que el cluster confíe en el cliente de kubelatch, o mapea un claim que el ID token lleve (Configurar el cluster), o usa el script.
el apiserver de … presentó un certificado que la CA no firma La CA no es la que firma el certificado de ese API server: es la de otro cluster, o la de un proxy que tiene delante. El token no se envió. Pega la CA de ese API server: el comando de solo lectura imprime la que usa tu kubeconfig.
el cluster usa Kubernetes 1.29.4; kubelatch necesita 1.30 o posterior La política de admisión del bootstrap necesita Kubernetes 1.30. No se escribió nada. Actualiza el cluster.
el apiserver te ve como oidc:bruno@acme.com (grupos oidc:developers) y esa identidad no puede create clusterrolebindings Al nombre que te da el API server le falta un permiso que el manifiesto necesita. No se escribió nada. Dale cluster-admin a ese usuario, o a uno de esos grupos, con un ClusterRoleBinding en el cluster, o usa el script.
no se pudo aplicar …/…: el apiserver respondió … El API server rechazó un objeto del manifiesto: un webhook de admisión, o la política de endurecimiento, que responde 403 a un bootstrap que crea o cambia sus ClusterRoleBindings. Lo anterior se queda aplicado. Corrige la causa y pulsa «Intentar de nuevo»: volver a aplicar es idempotente. Con la política de endurecimiento, quita antes su binding (Endurecer el cluster).
los tokens de las ServiceAccounts no aparecieron en un minuto Kubernetes no rellenó los dos Secrets de token de kubelatch-system. «Intentar de nuevo». Si se repite, revisa el controller manager del cluster, que es quien los rellena.
Un motivo de Qué valida kubelatch, como proxyToken: el token pertenece a …, se esperaba … Los tokens de las ServiceAccounts no validaron. «Intentar de nuevo»: vuelve a aplicar el manifiesto.
«Has entrado en … con una identidad distinta de la vinculada a tu cuenta (…). Vuelve a intentarlo con esa.» Has entrado en el proveedor con una cuenta que no es la vinculada a tu cuenta de kubelatch. «Intentar de nuevo» con la identidad vinculada; si el proveedor tiene abierta otra sesión, ciérrala allí antes.
«El enrolamiento caducó, o lo sustituyó otro, antes de que volvieras de …. Empieza de nuevo.» Pasaron más de 10 minutos en el proveedor, o mientras tanto alguien empezó otro enrolamiento del cluster o canceló este. «Intentar de nuevo».

Permisos y proxy

Síntoma Causa Solución
kubectl responde Forbidden aunque el permiso existe La reconciliación aún no ha pasado. Si el cluster dice cannot impersonate, kubelatch-proxy aún no incluye a esa persona. Mira el estado del cluster y su línea reconciliado hace … en «Clusters», o pulsa «Reconciliar».
403 … has no active permissions on cluster Sin ningún permiso vigente en ese cluster (revocados o caducados). Concede el permiso en «Permisos».
403 this credential is restricted to cluster … La credencial se emitió para otro cluster. Emite otra sin restricción o para ese cluster.
403 the account is disabled El sujeto está deshabilitado. «Habilitar» en «Usuarios» y emitir credencial nueva.
401 credential revoked o credential expired Las credenciales no se reactivan. Emitir otra.
400 kubelatch does not accept Impersonate-* headers Se usó kubectl --as. No está soportado: ver Comprobar qué puede hacer alguien.
400 invalid path: empty segments, '.' or '..' or escaped characters… La ruta lleva //, ., .. o algún % (un nombre codificado por el cliente). kubectl no codifica nombres válidos; con curl u otras herramientas, pon el nombre sin codificar.
502 could not talk to the cluster's API server: … kubelatch no llega a la URL registrada. Revisa la red o el túnel (Clusters privados). El error completo está en el log.
503 kubelatch cannot query its database Postgres no responde o, si solo pasa en un cluster, sus tokens no se descifran (log proxy: load cluster). Revisa Postgres, o rota los tokens.
GET /api/audit responde 400 Un filtro no es válido; el mensaje dice cuál. subject y credential son uuid, cluster un slug, from/to RFC 3339 con from anterior, page entre 1 y 10000.

Filas de auditoría con estado 499 o 403 sin motivo aparente: ver Auditoría.

Cuentas

Síntoma Causa Solución
El login responde 429 demasiados intentos 5 fallos seguidos (bloqueo de 15 min) o más de 10 intentos por minuto desde esa IP. El log dice cuál: login: account locked (y login: refused, account locked mientras dura) o login: rate limited, con el login y client_ip. Espera, o «Restablecer acceso» en la cuenta, en «Usuarios», o kubelatch-server user set-password.
Nadie puede entrar Contraseña olvidada, cuenta bloqueada o único admin deshabilitado. La CLI por kubectl exec: Cuando nadie puede entrar.
Nadie puede entrar tras configurar GITHUB_* u OIDC_* Solo las cuentas break-glass conservan la contraseña. kubelatch-server user set-break-glass <login> y entra desde «Entrar con contraseña».
409 al quitar el rol o deshabilitar a un admin Es el último administrador que puede entrar. Nombra antes otro admin.

Login con GitHub

Síntoma Causa Solución
GitHub muestra redirect_uri is not associated with this application La Callback URL de la App no coincide exactamente con <KUBELATCH_BASE_URL>/api/auth/github/callback. Corrige esquema, host, puerto y barra final en la App.
app not installed in the organization en el log de la sincronización La App no está instalada, o GITHUB_ORG no es el login exacto de la organización. Instálala y revisa GITHUB_ORG.
Todo el mundo ve «Tu cuenta de GitHub no es miembro activo de la organización.» (not_member) La App no tiene Organization → Members: read, o la organización no es la de GITHUB_ORG. Revisa los permisos de la App y GITHUB_ORG.
no_2fa al entrar La organización no exige 2FA. Actívalo en GitHub y espera hasta 10 minutos (caché). Si de verdad no quieres exigirlo, GITHUB_REQUIRE_ORG_2FA=false.
«Esa cuenta de GitHub no está vinculada a ninguna cuenta de kubelatch. Pide a un administrador un enlace de vinculación.» (unknown_account) No hay alta automática. Crea la cuenta o genera un «Enlace de vinculación».
github_taken al vincular Esa cuenta de GitHub ya está vinculada a otra persona. «Desvincular GitHub» en la otra cuenta primero.
membership sync: pass failed; nobody was disabled Error de GitHub, App desinstalada o cero miembros. Revisa el mensaje. La siguiente pasada lo reintenta.
El webhook responde 401 invalid signature El secreto de la App y GITHUB_WEBHOOK_SECRET no coinciden. Corrígelo. GitHub reintenta entregas desde la pestaña Advanced de la App.
El webhook responde 415 El webhook no usa Content type: application/json. Cámbialo en la configuración del webhook de la App.
El webhook responde 413 La entrega supera 1 MiB. No debería ocurrir con entregas normales de GitHub.
El webhook responde 404 Falta GITHUB_WEBHOOK_SECRET. Configúralo, o desactiva el webhook en la App.

Login con OIDC

{name} es el nombre del proveedor, OIDC_DISPLAY_NAME. Todos los mensajes que una persona puede leer en la página de login están en Cuando un acceso falla, con qué hacer.

Síntoma Causa Solución
El proveedor rechaza la URI de redirección (redirect_uri_mismatch, invalid redirect_uri o parecido) La URI de redirección registrada en el proveedor no coincide exactamente con <KUBELATCH_BASE_URL>/api/auth/oidc/callback. Corrige esquema, host, puerto y barra final en el proveedor.
Todo el mundo ve «kubelatch no puede contactar con {name} ahora mismo. Vuelve a intentarlo en unos minutos; si sigue igual, avisa a un administrador.» (provider_unavailable) y el log dice oidc login failed con code provider_unavailable (al arrancar, OIDC discovery failed; sign-ins will retry it) kubelatch no puede leer el documento de descubrimiento del proveedor (<OIDC_ISSUER>/.well-known/openid-configuration), sus claves o su endpoint de tokens: un OIDC_ISSUER equivocado, un cortafuegos entre el pod y el proveedor, el proveedor caído o un certificado de una CA privada. «Usuarios» y «Avisos» muestran el último error. Revisa OIDC_ISSUER, escrito exactamente como lo publica el proveedor (barra final incluida), y que el pod llega al proveedor por https. Con una CA privada, monta su certificado y apunta SSL_CERT_FILE a él, como explica la sección Keycloak. kubelatch vuelve a intentarlo en el siguiente acceso, como mucho una vez por minuto.
Todo el mundo ve «kubelatch no ha podido verificar la respuesta de {name}. Vuelve a intentarlo; si sigue igual, avisa a un administrador.» (token) El id_token no pasa la verificación: no va firmado con RS256, su iss no es exactamente OIDC_ISSUER, su aud no incluye OIDC_CLIENT_ID, le falta el claim de OIDC_SUBJECT_CLAIM o el reloj del servidor va desviado más de 30 s. La línea oidc login failed del log (con code token) trae la causa en err. Corrige la variable, haz que el proveedor firme los ID tokens con RS256 o corrige el reloj.
«{name} no ha compartido tu dirección de correo con kubelatch. Pide a un administrador que revise la configuración.» (no_email) Ni el id_token ni el userinfo del proveedor traen una dirección de correo. Haz que el proveedor entregue email a este cliente (en Entra, el claim opcional email): ver la sección del proveedor en Proveedores.
«{name} no garantiza tu dirección de correo, así que kubelatch no puede emparejarla con una cuenta.» (email_unverified) El claim que nombra OIDC_EMAIL_VERIFIED_CLAIM no es true para esa persona. Entra necesita OIDC_EMAIL_VERIFIED_CLAIM=xms_edov y ese claim opcional; Keycloak, Trust Email para los usuarios que vienen de LDAP, si su mail solo lo escriben los administradores; authentik 2025.10 o posterior, un mapeo de email que pase una verificación real, no un True fijo. Ver Proveedores.
«Esa cuenta de {name} no es de un dominio que este kubelatch acepte. ¿Has elegido una cuenta personal?» (domain_not_allowed) El dominio del correo no está en OIDC_ALLOWED_DOMAINS (exacto: un subdominio solo vale si está en la lista) o, con Google, el claim hd falta o nombra otro dominio. La persona elige su cuenta de empresa («Probar con otra cuenta»), o añades el dominio a OIDC_ALLOWED_DOMAINS.
«Ninguna cuenta de kubelatch tiene la dirección de correo de esa cuenta de {name}.» (unknown_account) Una cuenta tiene ese correo, pero OIDC_AUTOLINK no deja vincularla: off, o invited y la cuenta ya ha entrado antes y no tiene enlace pendiente. Quien no tiene ninguna cuenta con su correo llega a «Pedir unirse», o una regla de dominio lo da de alta (Acceso por dominio y solicitudes de alta). Genera un «Enlace de vinculación».
Alguien con cuenta llega a «Pedir unirse» Ninguna cuenta tiene su correo tal como lo manda el proveedor: fuera de las letras de la A a la Z, sí se distinguen mayúsculas y minúsculas (Álvaro@acme.com no es álvaro@acme.com), y una cuenta sin correo nunca se encuentra por él. Corrige el correo de la cuenta (en minúsculas) o genera un «Enlace de vinculación», y deniega la solicitud.
«Hay más de una cuenta de kubelatch con tu dirección de correo. Pide a un administrador que lo resuelva.» (ambiguous_account) Dos o más cuentas habilitadas tienen ese correo. El evento login.failure las lista en candidates. Cambia el correo de las que no son de la persona, o deshabilítalas.
«Tu cuenta de kubelatch está vinculada a otra identidad de {name}. Pide a un administrador que la desvincule.» (identity_mismatch) La cuenta con ese correo está vinculada a otra identidad del proveedor: se volvió a crear la cuenta de la persona en el proveedor, o la dirección es ahora de otra persona. Si es la misma persona, «Desvincular {name}» en la cuenta (Desvincular la identidad OIDC) y se vuelve a vincular en su siguiente acceso. Si la dirección ha pasado a otra persona, no desvincules: deshabilita la cuenta del dueño anterior y crea otra para la persona nueva.
«Esa cuenta de {name} ya está vinculada a otra cuenta de kubelatch.» (oidc_taken) Esa identidad ya abre otra cuenta de kubelatch. «Desvincular {name}» en la otra cuenta primero.

CI con GitHub Actions

Síntoma Causa Solución
El intercambio responde 401 invalid token El id_token no pasa la verificación: firma, iss, aud distinto de KUBELATCH_BASE_URL, caducado o jti ya canjeado. El motivo está en el log (ci: token rejected reason=…, o ci: token replayed si el jti ya se canjeó) y en el plano de control (ci.exchange.failure). Típico: la url de la action (o KUBELATCH_URL, sin la action) no es el KUBELATCH_BASE_URL del servidor, el token se canjeó dos veces, o el reloj del servidor va desviado más de 30 s.
403 no trust rule matches this workflow … No hay regla para ese repositorio, ref y environment. El mensaje trae repository_owner_id, repository_id, ref y environment: crea la regla con esos valores, o quita la ref o el environment.
403 que nombra al bot El bot está deshabilitado o no tiene permisos activos. Habilítalo o concédele permisos.
429 Más de 60 intercambios por minuto desde la misma IP. Reduce la frecuencia.
could not reach kubelatch en el workflow (curl: (7) o (35) sin la action) El runner no llega a kubelatch por https, o no confía en su certificado. Hace falta un nombre alcanzable desde los runners y un certificado en el que confíen: con una CA privada, su certificado en el almacén del sistema del runner o en NODE_EXTRA_CA_CERTS, en el env del job. KUBELATCH_KUBECONFIG_CA hace que los pasos siguientes del job también confíen en él.

El log del servidor

kubelatch escribe un objeto JSON por línea en la salida estándar (kubectl logs); con KUBELATCH_LOG_FORMAT=text, pares clave=valor. Al arrancar escribe listening con la versión, la dirección y si TLS y el login con GitHub están activos. Con OIDC configurado, escribe además OIDC login enabled, con el issuer, si el cliente es público, los dominios y la política de vinculación, y después OIDC discovery fetched u OIDC discovery failed; sign-ins will retry it.

Cada petición fuera de /clusters/ (la API, las sondas, el intercambio de CI y el webhook de GitHub) deja una línea http request, salvo los ficheros de la interfaz web:

{"time":"2026-10-02T17:32:41.767Z","level":"INFO","msg":"http request","method":"GET","route":"GET /api/me","status":200,"duration_ms":3,"bytes":412,"client_ip":"203.0.113.7","subject_id":"01999c1e-5b7a-7d43-9a51-3c2f0e8d4a10","request_id":"01a0fd3f-08a7-744c-8bad-6e34fc981ad1"}
  • route es el patrón de la ruta de la API, nunca la ruta pedida ni su query: ningún id ni token de una URL llega al log.
  • request_id es la cabecera X-Request-Id de la respuesta (las herramientas de desarrollo del navegador la muestran). Cualquier otra línea que escriba esa petición también lo lleva, como la causa de un 500 (request failed). El id lo genera kubelatch; el que envíe el cliente se ignora.
  • subject_id aparece cuando una sesión o un token de la CLI autenticó la petición.
  • /healthz y /readyz se registran en DEBUG.
  • El proxy no escribe líneas http request: cada petición de kubectl ya es una fila en «Auditoría». Las líneas que escribe sobre una petición (proxy: upstream error, proxy: load cluster…) llevan audit_id, el Audit-ID de la respuesta.
  • Los bloqueos y límites de frecuencia se registran en WARN con client_ip y el login (login: account locked, login: rate limited, ci: exchange rate limited…). Una contraseña, un código o un token no aparecen nunca.
  • Un acceso con OIDC fallido escribe oidc login failed con kind, code (el código del ?error= de la página de login) y err, la causa. Los tokens del proveedor, el código que devuelve y el secreto del cliente no aparecen nunca.

Para ver más, pon config.logLevel: debug en values.yaml (KUBELATCH_LOG_LEVEL) y ejecuta helm upgrade: el cambio reinicia los pods. debug añade una línea por cada sondeo, así que vuelve a info al terminar. warn deja solo avisos y errores.

Qué vigilar

kubelatch no expone /metrics todavía. Con lo que hay:

  • /readyz en tu monitorización externa: 503 significa Postgres inaccesible.
  • El log en JSON (kubectl logs): tls: the served certificate expires soon, tls: reload failed, reconciler: pass failed (con el cluster y el motivo), namespace watch down (con el cluster y la causa; namespace watch up cuando vuelve), namespace watch: cannot build the cluster's client, retention: pass failed, membership sync: pass failed, OIDC discovery failed; sign-ins will retry it, oidc login failed, ci: token rejected, login: account locked, login: rate limited.
  • GET /api/clusters: status y last_error de cada cluster (lo mismo que «Clusters»).
  • GET /api/oidc/status: discovery.error, la última lectura fallida del documento de descubrimiento del proveedor (lo mismo que «Usuarios»).
  • GET /api/control-events: varios login.failure seguidos desde una misma IP.