OpenShell: Il runtime di sicurezza dietro NemoClaw
Se NemoClaw è lo stack di sicurezza, OpenShell ne è il fondamento. Sviluppato dal team di ingegneria della sicurezza di NVIDIA negli ultimi 18 mesi, OpenShell fornisce sandboxing a livello kernel per l'esecuzione degli agenti IA — garantendo che anche un agente completamente compromesso non possa accedere a risorse al di fuori del suo perimetro di sicurezza definito.
Questo articolo è un approfondimento tecnico sull'architettura di OpenShell, i suoi meccanismi di isolamento e il modo in cui applica le policy di sicurezza con un overhead prestazionale minimo.
Perché l'isolamento a livello kernel?
Il sandboxing applicativo tradizionale — container, VM, isolamento a livello di processo — è stato progettato per software dal comportamento prevedibile. Gli agenti IA sono fondamentalmente diversi. Generano i propri piani di esecuzione al runtime, effettuano chiamate a strumenti che interagiscono con sistemi esterni e possono produrre comportamenti nuovi che nessuna suite di test aveva previsto.
Questa imprevedibilità richiede un modello di sicurezza che operi al livello più basso possibile: il kernel. OpenShell intercetta ogni chiamata di sistema effettuata dal processo di un agente, la classifica rispetto alla policy di sicurezza attiva e prende una decisione di autorizzazione o negazione prima che la chiamata raggiunga il kernel.
Agent Process
│
▼
OpenShell eBPF Layer ←── Policy Engine
│
├── ALLOW → System Call → Kernel
│
├── DENY → Error returned to agent
│
└── ESCALATE → Human approval queue
eBPF: La tecnologia dietro OpenShell
OpenShell è costruito su eBPF (extended Berkeley Packet Filter), una tecnologia del kernel Linux che permette l'esecuzione di programmi personalizzati nello spazio kernel senza modificare il kernel stesso. Il team NVIDIA ha scritto una suite di programmi eBPF specificamente ottimizzati per i carichi di lavoro degli agenti IA:
Intercettore delle chiamate di sistema
L'intercettore delle chiamate di sistema si aggancia al tracepoint sys_enter e valuta ogni chiamata di sistema rispetto alla policy attiva:
// Simplified OpenShell eBPF syscall interceptor
SEC("tracepoint/raw_syscalls/sys_enter")
int openshell_syscall_enter(struct trace_event_raw_sys_enter *ctx) {
u32 pid = bpf_get_current_pid_tgid() >> 32;
struct sandbox_policy *policy = bpf_map_lookup_elem(&sandbox_policies, &pid);
if (!policy)
return 0; // Not a sandboxed process
long syscall_nr = ctx->id;
int decision = evaluate_policy(policy, syscall_nr, ctx->args);
if (decision == DENY) {
// Send event to userspace audit log
emit_security_event(pid, syscall_nr, DENY);
// Override return value to -EPERM
bpf_override_return(ctx, -EPERM);
} else if (decision == ESCALATE) {
// Pause the process and notify approval queue
emit_approval_request(pid, syscall_nr, ctx->args);
send_signal(pid, SIGSTOP);
}
return 0;
}
Guardia del filesystem
La guardia del filesystem limita a quali file e directory un agente può accedere. Opera sulle operazioni VFS (Virtual Filesystem), intercettando le chiamate open, read, write, unlink e rename:
# Filesystem policy for a customer support agent
filesystem:
# Agent can read its own configuration
- path: "/etc/nemoclaw/agent.yaml"
permissions: [read]
# Agent can read/write to its workspace
- path: "/var/nemoclaw/workspace/**"
permissions: [read, write, create]
# Agent can read shared data
- path: "/var/nemoclaw/shared/**"
permissions: [read]
# Everything else is denied by default
defaultAction: deny
Sentinella di rete
La sentinella di rete si aggancia alle operazioni dei socket per controllare l'accesso alla rete dell'agente a livello di connessione:
SEC("cgroup/connect4")
int openshell_connect4(struct bpf_sock_addr *ctx) {
u32 pid = bpf_get_current_pid_tgid() >> 32;
struct network_policy *policy = bpf_map_lookup_elem(&net_policies, &pid);
if (!policy)
return 1; // Allow non-sandboxed processes
__be32 dst_ip = ctx->user_ip4;
__be16 dst_port = ctx->user_port;
if (!is_allowed_destination(policy, dst_ip, dst_port)) {
emit_security_event(pid, NETWORK_BLOCKED, dst_ip, dst_port);
return 0; // Block connection
}
return 1; // Allow connection
}
Architettura di applicazione delle policy
Le policy di OpenShell vengono compilate in bytecode eBPF per la massima velocità di applicazione. La pipeline di compilazione funziona come segue:
- 1.I file di policy YAML vengono scritti dai team di sicurezza in un formato leggibile dall'uomo
- 2.Il compilatore di policy converte il YAML in una rappresentazione intermedia (IR)
- 3.Il validatore di policy Nemotron verifica la coerenza logica e i conflitti dell'IR
- 4.Il compilatore eBPF genera bytecode verificato che viene caricato nel kernel
- 5.Il verificatore di runtime assicura che i programmi eBPF terminino e siano sicuri per la memoria
L'intera pipeline di compilazione viene eseguita in meno di 2 secondi per gli insiemi di policy tipici, e le policy possono essere ricaricate a caldo senza riavviare l'agente.
# Compile and load a policy
nemoclaw policy compile policies/customer-support.yaml
nemoclaw policy load customer-support
# Hot-reload a modified policy (no agent restart required)
nemoclaw policy reload customer-support
# Verify policy is active
nemoclaw policy status
# Output:
# POLICY STATUS LOADED AT RULES
# customer-support active 2026-03-19 14:30:01 47
# network-default active 2026-03-19 14:30:01 12
# filesystem-strict active 2026-03-19 14:30:01 23
Workflow di approvazione dell'operatore
Una delle caratteristiche più distintive di OpenShell è il suo sistema integrato di approvazione da parte dell'operatore. Quando un agente tenta un'azione classificata come ad alto rischio, OpenShell mette in pausa l'esecuzione dell'agente e instrada la richiesta di approvazione verso un operatore umano.
Come funziona l'approvazione
- 1.L'agente tenta una chiamata di sistema ad alto rischio (ad es., scrittura su un file protetto, connessione a un endpoint non approvato)
- 2.Il programma eBPF di OpenShell invia SIGSTOP al processo dell'agente
- 3.Viene generata una richiesta di approvazione e inviata tramite il canale configurato (Slack, Teams, PagerDuty, email)
- 4.L'operatore esamina il contesto della richiesta e approva o nega
- 5.Se approvata, OpenShell invia SIGCONT per riprendere l'agente; se negata, restituisce EPERM
La richiesta di approvazione include il contesto completo:
{
"request_id": "apr-2026031914-00042",
"agent": "customer-support-agent-01",
"action": "email.send",
"target": "[email protected]",
"context": {
"ticket_id": "TKT-12345",
"customer_name": "[REDACTED]",
"reason": "Agent wants to send a follow-up email to the customer regarding their refund request",
"email_preview": "Dear Customer, your refund of $250 has been processed..."
},
"risk_level": "medium",
"policy_rule": "external-communication-requires-approval",
"timestamp": "2026-03-19T14:30:42Z"
}
Timeout di approvazione e azioni predefinite
Gli operatori possono configurare cosa succede quando un'approvazione scade:
approvalConfig:
timeout: 15m
onTimeout: deny # deny | allow | escalate
onEscalate:
target: security-team
channel: pagerduty
maxPendingApprovals: 10 # Queue limit per agent
autoApprove:
# Automatically approve if the same action was approved
# 3 times in the past 24 hours for this agent
repeatThreshold: 3
repeatWindow: 24h
Caratteristiche prestazionali
OpenShell è progettato per carichi di lavoro di produzione dove la latenza conta. Ecco gli overhead misurati su un DGX Spark:
| Operazione | Overhead |
|---|---|
| Intercettazione syscall (autorizzazione) | 8 microsecondi |
| Intercettazione syscall (negazione) | 12 microsecondi |
| Verifica filesystem | 15 microsecondi |
| Verifica connessione di rete | 20 microsecondi |
| Ricaricamento a caldo della policy | < 500 millisecondi |
| Round-trip approvazione (Slack) | 2-30 secondi (dipende dall'umano) |
Per confronto, una tipica chiamata di inferenza LLM richiede 500 ms-5000 ms, quindi l'overhead di OpenShell è trascurabile nel contesto dei carichi di lavoro degli agenti.
Confronto con il sandboxing esistente
| Funzionalità | OpenShell | Docker/OCI | gVisor | Firecracker |
|---|---|---|---|---|
| Livello di isolamento | Kernel (eBPF) | Namespace | Kernel spazio utente | microVM |
| Filtraggio syscall | Per policy, ricaricamento a caldo | seccomp statico | Interposizione completa | Isolamento completo |
| Policy di rete | Per agente, livello L7 | iptables | iptables | iptables |
| Approvazione umana | Integrata | Nessuna | Nessuna | Nessuna |
| Policy IA-aware | Sì (Nemotron) | No | No | No |
| Overhead | ~10 microsecondi | ~5 microsecondi | ~50 microsecondi | ~100 ms all'avvio |
| Passthrough GPU | Nativo | NVIDIA CTK | Limitato | Limitato |
Il principale fattore differenziante di OpenShell è che è stato progettato da zero per i carichi di lavoro degli agenti IA, con supporto integrato per le policy in linguaggio naturale, i workflow di approvazione umana e la valutazione delle policy accelerata da GPU.
Iniziare con OpenShell
OpenShell può essere utilizzato in modo autonomo, senza il resto dello stack NemoClaw:
# Install OpenShell standalone
curl -fsSL https://github.com/NVIDIA/OpenShell | bash
# Create a minimal sandbox policy
cat > my-policy.yaml << 'EOF'
apiVersion: openshell.nvidia.com/v1
kind: SandboxPolicy
metadata:
name: my-first-sandbox
spec:
isolation:
network: restricted
filesystem: workspace-only
syscalls: minimal
EOF
# Run any process inside the sandbox
openshell run --policy my-policy.yaml -- python my_agent.py
OpenShell è open source sotto licenza Apache 2.0 e disponibile su nvidia/openshell su GitHub. Nel prossimo articolo, esploreremo scenari reali di distribuzione enterprise per l'intero stack NemoClaw.