«Eseguilo in una sandbox» sembra un'istruzione unica. In pratica ci sono quattro confini comuni a cui ci si riferisce, e fermano cose molto diverse. Sceglierne uno sbagliato ti lascia esposto o rende ogni esecuzione più lenta e più costosa del necessario.
Questo confronto presuppone che il codice sia davvero non fidato: scritto da un modello linguistico, inviato da un utente o arrivato in una pull request di qualcuno che non conosci. Il codice che hai scritto tu ha esigenze diverse.
Cosa può andare storto
Prima di confrontare i confini, conviene nominare a cosa servono. Il codice non fidato può:
- Leggere ciò che non dovrebbe: variabili d'ambiente, chiavi SSH, file nella tua home, endpoint dei metadati del cloud.
- Esaurire le risorse: girare all'infinito, fare fork fino a bloccare la macchina, riempire il disco.
- Abusare della rete: scansionare altri host, inviare spam, minare criptovalute, chiamare i tuoi servizi interni.
- Persistere: installare un cron job o un servizio che sopravvive all'attività.
- Evadere: sfruttare un bug dello strato sottostante per eseguire codice sull'host stesso.
Ogni livello qui sotto gestisce una parte di questi rischi, non tutti.
Livello 1: un processo
La sandbox più semplice è un processo figlio: subprocess.run con un timeout, magari con un utente dedicato, limiti di risorse e un filtro seccomp se sei scrupoloso.
Ferma: l'esecuzione infinita (il timeout), parte dell'esaurimento delle risorse (limiti), alcune chiamate di sistema pericolose (seccomp). Non ferma: la lettura di tutto ciò che quell'utente può leggere, l'accesso alla rete, la persistenza tramite tutto ciò su cui l'utente può scrivere, e qualsiasi bug del kernel. Cedimento tipico: il codice legge un file che avevi dimenticato fosse leggibile, oppure un interprete «limitato» si rivela avere una scappatoia. La storia è piena di sandbox interne ai linguaggi che non hanno retto.
Il tempo di avvio è praticamente nullo. Va bene per il tuo codice; non è un confine per quello altrui.
Livello 2: un container
I namespace danno al codice una propria vista di file, processi e rete; i cgroup limitano CPU e memoria; capability rimosse e seccomp restringono ciò che può chiedere al kernel.
Ferma: la lettura dei file dell'host (se non montati), la vista degli altri processi, l'uso illimitato delle risorse, gran parte del problema della persistenza se il container viene buttato via. Non ferma: un bug nel kernel condiviso dell'host. Tutti i container della macchina parlano con lo stesso kernel, quindi una vulnerabilità del kernel raggiungibile è un'uscita. Cedimento tipico: la configurazione più che exploit esotici. Un container privilegiato, il socket del runtime dei container montato all'interno, la rete dell'host attivata «solo per il debug». Ognuno di questi rimuove il confine in silenzio.
Il tempo di avvio è di millisecondi. Esistono varianti rafforzate, tra cui kernel in spazio utente che intercettano le chiamate di sistema prima che raggiungano l'host, a scapito di velocità e compatibilità. Per il codice di persone di cui ti fidi, un container ben configurato è un'impostazione predefinita sensata.
Livello 3: una microVM
Una microVM esegue il proprio kernel sotto un hypervisor, come una VM completa, ma quasi senza hardware emulato. L'esempio più noto è Firecracker.
Ferma: tutto ciò che ferma un container, più il problema del kernel condiviso. Per raggiungere l'host, il codice deve violare l'hypervisor o uno di una manciata di dispositivi virtuali, una superficie molto più piccola dell'interfaccia di chiamate di sistema di un kernel. Non ferma: l'abuso di ciò che le consegni. Il traffico in uscita aperto può ancora essere sfruttato; i segreti iniettati possono ancora trapelare. Cedimento tipico: le regole, non l'isolamento. Qualcuno passa un token di produzione «per far funzionare i test», oppure lascia il traffico in uscita senza restrizioni dove non serve.
Il tempo di avvio va da una frazione di secondo a circa un secondo, con pochi megabyte di overhead. È abbastanza veloce da crearne una per attività ed eliminarla dopo, il che risolve anche la persistenza: non resta nulla a cui tornare.
Livello 4: una macchina virtuale completa
Una VM normale, o un VPS, ha lo stesso tipo di confine di una microVM: virtualizzazione hardware e un hypervisor. La differenza sta in tutto il resto: un modello di dispositivi completo, un intero sistema operativo, un IP pubblico se lo vuoi e un ciclo di vita misurato in giorni o mesi.
Ferma: le stesse classi di problemi di una microVM, con una superficie di attacco un po' più ampia perché si emula più hardware. Non ferma: l'abuso della propria identità di rete. Una VM con IP pubblico che esegue codice malevolo fa finire il suo IP nelle blocklist, il che conta se lo stesso IP invia la tua posta. (Se è già successo, vedi cosa fare quando il tuo IP è in una blocklist.) Cedimento tipico: vive troppo a lungo. Una VM creata per un esperimento accumula credenziali e stato, e piano piano diventa la macchina fidata che doveva proteggere.
Il tempo di avvio va da decine di secondi a minuti, e la fatturazione è di solito mensile. È la forma giusta per un servizio di lunga durata che ha bisogno di porte in ingresso, e quella sbagliata per eseguire codice per 20 secondi.
Il confronto
| Processo | Container | MicroVM | VM completa | |
|---|---|---|---|---|
| Kernel proprio | no | no | sì | sì |
| Confine principale | permessi utente | namespace + kernel condiviso | hypervisor, modello di dispositivi minuscolo | hypervisor, modello di dispositivi completo |
| Avvio | ~0 | ms | ~0.1–1 s | 10 s – minuti |
| Overhead | nessuno | piccolo | pochi MiB | decine–centinaia di MiB |
| Buttare via dopo ogni attività | facile | facile | facile | lento, costoso |
| Porte in ingresso / IP pubblico | quelli dell'host | quelli dell'host | di solito nessuno | sì |
Come scegliere
- Codice scritto da te o dal tuo team: basta un processo o un container.
- CI per i tuoi branch: un container sul tuo runner.
- Codice di agenti, invii degli utenti, pull request esterne: una microVM per attività, eliminata dopo.
- Un servizio non fidato che deve accettare connessioni o girare per settimane: una VM separata con il proprio IP, lontana da tutto ciò che custodisce le tue credenziali o invia la tua posta.
Qualunque cosa tu scelga, valgono due regole in più: non mettere dentro nulla che non daresti all'autore del codice, e decidi consapevolmente cosa può fare la rete.
Dove si collocano i nostri prodotti
Per il livello 3 offriamo sandbox per il codice: microVM Firecracker che si avviano in circa un secondo, con internet in uscita, senza porte in ingresso e con fatturazione al secondo. Sono pensate proprio per il terzo punto qui sopra; la pagina delle protezioni MCP spiega come limitare ciò che un agente può farci. Per il livello 4, un VPS come la tariffa AI agent ti dà un'intera macchina al mese. Gli esempi svolti in sandbox per agenti IA mostrano lo schema con microVM dall'inizio alla fine, e cosa serve davvero agli agenti IA dall'infrastruttura considera l'isolamento come uno dei vari requisiti.
Commenti
Ancora nessun commento. Sii il primo.