Saltar a contenido

Modelo de seguridad

Qué garantiza kubelatch, qué no, y en qué se apoya cada garantía. Léelo antes de conceder permisos o de poner kubelatch en producción. Los mecanismos en sí se explican en Identidad, Roles de sistema y El viaje de una petición; esta página solo dice qué te dan y dónde se acaban.

Qué protege y qué no

kubelatch controla quién llega a los API servers a través de él, con qué identidad y qué queda registrado. En concreto:

  • Cada petición lleva una credencial propia, revocable al instante y con caducidad.
  • El cluster ve a la persona real (user:<login>, o el nombre que le da la plantilla de identidad del cluster) y solo los grupos de sus permisos activos.
  • Cada petición queda registrada antes de llegar al cluster, con un identificador que la correlaciona con la auditoría nativa del cluster.
  • La ServiceAccount del proxy no puede suplantar a nadie fuera de lo que kubelatch concede.
  • Las reglas de un entorno limitan los permisos de las personas y de los grupos, nunca los de los bots: un bot que necesite acceso permanente a prod lo recibe con un permiso directo.
  • Un permiso sobre un conjunto de clusters no da nunca acceso privilegiado, porque un conjunto crece solo: donde el rol o el nombre es privilegiado, el permiso no llega a ese cluster, y quien lo necesite allí lo recibe a mano, con sus 8 horas.

kubelatch no protege:

  • Lo que ocurre dentro de un namespace que ya está concedido: la frontera real es el namespace (ver Roles de sistema).
  • El acceso nativo a los clusters (identidades cloud, kubeconfigs de administrador, tokens de ServiceAccount sacados de un pod). Eso queda en la auditoría nativa del cluster, no en la de kubelatch.
  • La base de datos frente a quien tiene su rol de Postgres, ni la clave de cifrado frente a quien lee los Secrets del cluster de gestión.
  • Las cargas de trabajo: kubelatch no está en su camino.
  • Lo que un agente de IA hace por otra vía hacia un cluster que no sea el servidor MCP de kubelatch, y lo que hace con el contenido que lee (ver Agentes de IA).

Credenciales: tokens klt_

Una credencial es un token opaco: klt_ seguido de 32 bytes aleatorios en base64url.

  • kubelatch guarda solo su SHA-256 y los 12 primeros caracteres visibles (klt_ + 8), que sirven para reconocerla en el inventario y en la auditoría sin poder usarla. El token tiene 256 bits de entropía, así que un hash simple basta: no hay diccionario que probar.
  • El token y el kubeconfig se muestran una sola vez, en una respuesta que el navegador no guarda en caché. La interfaz no los guarda en el almacenamiento del navegador ni en la URL.
  • No hay caché de autorización: cada petición al proxy comprueba la credencial, así que una revocación surte efecto en la petición siguiente. Los streams abiertos se cortan en 10 s como máximo.
  • La caducidad es obligatoria: 30 días como máximo para personas y 90 para bots por defecto (KUBELATCH_MAX_TTL_USER, KUBELATCH_MAX_TTL_BOT). Las de CI duran 1 h por defecto (KUBELATCH_CI_TOKEN_TTL).

Los enlaces de invitación y vinculación (kli_…) siguen el mismo esquema: un solo uso, caducidad y solo se guarda su hash.

Sesiones de la CLI

kubelatch login termina en una credencial de tipo cli: un token klt_ como los demás, con el mismo inventario, la misma revocación inmediata y la misma auditoría. Lo que la distingue:

  • Dura 12 h (KUBELATCH_CLI_SESSION_TTL, nunca más que KUBELATCH_MAX_TTL_USER) y no se renueva sola.
  • Vale en todos los clusters donde la persona tenga permisos, y se emite aunque no tenga ninguno: kubelatch status lo dice y el proxy responde 403 como con cualquier credencial.
  • Solo existe para personas con la cuenta habilitada, nunca para bots, y solo después de que la persona apruebe la petición en la web con su propia sesión.
  • Además del proxy, la API la acepta como Authorization: Bearer, pero solo para autoservicio: tu perfil, tus propias credenciales y cerrar sesión (las rutas exactas están en la API HTTP). Cualquier otra ruta responde 403 cli.scope. Nunca actúa como administrador, aunque la persona lo sea: no crea permisos, clusters ni usuarios, ni aprueba otro login de la CLI.
  • No aparece nunca en pantalla: va de la API a un fichero 0600 (session.json) y de ahí a kubectl por el exec plugin. El kubeconfig no lleva ningún secreto.

La aprobación en la web es la defensa contra el phishing. Una petición de acceso vive 10 minutos; sus códigos son 32 bytes aleatorios, de un solo uso, y solo se guarda su hash. El flujo del navegador (PKCE con S256) solo redirige a http://127.0.0.1:<puerto> en la máquina que lo empezó, con el state de la propia CLI.

Con --device, quien tenga un código y consiga que se apruebe se queda con la sesión. Por eso la página de aprobación avisa de aprobar solo un kubelatch login que acabes de ejecutar, y por eso los códigos erróneos tienen un límite por persona y por IP. Cada aprobación, rechazo y login deja un evento cli.approve, cli.deny o cli.login en «Auditoría» → «Plano de control».

El proxy y su ServiceAccount

  • Sin cookies. El proxy solo acepta Authorization: Bearer klt_… e ignora las cookies, así que una página web no puede usar tu sesión contra un cluster.
  • Sin Impersonate-* del cliente. Cualquier cabecera Impersonate-* entrante se rechaza con 400. kubelatch ya usa la suplantación con la ServiceAccount kubelatch-proxy; dejar pasar una suplantación anidada permitiría a cualquiera pedir ser otro. Por eso kubectl --as no está soportado. Para probar «qué puede hacer X», usa el acceso nativo de administrador: kubectl auth can-i --as user:x --as-group kubelatch:ns:apps:viewer.
  • Audit-ID propio. El proxy genera el suyo y nunca respeta el del cliente.
  • Rutas estrictas. Rechaza segmentos ., .., vacíos y cualquier escape, para que nada se decodifique dos veces por el camino.
  • ServiceAccount acotada. kubelatch-proxy solo puede suplantar a los usuarios y grupos de la lista que mantiene el reconciliador: los sujetos con permisos activos y los grupos de esos permisos. Un fallo en el proxy no puede llegar a system:masters ni a nadie a quien kubelatch no haya concedido algo.
  • Nombres con prefijo. user: y bot: evitan colisiones con identidades nativas del cluster.
  • Una frase en un 403. Cuando el cluster rechaza una petición, el proxy añade una frase a su mensaje: el rol que la permitiría y dónde pedirlo (403 — sin permiso). No revela nada nuevo: el namespace es el de la petición, el modelo de cada rol es fijo, kubelatch no consulta el cluster, no nombra permisos de nadie más y un rol personalizado que nombra es uno que la persona podría pedir. Cualquier otra respuesta del cluster, y toda respuesta a un bot, pasa tal cual, y la auditoría guarda el 403 del cluster.

El reconciliador y su ServiceAccount

La ServiceAccount kubelatch-reconciler sí es equivalente a cluster-admin por diseño: tiene que poder crear el binding de cluster-admin. Nunca está en el camino de una petición de cliente. Sus escrituras están acotadas, lo que limita errores, no el privilegio.

Su ClusterRole puede escribir ClusterRoles y bindings con cualquier nombre: el ClusterRole de un rol personalizado, kubelatch-role-<id>, tiene un nombre que nadie conoce de antemano, y RBAC no puede limitar una regla a un prefijo de nombre. La cota es la política de admisión kubelatch-reconciler-jail, una ValidatingAdmissionPolicy (Kubernetes 1.30 o superior) que el manifiesto bootstrap crea antes que ese ClusterRole. Solo mira las peticiones del reconciliador, y rechaza:

  • cualquier ClusterRole, Role o binding cuyo nombre no empiece por kubelatch-;
  • el ClusterRole y el ClusterRoleBinding del propio reconciliador, kubelatch-reconciler;
  • el binding del proxy, kubelatch-proxy;
  • un binding a algo que no sea un ClusterRole (nunca a un Role de namespace, se llame como se llame), o a cualquier ClusterRole que no sea un nivel o un rol personalizado de kubelatch, admin o cluster-admin; nunca a kubelatch-reconciler ni a kubelatch-proxy.

La ServiceAccount puede leer la política, pero no cambiarla ni borrarla. La política acota los errores, y hasta dónde llega por nombre un kubelatch comprometido; no es una frontera de privilegio. Mira los nombres y el roleRef de un binding, no los sujetos ni las reglas: un token del reconciliador robado todavía puede vincularse a sí mismo a cluster-admin con un ClusterRoleBinding kubelatch-*, y un ClusterRole kubelatch-* con una de las etiquetas de agregación de Kubernetes (rbac.authorization.k8s.io/aggregate-to-admin, por ejemplo) suma sus reglas a los roles propios de Kubernetes. El reconciliador sigue siendo equivalente a cluster-admin, por diseño.

Cada reconciliación comprueba que la política y su binding están en su sitio y siguen denegando: no cuenta una política que deja pasar la petición que no puede evaluar, ni un binding que solo avisa o que estrecha lo que cubre la política. Si no, la reconciliación no escribe ningún rol personalizado, no borra ninguno y deja el cluster en «Error» hasta que se vuelva a aplicar el manifiesto. Entre que alguien borra la política y esa pasada, 10 minutos como mucho, las escrituras del reconciliador solo las acota el propio código de kubelatch. Un cluster con el manifiesto anterior no tiene política: su reconciliador solo puede escribir una lista fija de nombres, suficiente para los niveles del sistema pero no para los roles personalizados. Actualizar el bootstrap explica cómo pasarlo al actual.

La frontera de namespace

Dentro de un namespace concedido, kubelatch no puede separar nada: quien crea pods alcanza sus Secrets y sus ServiceAccounts. Por eso developer, debugger y admin exigen Pod Security Admission, y por eso los namespaces del sistema no admiten ningún permiso. Roles de sistema explica la frontera y sus consecuencias.

Endurecimiento opcional: bindings a kubelatch-*

Un admin de namespace, concedido por kubelatch o nativo, puede crear un RoleBinding a kubelatch-developer para el sujeto que quiera. Ese binding no da acceso a través de kubelatch, porque el proxy solo suplanta a quien tiene permisos vigentes. Pero un sujeto con una credencial nativa ganaría ese rol de forma nativa, y el binding confunde al reconciliador, que registra en el log los bindings que no son suyos pero llevan los nombres que gestiona.

El chart trae otra ValidatingAdmissionPolicy (Kubernetes 1.30+), distinta de la jaula del reconciliador, que solo deja a la ServiceAccount kubelatch-reconciler crear o cambiar bindings a un ClusterRole cuyo nombre empiece por kubelatch-; los Roles de namespace quedan libres. Se aplica en cada cluster gestionado, con el kubeconfig de ese cluster. La política también deniega a un administrador los bindings del propio bootstrap, así que mover el cluster a otra instancia o registrarlo de nuevo exige quitarla un momento. Cómo instalarla: Endurecer el cluster.

Tokens de los clusters, cifrados

Los tokens de las dos ServiceAccounts de cada cluster son las llaves del reino. kubelatch los guarda cifrados con AES-256-GCM bajo KUBELATCH_ENCRYPTION_KEY y nunca los muestra. Cada token va ligado a su cluster y a su papel (proxy o reconciliador), así que un token cifrado no sirve en otro cluster ni en el otro papel.

El enlace del comando de enrolamiento (kle_…) es un secreto al portador: quien lo tenga puede registrar tokens en ese cluster. Su vida es corta a propósito: sirve una sola vez, caduca a la hora, muere tras 10 intentos que no pasan la validación, lo sustituye cualquier enlace nuevo para el mismo cluster y solo funciona mientras el administrador que lo creó siga siendo un administrador habilitado. Viaja en la URL, así que el log de acceso de un reverse proxy delante de kubelatch puede registrarlo; kubelatch guarda solo su hash y sus propios logs nunca lo registran. La página del cluster muestra la caducidad de un enlace pendiente y el motivo del último intento fallido, nunca el comando, que solo tiene la pestaña que lo generó; el motivo lleva los dos tokens recortados. Los tokens van en el cuerpo de un POST enviado por stdin, nunca en una URL ni en los argumentos de un proceso.

La misma clave firma también las cookies de sesión y las cookies de estado del login con GitHub y con OIDC. Si se pierde o se rota, todo el mundo vuelve a iniciar sesión y hay que rotar los tokens de cada cluster. Las contraseñas y las credenciales klt_ no dependen de ella.

Guarda la clave aparte

La clave de cifrado no está en Postgres. Un backup de la base de datos sin la clave no permite usar los tokens de los clusters; con la clave, sí. Guárdalas por separado.

Enrolar con la identidad de un administrador

Cuando un administrador enrola un cluster con su identidad, kubelatch usa el ID token que le da su proveedor solo en la petición que lo trae de vuelta, solo contra la URL y la CA de ese enrolamiento, por TLS verificado y sin seguir redirecciones, y solo para aplicar el bootstrap; no lo guarda nunca. La identidad tiene que ser la vinculada a su cuenta, y el enrolamiento está atado a su navegador, a su sesión y a su rol de admin, con un solo intento en 10 minutos.

kubelatch no pide nunca un kubeconfig ni ninguna credencial de administrador de un cluster: solo la URL del API server y su CA, que no son secretos. La API no tiene dónde recibir un kubeconfig, y uno pegado por error se borra sin enviarse. Una página web no puede defenderse de una extensión del navegador que tiene permiso sobre ella. Si alguna te preocupa, hay dos defensas fuera de la página: una ventana privada, donde las extensiones no se ejecutan salvo que lo permitas, y, en una empresa, la política ExtensionSettings de Chrome y Edge con el host de kubelatch en runtime_blocked_hosts ({"*": {"runtime_blocked_hosts": ["*://kubelatch.example.com"]}}), que deja todas las extensiones fuera de kubelatch. Esa política protege también la sesión del administrador, no solo esta pantalla.

El chart monta el ConfigMap kube-root-ca.crt del cluster, que solo lleva su CA: no da ningún permiso, y el pod sigue sin token de ServiceAccount.

Proxies de confianza y la IP de origen

La IP de origen de la auditoría y los limitadores por IP (login, acceso desde la CLI, canje de CI y fallos de autenticación del proxy) usan la dirección de la conexión TCP. Detrás de un Ingress u otro proxy L7, esa dirección es la del proxy.

KUBELATCH_TRUSTED_PROXIES dice de qué redes se acepta X-Forwarded-For, leído de derecha a izquierda hasta el primer salto que no es de confianza. Solo admite CIDR: una IP suelta impide el arranque, y un prefijo más amplio que /8 en IPv4 o /16 en IPv6 también.

  • No pongas rangos que alcance un cliente: podría elegir la IP con la que aparece en la auditoría y esquivar los límites.
  • Detrás de un Ingress, confía solo en las IP de los pods del controlador. Un CIDR de pods de todo el cluster convierte cada pod en un proxy de confianza. Por eso el chart, con exposure: ingress, trae una NetworkPolicy que solo admite tráfico desde el namespace del controlador, y necesita un CNI que aplique NetworkPolicy.
  • Detrás de un LoadBalancer de capa 4 con externalTrafficPolicy: Local, déjalo vacío.

Los limitadores agrupan IPv6 por /64, para que rotar direcciones dentro del prefijo no multiplique los intentos. Con dos réplicas, cada una cuenta sus límites por IP en memoria; el bloqueo de cuenta tras 5 fallos sí es global.

Contraseñas y sesiones

  • Contraseñas de 12 a 128 caracteres, distintas del login, sin reglas de composición, con hash argon2id.
  • 5 fallos seguidos bloquean la cuenta 15 minutos, y cada IP tiene 10 intentos por minuto. La respuesta es la misma para login inexistente, contraseña errónea o cuenta deshabilitada, y tarda lo mismo.
  • Todo intento de login, bueno o malo, queda en «Auditoría» → «Plano de control» con la IP. La excepción es un login de más de 64 caracteres: recibe el mismo 401 sin llegar a la base de datos ni quedar registrado.
  • Cambiar la propia contraseña en «Mi cuenta» tiene su propio límite: 10 intentos por minuto por cuenta, y cada fallo queda registrado.
  • Sesiones de 12 h en una cookie firmada, revocables todas a la vez. Las mutaciones de la API tienen protección contra peticiones de otro origen.
  • La interfaz web y la API responden con una Content-Security-Policy estricta (scripts solo del propio kubelatch), X-Frame-Options: DENY, X-Content-Type-Options: nosniff y Referrer-Policy: same-origin, así que ninguna otra página, ni siquiera una de un subdominio hermano, puede enmarcar una pantalla como la aprobación de dispositivo de la CLI. Con una KUBELATCH_BASE_URL https se añade además Strict-Transport-Security. Las respuestas bajo /clusters/ conservan las cabeceras del propio cluster.

Con una URL base https, las cookies de sesión y de estado llevan el prefijo __Host- (__Host-kubelatch_session, __Host-kubelatch_github_state, __Host-kubelatch_oidc_state): Secure, Path=/ y sin Domain, así que un host hermano bajo el mismo dominio no puede colar una sesión suya en tu navegador, por ejemplo en la página de aprobación de la CLI. Una cookie sin el prefijo se ignora.

Tras 5 fallos, el 429 confirma que el login existe, y cualquiera puede bloquear una cuenta 15 minutos. Se acepta para una herramienta interna; el límite por IP lo encarece.

Identidad con GitHub

Con la GitHub App configurada, la identidad de las personas es la de GitHub. El flujo está descrito en Identidad; aquí, lo que supone para la seguridad:

  • Doble factor. kubelatch no lo implementa: se apoya en el que impone la organización. Solo puede comprobarlo si la App tiene Organization → Administration: read; sin ese permiso, avisa y confía. Activa el 2FA obligatorio en GitHub antes que nada.
  • Contraseñas. Con GitHub activo, solo entran con contraseña las cuentas break-glass, que no tienen doble factor. Que sean pocas, con contraseñas largas en un gestor, y para usar solo cuando GitHub no está disponible. Los hashes de las demás cuentas siguen en la base de datos pero no sirven para entrar.
  • Bajas. Quien sale de la organización se deshabilita solo (webhook firmado o sincronización cada hora). La sincronización nunca deshabilita ante un error de GitHub y nunca rehabilita. El TTL máximo de las credenciales acota lo que un fallo prolongado de ambas vías podría dejar abierto.
  • El flujo OAuth. state aleatorio en una cookie firmada de 10 minutos. El código se canjea en el servidor con el client secret, y el token de GitHub de la persona se descarta tras el login. No se usa PKCE: GitHub no lo documenta para GitHub Apps y kubelatch es un cliente confidencial, para el que state más client secret es lo que exige la BCP de OAuth 2.0. Los tokens de instalación de la App viven solo en memoria.
  • Webhook sin deduplicación. Una entrega firmada y repetida puede deshabilitar a alguien que un admin rehabilitó tras volver a la organización. La cuenta queda deshabilitada hasta que un admin la rehabilite otra vez, con credenciales nuevas porque las anteriores quedaron revocadas. Guarda GITHUB_WEBHOOK_SECRET como cualquier secreto y rótalo si se filtra. Si alguien que volvió aparece deshabilitado, revisa «Usuarios» y los eventos user.disable con via: github-webhook.

Identidad con un proveedor OIDC

Con un proveedor OIDC configurado, la identidad de las personas es la del proveedor: su issuer, el nombre del claim que las identifica y el valor de ese claim (Identidad). Esto es lo que supone para la seguridad:

  • Qué comprueba cada acceso. El flujo de código de autorización, siempre con PKCE (S256), también con un cliente confidencial, y un state aleatorio en una cookie firmada de 10 minutos. El id_token solo se acepta firmado con RS256 por una clave del JWKS del propio issuer: HS256, none y las curvas elípticas se rechazan antes de buscar ninguna clave. Su iss tiene que ser el issuer configurado (la única excepción es el accounts.google.com sin esquema de Google), aud tiene que incluir el client id, azp tiene que coincidir con él siempre que venga y tiene que venir cuando aud lista varias audiencias, exp es obligatorio, iat y nbf tienen 30 s de margen para el desfase de relojes, y su nonce tiene que ser el que envió kubelatch.
  • El correo solo cuenta cuando el proveedor lo garantiza. El claim de verificación (email_verified, o el que diga OIDC_EMAIL_VERIFIED_CLAIM) tiene que ser true, y el dominio tiene que ser exactamente uno de OIDC_ALLOWED_DOMAINS. Con Google, además, el claim hd tiene que venir, estar permitido y coincidir con el dominio del correo: una cuenta sin él es un Gmail personal. Si al token le falta el correo o el claim de verificación (el de Okta, en el flujo de código de autorización, trae email sin email_verified), kubelatch pregunta una vez a userinfo, solo se fía de la respuesta si su sub es el del token, y entonces toma el correo y su verificación solo de esa respuesta. Un claim de verificación que dice false se rechaza sin preguntar.
  • Vinculación por correo. Solo en un primer acceso, solo sobre una única cuenta habilitada sin identidad de este proveedor y solo si OIDC_AUTOLINK lo permite. Una identidad del mismo proveedor nunca se sustituye por correo. Cada vinculación deja un evento oidc.link, revoca los enlaces pendientes de la cuenta y aparece en «Avisos». El riesgo que queda, una cuenta nunca vinculada cuya dirección de correo acaba en manos de otra persona en el proveedor, lo cubren ese aviso, la política invited y deshabilitar a la gente el mismo día que se va.
  • Contraseñas. Como con GitHub, solo entran con contraseña las cuentas break-glass, que son también la forma de entrar cuando el proveedor está caído.
  • Bajas. El proveedor no da una lista de miembros, así que kubelatch no deshabilita a nadie por su cuenta. Deshabilitar a una persona en el proveedor impide su siguiente acceso, pero lo que ya tiene sigue vivo hasta que caduca: la sesión del navegador hasta 12 h, la sesión de la CLI (KUBELATCH_CLI_SESSION_TTL, 12 h por defecto) y cada credencial (hasta KUBELATCH_MAX_TTL_USER, 30 días por defecto). «Deshabilitar» en «Usuarios» lo corta todo a la vez: hazlo el mismo día.
  • Doble factor. El que imponga el proveedor. kubelatch no tiene uno propio, y guarda en cada login.success el amr y el acr del proveedor, cuando los envía.
  • Los tokens del proveedor. El id_token, el access_token, el código de autorización, el verificador PKCE y el client secret nunca llegan a una línea del log, a un evento, a una cookie ni a una respuesta: los tokens solo viven mientras dura la petición del callback. Importa con un cliente público cuyo client id también acepta un cluster: ahí, ese id_token abriría además el API server.
  • Llamadas al proveedor. Solo al issuer configurado y a los endpoints https que nombra su documento de descubrimiento, sin seguir redirecciones, con un timeout de 10 s y un tope de tamaño en cada respuesta. Cada réplica guarda el documento de descubrimiento 24 h y las claves de firma, 1 h. Mientras el proveedor no responde, los accesos a través de él fallan con provider_unavailable; las cuentas break-glass siguen entrando.

Sin login externo

Sin las variables GITHUB_* ni OIDC_*, el login local no tiene doble factor ni bajas automáticas. Una contraseña robada da acceso a los clusters con los permisos de esa persona. Mitigaciones activas: sesiones de 12 h, bloqueo por intentos y límite por IP, credenciales con caducidad, revocación inmediata y auditoría de cada login. Es aceptable para una prueba o un entorno sin proveedor de identidad. En producción, configura la GitHub App o tu proveedor OIDC y, mientras tanto, deshabilita el mismo día las cuentas de quien se va.

Credenciales de CI sin secretos

Un workflow de GitHub Actions no guarda ningún secreto de kubelatch: canjea un id_token OIDC que GitHub firma para ese run (CI: reglas de confianza). La verificación es estricta:

  • Firma. Solo RS256, con las claves públicas de <issuer>/.well-known/jwks (KUBELATCH_GITHUB_ACTIONS_ISSUER). kubelatch las guarda 1 h; una clave desconocida fuerza un refresco, como mucho uno por minuto. Si GitHub no responde, sigue usando las guardadas hasta 24 h después del último refresco correcto. Pasado ese plazo, todos los canjes fallan con 401.
  • Claims. iss exacto, aud igual a KUBELATCH_BASE_URL, y exp, nbf e iat con 30 s de margen para el desfase de relojes.
  • Un solo uso. El jti se guarda al canjearlo; un token repetido se rechaza con 401.
  • Ids, no nombres. Las reglas de confianza comparan repository_owner_id, repository_id, ref y environment. kubelatch no interpreta sub: acepta tanto el formato clásico repo:owner/name:… como el de ids inmutables.

Cualquier fallo del token responde el mismo 401 invalid token; el motivo solo queda en el log y en el evento ci.exchange.failure.

La clave de licencia

Una clave Pro es un token firmado (Ed25519) que kubelatch verifica contra las claves públicas incluidas en su binario, al arrancar y cada hora. La comprobación no llama a ningún servicio ni saca nada de tu instancia, así que las instalaciones aisladas de internet funcionan. La única llamada de kubelatch a Picaporte Labs es la comprobación diaria de versión, que lee un JSON pequeño, no envía nada y solo enseña a los administradores un aviso cuando hay una versión más nueva (Saber cuándo hay una versión nueva); KUBELATCH_UPDATE_CHECK la desactiva. Una clave pegada en la interfaz se guarda cifrada con KUBELATCH_ENCRYPTION_KEY; si esa clave se pierde o se cambia, la clave pegada no se puede abrir (Si se pierde o se cambia la clave de cifrado). Una clave en KUBELATCH_LICENSE se lee del entorno. Una clave que no verifica, o que no se puede abrir, deja kubelatch en Free con un aviso; nunca lo para. Un límite rechaza un alta nueva y nada más: el proxy, los permisos y las credenciales nunca se degradan por una clave.

Agentes de IA

El servidor MCP no añade una segunda vía hacia los clusters: cada llamada a una herramienta pasa por el proxy, con la misma suplantación, la misma fila de auditoría, sin la cual la petición no sale, y el RBAC del cluster decidiendo. Además:

  • /mcp solo acepta las credenciales propias de un bot y los tokens de acceso de los agentes delegados; esos tokens no valen en ningún otro sitio. La credencial de una persona no se le puede dar a un agente en /mcp.
  • Un agente delegado nunca recibe más que su persona: cada permiso suyo deriva de uno de ella, con el mismo rol o viewer, nunca cluster-admin, y termina con él.
  • El consentimiento y cada aprobación necesitan la sesión web de una persona y una pulsación; ningún enlace los responde.
  • Una escritura aprobada ejecuta la petición guardada una vez, con una precondición; su cuerpo se guarda cifrado mientras espera.
  • Los valores de los Secrets solo llegan a un agente por read_secret, y cada lectura es una fila de auditoría.

Los límites (contenido que lleva instrucciones, un valor leído que no se puede recuperar, otras vías en la máquina del agente) están en Agentes de IA.

Auditoría inmutable

kubelatch mantiene dos registros en Postgres: una fila por petición al proxy, escrita antes de reenviarla y completada al terminar, y un evento por cada acción del plano de control (altas, permisos, credenciales, revocaciones, cambios de cuentas, reglas de confianza, cada intento de login), escrito en la misma transacción que la acción.

La propia base de datos impide manipularlos: una fila de petición solo se completa una vez, los eventos del plano de control nunca se modifican y ninguno de los dos registros se puede truncar. Solo borra la tarea periódica de retención, y solo filas más antiguas que KUBELATCH_AUDIT_RETENTION (90 días por defecto, 24 horas como máximo si la instancia nunca tuvo clave; ver Auditoría y retención). Borrar un cluster no borra su historia, y las cuentas nunca se borran, solo se deshabilitan.

La base de datos es tan segura como su acceso

Quien tenga el rol de Postgres de kubelatch puede desactivar estas protecciones. kubelatch usa el mismo rol para las migraciones y para la ejecución. Si necesitas evidencia a prueba de manipulación, exporta la auditoría a un almacenamiento inmutable.

La auditoría nativa del cluster, segunda fuente

Mantén activa la auditoría nativa de cada cluster. Registra lo que no pasa por kubelatch (accesos nativos, tokens de ServiceAccount usados desde pods) y es una segunda fuente independiente. El API server usa el Audit-ID de kubelatch como su auditID, así que una fila de kubelatch y su evento nativo se encuentran por el mismo identificador.

Datos personales

La auditoría guarda por petición la IP, el login, el User-Agent y la query string; en un exec, la query contiene el comando que la persona ejecutó. Los eventos del plano de control guardan el actor y la IP de cada acción administrativa y el login y la IP de cada intento de login. Finalidad: seguridad y trazabilidad del acceso a los clusters. Plazo: KUBELATCH_AUDIT_RETENTION, 90 días por defecto (24 horas como máximo si la instancia nunca tuvo clave). Auditoría y retención explica cómo consultarlos y borrarlos.

Lo que kubelatch no cubre

Grabación de sesiones, ingesta de la auditoría nativa del cluster, relay para clusters privados, gestión de namespaces y cuotas, kubectl --as, SAML, más de un proveedor OIDC a la vez, los grupos del proveedor de identidad, el alta o la baja desde él (SCIM), límite de peticiones por credencial en el proxy, ni el exec, port-forward, watch o el seguimiento de logs de un agente. Tampoco sustituye al acceso nativo de emergencia a cada cluster, que debe existir y estar probado (ver Cuentas y recuperación).