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.
Identidad: Thulu no guarda contraseñas
Sección titulada «Identidad: Thulu no guarda contraseñas»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.
Claves: tuyas y de cada corrida
Sección titulada «Claves: tuyas y de cada corrida»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.
Qué credenciales ve el agente
Sección titulada «Qué credenciales ve el agente»- 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-sandboxy elargus-browserpor 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).
Secretos guardados
Sección titulada «Secretos guardados»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.
El registro de auditoría
Sección titulada «El registro de auditoría»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.

Exportar
Sección titulada «Exportar»“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.

Cadena de hashes
Sección titulada «Cadena de hashes»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:
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.
Mandarlo afuera
Sección titulada «Mandarlo afuera»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.
Retención
Sección titulada «Retención»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 |
curl -X PUT -H "Authorization: Bearer $OCTOPUS_KEY" -H "Content-Type: application/json" \ -d '365' https://thulu.tu-empresa.internal/settings/audit.retention_daysBorrar 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.
Releases firmadas
Sección titulada «Releases firmadas»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”).
Lo que Thulu no hace
Sección titulada «Lo que Thulu no hace»- 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.