El contratista con la llave maestra: aislar agentes de IA del workstation al cluster

Primer post de una pareja sobre aislamiento de agentes de IA. Este fija el qué y el dónde: el mapa completo de primitivas de aislamiento y a qué dominio pertenece cada una. El runbook hermano fija el cómo, con comandos: ai-jail y bubblewrap en el cliente, TracingPolicy de Tetragon y RuntimeClass en el cluster. Si solo vas a leer uno, este te da el modelo mental; el otro, los ficheros que se copian y pegan.

TL;DR

Un agente de IA que ejecuta código necesita acceso a tu filesystem y a tus herramientas: compilador, linter, grep, make, cargo, npm. Ese es el mínimo para ser útil. El problema es que junto a ese acceso viaja la capacidad de leer ~/.aws/credentials, exfiltrar tus claves SSH o lanzar un rm -rf fuera del directorio del proyecto. Y no hace falta un modelo malicioso: basta una dependencia comprometida en un npm install, porque el agente bienintencionado y el post-install script envenenado corren con los mismos permisos. La respuesta no es confiar en las buenas intenciones del LLM; es aislar para acotar el radio de explosión. Este post recorre las cinco familias de aislamiento de 2026 —del sandbox de proceso a la VM completa— y las reparte en dos columnas: lo que aplica en el cliente (el workstation del desarrollador: bubblewrap, ai-jail, sandbox-exec, Landlock, los sandboxes nativos de Claude Code y Codex) y lo que aplica en el cluster (donde el agente o la inferencia corren en Kubernetes: namespaces+seccomp, gVisor, microVMs Firecracker/Kata y eBPF/Tetragon como capa de observación y enforcement en caliente). La tesis: el modelo de amenaza es el mismo en los dos sitios; las herramientas, no. La política se extrapola; la primitiva se reescribe.

La analogía: el contratista con la llave maestra

Contratas a un operario para una reforma. Es competente y va de buena fe. Pero pasan dos cosas que no controlas. La primera: puede malinterpretar la orden y tirar el tabique equivocado. La segunda, peor: su caja de herramientas pudo manipularse antes de que entrara por tu puerta —alguien metió algo dentro—, y cuando la abre en tu salón, ese algo se activa.

Nadie sensato le da la llave maestra del edificio entero. Le abres la habitación donde trabaja, le dejas las herramientas que necesita, y mantienes cerrados el despacho con la caja fuerte y el cuarto de los servidores. Si la reforma sale mal —por error o por sabotaje—, el daño se queda en esa habitación.

Un agente de IA es ese contratista. El sandbox es la política de llaves: le das la habitación del proyecto y las herramientas, no la llave maestra del sistema. Y aquí está el giro que justifica dos posts: el operario trabaja en dos edificios distintos. Uno es tu piso —el workstation del desarrollador, con tus credenciales, tu ~/.ssh, el baúl de contraseñas del navegador—. El otro es el centro de datos —el cluster donde la inferencia y los agentes autónomos sirven a clientes, con datos de varios inquilinos a la vez—. La política de llaves es idéntica en los dos: principio de mínimo privilegio, acota el radio. Pero la cerradura de la puerta de tu piso no es la misma que la del centro de datos. En el piso pones un bombín (bubblewrap). En el centro de datos pones un guardia que vigila cada puerta y un ala separada del edificio (Tetragon + microVM). Mismo principio, distinta ferretería. Eso es extrapolar la tecnología, no copiarla.

El modelo de amenaza: qué puede hacer un agente desbocado

Antes de elegir cerradura conviene enumerar al ladrón. La superficie de ataque de un agente que ejecuta bash arbitrario se descompone en cinco amenazas concretas. No todas se defienden con la misma capa, y —dato incómodo que la propia documentación de seguridad reconoce— ninguna capa las cubre todas.

AmenazaQué hace el agenteCapa mínima que la corta
Filesystem fuera de alcanceLee .env, ~/.ssh/id_rsa, secretos del sistema; modifica fuentes fuera del proyectoSandbox de proceso (allowlist de rutas)
Egress de red arbitrarioExfiltra datos, recibe instrucciones de un C2 remoto, llama APIs sin autorizarBloqueo de red / NetworkPolicy / microVM
Superficie de syscalls del kernelUn exploit del kernel desde el contenedor escala al host (kernel compartido)gVisor o microVM (kernel dedicado)
Fuga entre inquilinosEl workload de un cliente lee datos de otro en una plataforma multi-tenantmicroVM (estándar de facto)
Exfiltración de secretosSaca tokens y variables de entorno vía /proc o el environment--clearenv / tmpfs de $HOME / secretos fuera del pod

Hay una sexta amenaza que ningún sandbox resuelve: el prompt injection. Si un atacante consigue colar instrucciones en el contexto del agente —un comentario envenenado en el código, un fichero malicioso que el agente lee, una respuesta adversaria de una herramienta—, el agente ejecutará esas instrucciones con los permisos que el sandbox le conceda. El aislamiento encoge el radio de impacto de una inyección exitosa; no impide la inyección. Por eso el sandbox es una capa, no la solución: encima van validación de entrada, allowlists de tool-calls y auditoría de salida. La frase a interiorizar: el aislamiento no hace al agente confiable; acota lo que un agente no confiable puede romper.

Dos dominios, una política

El operario trabaja en dos edificios. El reparto de herramientas se ve mejor a dos columnas:

Misma política de mínimo privilegio · distinta primitivaCLIENTE · workstation del devun proceso, un usuario, datos personalesSandbox de procesobubblewrap (Linux) · sandbox-exec (macOS)Landlock (LSM, 2ª barrera VFS)defensa en profundidad, kernel ≥5.13Dev container (opcional)reproducibilidad + reset, kernel compartidoLo que lo envuelve:ai-jail · Claude Code /sandboxCodex --sandbox · Cursor /worktreeRed de seguridad: git remoto sin pusharranque ~0 ms · sin daemonCLUSTER · inferencia / agentes en prodmulti-pod, multi-tenant, RKE2Baseline de podnamespaces + seccomp + cgroups + NetworkPolicygVisor (runsc) — kernel en user-spacereduce superficie de syscalls al hostmicroVM Firecracker / Kata — kernel propioaislamiento por construcción para no confiableeBPF / Tetragon (lo que ya tenemos)observa cada exec · connect · open en kernely mata (Sigkill) lo que se salga del guionRed de seguridad: GitOps + revisión de PRarranque <1 s (microVM) · capa runtime siempreextrapolar: el control del cliente tiene su análogo en el cluster (tabla de equivalencias en el runbook)

El cliente: aislar al agente en el workstation

Aquí el agente es un asistente de coding —Claude Code, Codex, OpenCode, Cursor— que un desarrollador lanza en su máquina. Un proceso, un usuario, y al lado los activos más jugosos que existen: ~/.aws/credentials, ~/.ssh, ~/.gnupg, el almacén de contraseñas del navegador. El tier que corresponde es el más ligero: el sandbox de proceso.

bubblewrap (Linux) y sandbox-exec (macOS). bubblewrap (bwrap) es el mismo sandbox que usa Flatpak para aislar cada app de escritorio: ~50 KB de binario, ~4.000 líneas de C, mantenido por el equipo de GNOME, y —la propiedad clave— corre sin root vía CLONE_NEWUSER, creando namespaces sin privilegios elevados. Monta $HOME como un tmpfs efímero y solo expone, con escritura, el directorio del proyecto; el resto del sistema se vuelve invisible. En macOS el equivalente es sandbox-exec con perfiles SBPL: API legacy de Apple, oficialmente deprecada y sin reemplazo público, pero funciona hoy. La paridad entre las dos no es exacta —en macOS la GPU (Metal) y el display (Cocoa) son de sistema y sandbox-exec no los restringe—, pero ambas protegen lo que importa: el acceso a las zonas sensibles del filesystem.

Landlock como segunda barrera. bubblewrap aísla por namespaces y montajes; Landlock —un Linux Security Module disponible desde el kernel 5.13— restringe el acceso a nivel VFS, independiente de los namespaces. No reemplaza a bwrap: lo complementa. Cierra vectores que el aislamiento por montaje no cubre por sí solo (rutas de escape vía /proc, trucos con symlinks dentro de montajes permitidos) y actúa de red de seguridad si la maquinaria de namespaces tuviera un bug. Es defensa en profundidad dentro del propio cliente, y degrada limpiamente a no-op en kernels que no lo soportan.

Dev containers, cuando hace falta reproducibilidad. Un dev container (devcontainer.json, lo que usan Codespaces y Cursor) es un contenedor Docker con una capa de configuración encima. Da aislamiento de filesystem razonable y reset fácil (destruir y recrear), pero comparte el kernel del host —misma limitación que cualquier Docker— y tiende a ser de larga vida, acumulando estado. Para un agente que ejecuta código de tu propio equipo, en tu máquina, es un buen relato de repetibilidad; no es la capa de aislamiento para código no confiable por sí solo.

Lo que envuelve todo esto. El script de bash a mano funciona, pero no escala a un equipo. Las herramientas que lo empaquetan:

  • ai-jail (Rust, GPL-3.0): envuelve bwrap/sandbox-exec con config por proyecto en un fichero .ai-jail (TOML, commiteable al repo, de modo que todo el equipo hereda la misma política), auto-detección de GPU/Docker/display, modo --lockdown (proyecto en read-only, red cortada con --unshare-net, --clearenv), --dry-run para auditar, y --bootstrap para generar las allowlists de permisos de cada agente. Es agnóstico de la herramienta: el mismo binario sirve para Claude, Codex, OpenCode o Crush. Aplica además Landlock automáticamente en kernels 5.13+ como defensa en profundidad.
  • El /sandbox de Claude Code: desde octubre de 2025, Claude Code trae sandbox propio que usa —exactamente— bubblewrap en Linux y sandbox-exec en macOS. Su Sandboxed Bash aísla los comandos de shell, pero no las herramientas de fichero, los servidores MCP ni los hooks, que corren con los permisos completos del proceso salvo que actives el paquete beta sandbox-runtime, que envuelve el proceso entero. Hay un matiz que conviene conocer: si un comando falla por una restricción, el agente puede reintentar con dangerouslyDisableSandbox —es opt-out, no opt-in—.
  • Codex CLI: tres modos vía --sandbox (read-only, workspace-write, danger-full-access); el recomendado por defecto es workspace-write. La filosofía es deliberada: Codex no provee el aislamiento, lo delega al entorno que lo envuelve. danger-full-access solo tiene sentido dentro de una microVM.
  • Cursor: sus cloud agents corren en VMs aisladas; /worktree crea un worktree aislado de un solo uso por tarea, y /best-of-n lanza varios intentos en paralelo en worktrees separados.

El cluster: aislar al agente en producción

El segundo edificio es el centro de datos. Aquí el “agente” puede ser un agente autónomo que corre sin un humano delante, o el propio servicio de inferencia ejecutando código generado, o un workload multi-tenant donde el pod de un cliente no debe tocar los datos de otro. El proceso ya no es uno: son pods en un cluster Kubernetes (RKE2/RKE3 en una plataforma soberana típica). Las primitivas cambian de naturaleza.

El baseline del pod. Antes de nada, lo de serie: namespaces de Linux, seccomp (RuntimeDefault) para recortar la superficie de syscalls, cgroups para los límites de recursos, securityContext sin privilegios (runAsNonRoot, readOnlyRootFilesystem, drop de todas las capabilities) y NetworkPolicy para cortar el egress. Es el equivalente cluster de la allowlist del sandbox de proceso. Necesario, pero comparte kernel con el host: insuficiente para código realmente no confiable.

gVisor (runsc). El kernel en espacio de usuario de Google: intercepta las syscalls del workload antes de que lleguen al kernel del host y las atiende dentro de un kernel Linux reimplementado en Go (el Sentry). La superficie expuesta a vulnerabilidades del kernel del host se reduce drásticamente, manteniendo arranque rápido y footprint bajo. Es el término medio cuando el riesgo de escape de kernel es real pero el overhead de una microVM no es asumible.

microVMs Firecracker / Kata. El estándar de facto para código no confiable en 2026. Firecracker (VMM de AWS en Rust, sobre KVM) da a cada sandbox un kernel Linux dedicado: un exploit de kernel dentro de la microVM no alcanza al host por construcción. Es lo que hay debajo de Vercel Sandbox (GA enero 2026) y E2B. En Kubernetes, Kata Containers trae ese modelo a un RuntimeClass: marcas el pod del agente no confiable con runtimeClassName: kata y se ejecuta en su propia microVM en lugar de compartir el kernel del nodo. Para multi-tenant con código generado, esto es el baseline, no el lujo.

eBPF / Tetragon: la capa que ya tenemos. Aquí está la pieza que distingue una plataforma con observabilidad de runtime de una que solo confía en la configuración. Las capas anteriores son estáticas: definen lo que el pod puede hacer antes de arrancar. Tetragon —el componente de seguridad runtime de Cilium, basado en eBPF— es dinámico: observa, en el kernel y con coste mínimo, cada ejecución de proceso, cada conexión de red y cada apertura de fichero de cada pod, y puede actuar en línea. No reemplaza al sandbox; lo vigila desde dentro del kernel. Donde bubblewrap en el cliente bloquea curl con una blocklist de comandos, Tetragon en el cluster engancha tcp_connect en el kernel y, si el destino no está permitido, mata el proceso con Sigkill antes de que el paquete salga. Donde el cliente esconde ~/.ssh tras un tmpfs, Tetragon engancha security_file_open y reporta —o mata— cualquier intento de leer una ruta sensible montada. Es el guardia que recorre los pasillos mientras las microVMs son las paredes. Y es, exactamente, el tipo de control que materializa las medidas de monitorización y trazabilidad del ENS (op.mon, op.exp) sin instrumentar la aplicación: la visibilidad vive en el kernel, no en el código del agente.

La tabla del panorama

Las cinco familias, su fortaleza relativa de aislamiento, su coste de arranque y el dominio donde viven:

TierPrimitivaAislamientoArranqueDominio natural
Sandbox de procesoSeatbelt · bubblewrapBaseline~0 msCliente (defecto de Claude Code)
Dev containerDocker + seccompModeradosegundosCliente / cluster (repetibilidad)
Kernel user-spacegVisor (runsc)FuertemsCluster (multi-tenant medio)
microVMFirecracker · KataEl más fuerte (práctico)<1 sCluster (código no confiable)
VM completaKVM · EC2Máximo30 s+Cluster (frontera externa, compliance)
Runtime enforcementeBPF · TetragonTransversalsiempre activoCluster (observa+mata sobre cualquier tier)

Tetragon ocupa una fila aparte a propósito: no es un tier en la escalera, es una capa transversal que opera sobre cualquiera de los otros. Se apila con todos.

Un apunte numérico sobre por qué la columna “arranque” decide tanto como la columna “aislamiento”. Una VM completa gana en aislamiento bruto pero tarda decenas de segundos en provisionarse; para un agente que necesita un entorno fresco por petición o por sesión, ese coste es prohibitivo. Una microVM Firecracker arranca en menos de 1 segundo y un sandbox de proceso en ~0 ms. Por eso el patrón dominante en 2026 no es “la VM más aislada”, sino VM completa como frontera externa + microVM como unidad de ejecución por petición dentro —la arquitectura de Vercel, AWS Lambda y E2B—. En el cliente el cálculo es el opuesto: el desarrollador lanza el agente decenas de veces al día de forma interactiva, y un arranque de segundos rompería el flujo; de ahí que el sandbox de proceso, con su overhead de microsegundos, sea el defecto correcto.

Extrapolar, no copiar

La tesis de la pareja de posts cabe en una frase: el modelo de amenaza es invariante entre dominios; la primitiva que lo implementa, no. El cliente y el cluster defienden exactamente los mismos cinco vectores —filesystem, red, kernel, multi-tenant, secretos—, pero con cajas de herramientas que no se solapan. Cada control tiene su gemelo en el otro lado:

  • $HOME como tmpfs efímero (cliente) ↔ readOnlyRootFilesystem + emptyDir (cluster).
  • Blocklist de curl/wget en bwrap (cliente) ↔ TracingPolicy sobre tcp_connect en Tetragon + NetworkPolicy (cluster).
  • --unshare-net en lockdown (cliente) ↔ NetworkPolicy default-deny (cluster).
  • Sin escape hatch, el proceso vive dentro de bwrap (cliente) ↔ sin privileged, sin hostPath, RuntimeClass kata (cluster).
  • ~/.ssh y ~/.aws nunca montados (cliente) ↔ secretos fuera del pod + Tetragon vigilando security_file_open (cluster).

El runbook hermano convierte cada una de estas equivalencias en ficheros concretos. Lo que importa retener aquí es el método: cuando alguien te enseña un sandbox de agente —sea el /sandbox de Claude Code en un portátil o un microVM en un PaaS—, la pregunta útil no es “¿qué herramienta usa?”, sino “¿cuál de los cinco vectores cierra, y cuál deja abierto?”. La herramienta se sustituye; el mapa de amenazas se queda.

Lo que ningún sandbox resuelve

Tres límites que la propia documentación de Anthropic enuncia, y que conviene tener delante para no vender humo:

  1. El egress sigue siendo un riesgo en cualquier sandbox que permita conexiones salientes. Si el agente puede abrir una conexión, puede exfiltrar. Por eso el lockdown del cliente corta la red y el cluster usa NetworkPolicy default-deny + Tetragon: no se confía en “filtrar bien”, se confía en “no dejar salir”.
  2. La modificación de código sigue siendo posible en cualquier sandbox con el directorio del proyecto montado en escritura. El remedio no es técnico-de-sandbox, es git: con el remoto intacto y sin permiso de push, el peor caso es corromper el working copy local —git checkout . y a empezar—. El daño no llega al remoto.
  3. Ningún sandbox impide que un prompt comprometido llegue a la API. El aislamiento acota el impacto de una inyección; no la previene. Las defensas complementarias —validación de entrada, allowlists de tool-calls, auditoría de salida— son obligatorias junto al aislamiento, no en su lugar.

La conclusión operativa: el aislamiento encoge el radio de explosión; la defensa en profundidad es lo que cierra el círculo. Un sandbox de proceso para código de confianza en una máquina conocida es apropiado y prácticamente gratis. Para un agente que actúa sobre prompts de usuario, ejecuta código generado o corre en multi-tenant, el mínimo aceptable en 2026 es una microVM, con Tetragon observando por encima. Elige el tier que case con tu amenaza real, verifica qué vector deja abierto, y apila controles complementarios encima.

Ver también

Referencias