Ir al contenido

Seguridad y auditoría

Esta página explica cómo protege Thulu el acceso y qué rastro deja. Sirve para responder un cuestionario de seguridad o para decidir cómo configurar una instalación propia. La mayor parte del modelo funciona sin que hagas nada; lo que se ajusta está indicado en cada sección, con su pantalla o su variable de entorno.

Thulu no autentica a nadie. No hay contraseña, segundo factor ni passkey que configurar: el inicio de sesión ocurre en un proveedor de identidad por OIDC (Okta, Microsoft Entra ID, Google, Keycloak o MisterD ID en la SaaS) o con GitHub, incluido GitHub Enterprise Server, y Thulu empieza a trabajar cuando el proveedor le devuelve una identidad con el correo verificado. MFA, bloqueo por intentos y recuperación de cuenta son responsabilidad del proveedor.

Lo que sí es de Thulu: los workspaces, los roles de cada persona y las sesiones después de entrar. Mientras usás Thulu, la sesión del navegador se renueva sola cada 30 minutos; si pasás 7 días sin entrar, o a los 30 días del inicio de sesión (OCTOPUS_SESSION_MAX_LIFETIME en self-hosted), tenés que volver a iniciar sesión. Cada persona ve y cierra sus sesiones en “Configuración → Cuenta” (ver Configuración).

En una instalación propia, quién puede entrar se decide con variables de entorno:

Variable Para qué
OCTOPUS_OIDC_ISSUER, OCTOPUS_OIDC_CLIENT_ID, OCTOPUS_OIDC_CLIENT_SECRET, OCTOPUS_OIDC_REDIRECT_URI El proveedor OIDC (uno por instalación)
OCTOPUS_SSO_ALLOWED_DOMAINS Dominios de correo admitidos
OCTOPUS_SSO_ALLOWED_GROUPS Grupos del proveedor admitidos; sacar a alguien del grupo lo deja afuera en su próximo inicio
OCTOPUS_OIDC_GROUP_ROLE_MAP Tomar el rol de un grupo del proveedor en vez de asignarlo a mano
OCTOPUS_SSO_DEFAULT_WORKSPACE, OCTOPUS_SSO_DEFAULT_ROLE A qué workspace y con qué rol entra alguien nuevo (lector por defecto)
OCTOPUS_SIGNUP_MODE=allowlist Sólo pueden darse de alta los correos de una lista (es la que maneja “Acceso a la beta” en la SaaS)

thulu init pregunta por el proveedor al instalar; los detalles están en Instalación self-hosted. Lo que resultó de estas variables se ve, en sólo lectura, en el panel “Inicio de sesión” de “Configuración → Miembros”.

Cada persona tiene un rol por workspace. Los roles son cuatro y fijos; no hay roles personalizados.

Rol (en la UI) Puede
“lector” Ver tareas, tableros, proyectos, agentes y uso
“desarrollador” Lo anterior, más crear, editar y mover tareas, comentar, responder preguntas, decidir aprobaciones y relanzar o frenar agentes
“administrador” Lo anterior, más borrar tareas y administrar proyectos, agentes, skills, tableros, credenciales, webhooks, API keys, miembros y el registro de auditoría
“dueño” Lo anterior, más pasar el workspace a otra persona, borrarlo, conectar la GitHub App y habilitar los chats delegados

Las secciones de la instalación entera (Salud completa, retención, Actualizaciones, Infraestructura, la dirección de telemetría, la verificación de la cadena de auditoría) son del administrador del workspace operador. Invitar y cambiar roles se explica en Workspaces y equipo.

Hay dos tipos de clave de API y ninguna sirve fuera de su workspace.

Las que creás vos en “Configuración → API” llevan un rol (nunca más alto que el tuyo), una lista de permisos y un vencimiento de 90 días como máximo por defecto. Una llamada tiene que pasar el rol y el permiso a la vez. Thulu guarda sólo un hash de la clave: si la perdés, no hay forma de recuperarla. Cómo se crean, rotan y revocan está en Configuración.

Las de cada corrida las crea Thulu solo. Cada contenedor que arranca (una etapa, un chat, una mención, el auditor) recibe su propia clave, que:

  • tiene como máximo rol desarrollador;
  • dura hasta 24 horas y se revoca cuando el contenedor termina;
  • sólo puede modificar su tarea, las subtareas y hermanas de su grupo y las tareas que esa corrida creó;
  • puede pedir una aprobación pero nunca aprobarla, rechazarla ni borrarla;
  • no puede subir carpetas como proyectos ni integrar ramas de un proyecto subido;
  • sólo ve su propio chat y las transcripciones de las corridas que puede modificar.

Cada tanda de Evidencia corre con una clave que sólo sirve para esa tanda y se revoca al terminar.

Un chat con “Actuar por mí” recibe otra clave, de 8 horas, que puede trabajar en todos los tableros con el rol de la persona (como máximo desarrollador); sus borrados esperan que esa persona los confirme. Ver Chat.

  • La key del modelo: con el gateway LLM, prendido por defecto en los stacks de compose y en Helm, el contenedor del agente recibe un token propio de la corrida y el daemon pone la key real (o firma el pedido a Bedrock o Vertex). Un token OAuth de Claude Pro/Max no pasa por el gateway; ese token sólo lo carga el dueño del workspace operador, y con los agentes en Kubernetes está apagado salvo OCTOPUS_KUBE_ALLOW_CLAUDE_OAUTH_TOKEN=1. Con una sesión personal de Claude (sólo en Docker), cualquier contenedor de agente de las corridas de esa persona puede leer la sesión.
  • Los MCP: desde 0.3.3 todo MCP que usa un agente pasa por el proxy MCP del daemon con la key de la corrida. El daemon decide en cada pedido si la corrida tiene ese server concedido, rechaza las tools fuera de la lista y agrega la credencial; el contenedor no recibe URLs ni credenciales de los MCP. Quedan directos argus-sandbox y el argus-browser por corrida. Ver MCPs.
  • El token de GitHub nunca entra al contenedor del agente, y desde 0.3.3 tampoco al sandbox. En Docker, el daemon hace el commit y el push; en Kubernetes, el agente empuja su rama a Thulu y el daemon la publica en GitHub con el token del proyecto. Las tools de GitHub que usan los agentes piden el token al servidor en cada llamada, con los permisos mínimos de la GitHub App para esa tool, y las que despachan workflows, aprueban deployments o mergean se conceden sólo por nombre. Configuración en Git y GitHub y Credenciales y motores.

En Docker los agentes corren con capabilities recortadas y en una red propia, sin filtro de salida a internet. El control de egress existe sólo en el runtime de Kubernetes (open o proxy-only).

Las claves de los modelos, las credenciales de AWS, Google Cloud, GitHub y de los MCP, la clave privada de la GitHub App y los secretos de los webhooks se guardan cifrados (AES-256-GCM). En self-hosted, la clave de cifrado es OCTOPUS_SECRETBOX_KEY; para rotarla, la vieja pasa a OCTOPUS_SECRETBOX_PREVIOUS_KEYS y el próximo arranque recifra todo. El resto de la base (tareas, chats, transcripciones) no va cifrado por Thulu: si lo necesitás, usá un volumen o un Postgres administrado con cifrado en reposo.

Cada acción administrativa queda en el registro del workspace: inicios de sesión, miembros, claves, tareas y etapas, aprobaciones y preguntas, agentes y credenciales, chats delegados, instalaciones del Workshop, cambios del script de inicialización, runners, actualizaciones. Desde 0.3.3 son 62 tipos de evento. Cada entrada guarda quién lo hizo (una persona, una API key con su nombre o la corrida de un agente), la IP y la hora. Se ve en “Configuración → Registro de auditoría”; requiere rol administrador.

Registro de auditoría filtrado por auth.* con los botones Exportar CSV y Exportar NDJSON habilitados
Con licencia Enterprise, la exportación respeta el filtro elegido en el selector.

“Exportar CSV” y “Exportar NDJSON” (una entrada JSON por línea) bajan todas las entradas que coinciden con el filtro. El archivo trae más que la tabla: email del actor, tipo de actor, IP, navegador y los dos hashes de la cadena. Exportar necesita licencia Enterprise en la instalación; el panel “Licencia” de “Salud” muestra cuál tenés.

Panel Licencia con edición Enterprise, licenciatario, fecha de vencimiento y funciones
Con licencia, el panel muestra licenciatario, vencimiento y funciones; "*" significa todas.

Cada entrada guarda el hash de la anterior, así que borrar, editar o insertar una fila rompe la cadena. Un administrador del workspace operador la verifica con “Verificar”, arriba del registro: dice cuántas entradas cubre y su hash de cabeza, y si una está rota la muestra. También se pide por API, con una sesión o una API key de ese mismo rol:

Ventana de terminal
curl -H "Authorization: Bearer $OCTOPUS_KEY" https://thulu.tu-empresa.internal/audit/verify
# {"checked":14,"legacy":0,"ok":true,"head":"25d2a5f5…"}

Guardá el valor de head fuera de la base de datos. La cadena detecta cambios en el medio, pero un recorte del final sólo se nota comparando contra un head anotado antes.

En self-hosted, OCTOPUS_AUDIT_SINK=stdout (o stderr, o file:/ruta/audit.log) escribe cada entrada como una línea JSON en el momento en que se registra, para que la levante tu colector de logs. Esa copia es la que un administrador de la base no puede editar.

Un proceso horario borra los datos viejos, en Docker y en Kubernetes; la auditoría se recorta cada 12 horas. Los plazos son ajustes de la instalación (en días; 0 es para siempre). El operador los cambia en “Configuración → Salud → Retención y limpieza”, que muestra cada plazo con su valor por defecto, o por API con PUT /settings/<clave>.

Dato Clave Por defecto
Logs y archivos de las corridas retention.run_logs_days 30
Uso por corrida (los totales diarios de costo quedan) retention.sessions_days 90
Entregas de webhooks retention.webhook_deliveries_days 30
Claves de corrida revocadas retention.run_keys_days 7
Sandboxes ya desarmados retention.sandbox_rows_days 30
Historial de la caché de dependencias (instalaciones y mediciones) retention.cache_metrics_days 90
Worktrees de tareas trabadas (el trabajo se commitea antes) retention.stuck_worktree_days 14
Registro de auditoría audit.retention_days sin límite
Ventana de terminal
curl -X PUT -H "Authorization: Bearer $OCTOPUS_KEY" -H "Content-Type: application/json" \
-d '365' https://thulu.tu-empresa.internal/settings/audit.retention_days

Borrar un workspace entero lo hace su dueño desde “Cuenta” escribiendo el slug; se llevan tareas, sandboxes, worktrees, adjuntos, chats, uso, API keys y, en Kubernetes, el namespace del workspace. No hay exportación ni borrado por persona: se trabaja por workspace.

Las imágenes publicadas se firman con cosign (keyless) y llevan un SBOM firmado. install.sh verifica el checksum y, si cosign está instalado, la firma; sin cosign avisa y sigue sólo con el checksum, salvo que fijes OCTOPUS_REQUIRE_SIGNATURE=1. Para pasar de versión, thulu update y thulu apply verifican un manifiesto firmado de la release antes de tocar nada, sacan un snapshot de la base y vuelven solos si algo falla. Thulu nunca se actualiza solo: “Configuración → Actualizaciones” sólo informa y da el comando (ver Configuración).

Las vulnerabilidades se reportan por el formulario privado de GitHub del repositorio (“Report a vulnerability”).

  • Un solo proveedor OIDC por instalación. Sin SAML (federalo en un proveedor OIDC) ni SCIM.
  • Sin roles personalizados.
  • Sin exportación ni borrado de datos por persona.
  • No está certificado SOC 2 ni ISO 27001.
  • El envío de auditoría escribe a stdout, stderr o un archivo; no hay conectores directos a Splunk o Datadog.
  • En Docker no hay filtro de egress para los agentes.