GPT Diffusion

OpenShell de NVIDIA: enjaular agentes de código con límites de kernel

2026-09-28 · Devs #agentes#coding-agents#seguridad#self-hosting#arquitectura

Tus reglas le dicen al agente qué no hacer; el kernel se lo impide. Esa es la promesa de OpenShell, el runtime open-source de NVIDIA para ejecutar agentes de código en sandbox: políticas declarativas en YAML que se aplican con Landlock y seccomp, no con instrucciones en el prompt. Esta semana arrancó su serie estable (v0.1.0 a v0.1.2, del 25 al 28 de septiembre de 2026), así que es buen momento para leer la documentación y separar lo que hace de lo que dice que hace.

TL;DR

  • Verificado (repo y docs de NVIDIA, consultados el 2026-09-28): OpenShell es un runtime en Rust con licencia Apache-2.0 que ejecuta cada agente en un sandbox con una identidad no-root y sin capabilities de Linux; Landlock limita el acceso al filesystem y seccomp user notification intercepta las operaciones de red. Alrededor de 9.200 estrellas en GitHub (9.247 en la API al 2026-09-28).
  • Verificado: la red va denegada por defecto — “OpenShell denies every outbound connection from a sandbox unless a rule in network_policies allows it” —, cada regla filtra por binario, destino y método, y las credenciales nunca llegan al agente: OpenShell las inyecta solo en peticiones a endpoints aprobados.
  • El matiz: lo fuerte (red) cambia en caliente; lo débil (filesystem y proceso) queda fijo al arrancar el sandbox. Y por defecto, si Landlock no puede aplicar tus reglas de ficheros, el sandbox arranca igual sin ellas (best_effort) — hay que pedir hard_requirement explícitamente.
  • La trampa: en Kubernetes, el propio aviso de NVIDIA lo dice: K8s acepta las NetworkPolicy aunque ningún CNI las aplique. Sin CNI que las fuerce, los workloads del sandbox llegan a la red directamente y se saltan la política del supervisor.
  • Veredicto: para contener agentes con capacidad real en Linux es el diseño más serio que hemos visto en open source. Pero está en v0.1.x, con cuatro días de vida como serie estable: para probar y para staging, sí; como única barrera en producción, todavía no.

Qué es y por qué existe

El problema que ataca no es nuevo, pero se ha vuelto urgente: un agente de coding útil necesita leer ficheros, instalar paquetes y llamar APIs con credenciales reales. Darle esa capacidad sin contención es dejarle las llaves de casa; negársela toda es volver a copiar y pegar a mano.

OpenShell lo resuelve por la vía de abajo: instrumenta el kernel para aplicar la política en cada acceso a fichero, syscall y conexión de red, y usa verificación formal para revisar qué permitiría un cambio de política antes de aprobarlo. El proyecto arrancó en febrero de 2026 y hasta esta semana solo publicaba builds v0.0.x; la serie estable v0.1.0 → v0.1.1 → v0.1.2 salió en cuatro días (25-28 de septiembre de 2026 según la API de releases de GitHub).

Una corrección que circula mal: la imagen por defecto no trae agentes preinstalados. El README es explícito — “minimal Ubuntu with no agent installed” — y el flujo oficial pasa por perfiles de provider (hay ejemplos oficiales para claude-code, codex, copilot, cursor u openrouter en providers/) más imágenes de agente separadas. Si alguien te vende OpenShell como “distro de agentes”, no es eso.

Cómo funciona: gateway, supervisor y sandbox

La arquitectura documentada tiene tres piezas y una frontera de confianza que la doc resume así: “The supervisor is trusted and makes the decisions. The sandbox shares the boundary with the untrusted agent, so it never makes policy decisions. It reports what the agent is trying to do and lets the supervisor decide.” El sandbox es la pieza que vive dentro de la frontera, junto al agente: lo lanza como proceso hijo propio, con “one non-root identity and no Linux capabilities”; Landlock (un LSM del kernel) limita el filesystem, y seccomp user notification intercepta las operaciones de red y DNS para entregarlas fuera de la frontera. El supervisor, al otro lado, es el componente de confianza que decide: comprueba cada petición contra la política, resuelve el DNS y abre solo las conexiones aprobadas. Y el gateway es el plano de control: sabe qué sandboxes existen, entrega políticas y credenciales, y en él corre el prover que verifica los cambios de política antes de aprobarse. Todo fail-closed: lo que la política no permite, no sale.

Las credenciales merecen párrafo propio porque ahí está parte del valor real: el agente nunca ve el secreto. Tú registras la credencial en el provider del gateway y OpenShell la añade solo a las peticiones que van a un endpoint aprobado. El agente puede usar la API de GitHub sin que el token esté jamás en su contexto, su historial o sus logs.

Quién aplica qué (y cuándo puedes cambiarlo)

La doc de políticas es honesta sobre el ciclo de vida de cada dominio, y esa tabla es la parte más útil de todo el diseño:

SecciónQué controlaLo aplicaCuándo cambia
filesystem_policyRutas legibles y escribiblesLandlock, en el kernelAl arrancar; fijo
landlockQué pasa si no se pueden aplicar las reglasRuntime del sandboxAl arrancar
processUsuario y grupo del workloadDocker/Podman al crearFijo al crear
network_policiesDestinos por binario y peticiones permitidasProxy de red del sandboxEn caliente
network_middlewaresInspección o bloqueo extra del tráficoProxy de red del sandboxEn caliente

Esto significa que el dominio más maduro (red) es también el más flexible: puedes afinar reglas con el sandbox corriendo. El filesystem, en cambio, se decide antes de arrancar; cambiarlo implica recrear el sandbox.

Guía mínima: una política que deniega todo lo que no nombras

Con el CLI instalado (Linux, macOS Apple Silicon o WSL2 experimental, con Docker o Podman):

curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh
openshell sandbox create --name demo --policy mi-politica.yaml

Un esqueleto de política mínima (campos tomados del schema oficial; ajusta rutas y binarios a tu imagen):

version: 1

filesystem_policy:
  include_workdir: true
  read_only: [/usr, /lib, /etc]
  read_write: [/tmp]

landlock:
  compatibility: hard_requirement

process:
  run_as_user: "1500"
  run_as_group: "1500"

network_policies:
  github_readonly:
    endpoints:
      - host: api.github.com
        port: 443
        protocol: rest
        access: read-only
    binaries:
      - path: /usr/local/bin/gh
  pypi_packages:
    endpoints:
      - host: pypi.org
        port: 443
      - host: files.pythonhosted.org
        port: 443
    binaries:
      - path: /usr/bin/python3.12

Tres detalles que hacen funcionar esto de verdad:

  • La red es una matriz binario × destino. Cada regla lista endpoints y binarios, y permite cada cruce. El matching es por ruta real del ejecutable tal como la ve el kernel: si pip es un script de Python, quien conecta a PyPI es el intérprete, y la regla debe listar /usr/bin/python3.12, no /usr/bin/pip. Además OpenShell registra un hash de cada binario la primera vez que participa en una conexión y deniega las siguientes si el fichero cambia.
  • El filtrado llega hasta el método HTTP. Con protocol: rest y access: read-only, el endpoint solo acepta GET, HEAD y OPTIONS; con rules y deny_rules puedes permitir /repos/** y bloquear /repos/private/**. Ojo al matiz: en los endpoints inspeccionados, el modo por defecto es audit (permite y registra); pon enforcement: enforce cuando confirmes en los logs que la regla es la que quieres.
  • El acceso nuevo se abre con verificación, no con un sí del prompt. Cuando el agente toca un destino no permitido, la petición se deniega y se redacta un borrador de regla. El advisor agrupa las denegaciones recientes por host, puerto y programa que las originó, y propone reglas estrechas; el prover verifica formalmente cada propuesta antes de que la revises (openshell rule get my-agent --status pending para verlas, openshell rule approve para aceptarlas). Las reglas aprobadas hacen hot-reload en el sandbox sin reiniciarlo.

Ese último punto es la idea diferencial: el bucle advisor → prover → humano convierte “el agente me pide acceso” en una propuesta verificable y estrecha, en lugar de un “dale acceso a todo internet” a las once de la noche.

Por qué kernel gana a las reglas por prompt

La alternativa común es poner la política en el system prompt y confiar en que el modelo la respete. Esa política compite con todo lo demás que el agente lee: el contenido de la web que consulta, los issues que procesa, el README del repo que clona. Un prompt injection bien colocado no tiene que “hackear” nada: basta con que el modelo decida que aquella instrucción tenía sentido. La política por prompt es una sugerencia que el modelo puede pesar.

Con Landlock y seccomp, la negociación desaparece. La llamada al sistema no devuelve el dato; la conexión no sale del sandbox. No es que el agente prometa no exfiltrar: es que la ruta no existe. Y como la identidad es no-root sin capabilities, un hipotético escape del sandbox aterriza en un entorno con poco que agarrar.

La capa de verificación formal suma lo otro: no basta con que el kernel aplique — el prover comprueba, antes de aprobar un cambio, que la política nueva no concede más acceso que el límite que declaras. Cambias el problema de “convencer al modelo” a “demostrar lo que permites”.

Esto encaja con lo que contamos en memoria de agentes y envenenamiento RAG: si el agente ingiere contenido no confiable, la pregunta no es si fallará algún día, sino qué pasa cuando falle. Y cuanto más autónomo es el bucle — agentes que se auto-mejoran —, más vale una contención que no depende de que el propio agente tome la decisión correcta.

Dónde se queda corto

  • Filesystem y proceso congelados. Lo documentado: filesystem_policy y process quedan fijos al arrancar el sandbox; solo red y middleware cambian en caliente. Si tu agente necesita escribir en un volumen nuevo, toca recrear el sandbox. Coherente, pero no lo vendas como “política toda caliente”.
  • best_effort por defecto en Landlock. Si Landlock no puede aplicar ninguna de tus rutas (kernel viejo, paths inexistentes), con el valor por defecto el sandbox arranca igual sin las reglas de filesystem y lo deja en un log de severidad alta. Para contención real, declara hard_requirement y comprueba que tu kernel soporta Landlock ABI v3 o superior.
  • La trampa del CNI en Kubernetes. El warning oficial es del tipo que merece marco: “OpenShell creates the policies, but Kubernetes accepts them even when no CNI enforces them. Without enforcement, sandbox workloads may reach the network directly and bypass supervisor policy”. Es decir: tu cluster puede estar aceptando NetworkPolicies que nadie aplica. Verifica que tu CNI fuerza ingress y egress antes de confiar en el despliegue.
  • Plataformas. Linux y macOS (Apple Silicon) soportados; Windows vía WSL2 en experimental. El despliegue en Kubernetes va por Helm, con Agent Sandbox (proyecto SIG de K8s) y K8s 1.29+ como prerequisitos.
  • Telemetría activada por defecto. Anónima y limitada a categorías operativas según el README (sin prompts, rutas ni credenciales), pero está activa sin preguntar. OPENSHELL_TELEMETRY_ENABLED=false la desactiva; en Helm, server.telemetryEnabled=false.
  • v0.1.x. Cuatro días de serie estable y ya hay guía oficial de upgrade a 0.1.0 — sinónimo de que entre versiones hay cambios que rompen. La cadencia es buena señal, pero es pronto para apostar producción a esta carta.

Qué haría yo

Si corres agentes de coding con credenciales reales en Linux: pruébalo ya, empezando por el tutorial oficial (OpenCode contra un modelo gratuito de OpenRouter) para ver el bucle advisor/prover con tus ojos. Monta tu política desde la default —restrictiva— y deja que el advisor proponga lo que tu agente realmente necesita; aprueba tú cada regla. Declara hard_requirement en Landlock desde el primer día.

No lo usaría todavía como única barrera en producción: está en alpha, el filesystem se congela al arrancar y la trampa del CNI exige auditoría de tu cluster. Como capa de contención adicional —la que aplica el kernel cuando el prompt falla— es, hoy por hoy, lo mejor diseñado que existe en open source. Y si tu plan es ejecutar agentes fuera de tu máquina, mira también dónde desplegarlos en Cloudflare Workers: otro modelo de contención, con otras garantías.

Fuentes

Cargando comentarios...