„Rulează-l într-un sandbox” sună ca o singură instrucțiune. În practică, sunt patru granițe obișnuite la care se gândesc oamenii când o spun și opresc lucruri foarte diferite. Dacă o alegi pe cea greșită, fie rămâi expus, fie fiecare rulare devine mai lentă și mai scumpă decât ar trebui.
Comparația pornește de la ideea că acel cod chiar e nesigur: scris de un model de limbaj, trimis de un utilizator sau venit într-un pull request de la cineva pe care nu-l cunoști. Codul scris de tine are alte nevoi.
Ce poate merge prost
Înainte să compari granițele, ajută să numești la ce folosesc. Codul nesigur poate:
- Să citească ce nu trebuie: variabile de mediu, chei SSH, fișiere din directorul home, endpointurile de metadate ale cloudului.
- Să epuizeze resursele: să ruleze într-o buclă infinită, să se multiplice până blochează mașina, să umple discul.
- Să abuzeze de rețea: să scaneze alte hosturi, să trimită spam, să mineze criptomonede, să-ți apeleze serviciile interne.
- Să rămână: să instaleze un cron job sau un serviciu care trăiește mai mult decât sarcina.
- Să scape: să folosească un bug din stratul de dedesubt ca să ruleze cod chiar pe host.
Fiecare nivel de mai jos acoperă unele dintre acestea, iar altele nu.
Nivelul 1: un proces
Cel mai simplu sandbox e un proces copil: subprocess.run cu un timeout, poate sub un utilizator separat, cu limite de resurse și un filtru seccomp, dacă ești temeinic.
Oprește: timpul scăpat de sub control (timeoutul), o parte din epuizarea resurselor (limitele), unele apeluri de sistem periculoase (seccomp). Nu oprește: citirea a tot ce poate citi utilizatorul respectiv, accesul la rețea, persistența prin orice poate scrie utilizatorul și niciun bug de kernel. Cum cedează de obicei: codul citește un fișier despre care ai uitat că poate fi citit sau un interpretor de limbaj „restricționat” se dovedește a avea o portiță. Istoria e plină de sandboxuri în interiorul limbajului care n-au rezistat.
Timpul de pornire e practic zero. În regulă pentru cod scris de tine; nu e o graniță pentru cod pe care nu l-ai scris tu.
Nivelul 2: un container
Namespaces îi dau codului propria vedere asupra fișierelor, proceselor și rețelei; cgroups plafonează CPU-ul și memoria; capabilitățile eliminate și seccomp restrâng ce poate cere de la kernel.
Oprește: citirea fișierelor hostului (dacă nu sunt montate), vederea altor procese, consumul nelimitat de resurse, o mare parte din problema persistenței, dacă containerul e aruncat după aceea. Nu oprește: un bug în kernelul comun al hostului. Fiecare container de pe mașină vorbește cu același kernel, așa că o vulnerabilitate de kernel accesibilă e o ieșire. Cum cedează de obicei: prin configurare, nu prin exploituri exotice. Un container privilegiat, socketul runtime-ului de containere montat înăuntru, rețeaua hostului pornită „doar pentru depanare”. Fiecare dintre ele elimină pe tăcute granița.
Timpul de pornire e de milisecunde. Există variante întărite, inclusiv kerneluri în user space care interceptează apelurile de sistem înainte să ajungă la host, cu un cost în viteză și compatibilitate. Pentru cod de la oameni în care ai încredere, un container bine configurat e o alegere implicită rezonabilă.
Nivelul 3: un microVM
Un microVM rulează propriul kernel sub un hypervisor, ca o VM completă, dar cu aproape tot hardware-ul emulat eliminat. Firecracker e cel mai cunoscut exemplu.
Oprește: tot ce oprește un container, plus problema kernelului comun. Ca să ajungă la host, codul trebuie să spargă hypervisorul sau unul dintre puținele dispozitive virtuale, o suprafață mult mai mică decât interfața de apeluri de sistem a unui kernel. Nu oprește: folosirea abuzivă a ce îi dai. O ieșire deschisă spre internet poate fi în continuare folosită abuziv; secretele pe care le injectezi se pot scurge în continuare. Cum cedează de obicei: prin politici, nu prin izolare. Cineva transmite un token de producție „ca să meargă testele” sau lasă traficul spre exterior nerestricționat la o sarcină care nu are nevoie de el.
Timpul de pornire e de la o fracțiune de secundă până la aproximativ o secundă, cu câțiva megabyți de overhead. E destul de repede încât să creezi câte unul pentru fiecare sarcină și să-l ștergi după aceea, ceea ce rezolvă și persistența: nu rămâne nimic la care să te întorci.
Nivelul 4: o mașină virtuală completă
O VM obișnuită, sau un VPS, are același fel de graniță ca un microVM: virtualizare hardware și un hypervisor. Diferența e tot ce e în jurul ei: un model complet de dispozitive, un sistem de operare întreg, un IP public dacă vrei unul și un ciclu de viață măsurat în zile sau luni.
Oprește: aceleași clase de probleme ca un microVM, cu o suprafață de atac ceva mai mare, pentru că e emulat mai mult hardware. Nu oprește: folosirea abuzivă a propriei identități de rețea. O VM cu IP public care rulează cod abuziv își vede propriul IP pus pe liste negre, ceea ce contează dacă același IP îți trimite și e-mailurile. (Dacă s-a întâmplat deja, vezi ce faci când IP-ul tău e pe o listă neagră.) Cum cedează de obicei: trăiește prea mult. O VM creată pentru un experiment adună date de acces și stare și devine încet mașina de încredere pe care trebuia s-o protejeze.
Timpul de pornire e de la zeci de secunde la minute, iar facturarea e de obicei lunară. E forma potrivită pentru un serviciu de lungă durată care are nevoie de porturi de intrare și forma greșită pentru o rulare de cod de 20 de secunde.
Comparația
| Proces | Container | MicroVM | VM completă | |
|---|---|---|---|---|
| Kernel propriu | nu | nu | da | da |
| Granița principală | permisiunile utilizatorului | namespaces + kernel comun | hypervisor, model de dispozitive minuscul | hypervisor, model complet de dispozitive |
| Timp de pornire | ~0 | ms | ~0,1–1 s | 10 s – minute |
| Overhead | niciunul | mic | câțiva MiB | zeci–sute de MiB |
| Aruncat după fiecare sarcină | ușor | ușor | ușor | lent, costisitor |
| Porturi de intrare / IP public | ale hostului | ale hostului | de obicei niciunul | da |
Alegerea
- Cod scris de tine sau de echipa ta: un proces sau un container e în regulă.
- CI pentru propriile branchuri: un container pe runnerul tău.
- Cod generat de agenți, trimiteri ale utilizatorilor, pull requesturi din afară: un microVM pentru fiecare sarcină, șters după aceea.
- Un serviciu nesigur care trebuie să accepte conexiuni sau să ruleze săptămâni întregi: o VM separată, cu propriul IP, ținută departe de tot ce are datele tale de acces sau îți trimite e-mailurile.
Orice ai alege, două reguli se aplică peste: nu pune înăuntru nimic din ce nu i-ai da autorului codului și decide deliberat ce are voie să facă rețeaua.
Unde se încadrează produsele noastre
Pentru nivelul 3 rulăm sandboxuri de cod: microVM-uri Firecracker care pornesc în aproximativ o secundă, cu internet spre exterior, fără porturi de intrare și cu facturare la secundă. Sunt făcute exact pentru al treilea punct de mai sus; pagina MCP guardrails arată cum limitezi ce poate face un agent cu ele. Pentru nivelul 4, un VPS ca planul AI agent îți dă o mașină întreagă, cu plata lunară. Exemplele lucrate din sandbox pentru agenți AI arată tiparul microVM de la cap la coadă, iar de ce au nevoie agenții AI de la infrastructură privește izolarea ca pe una dintre mai multe cerințe.
Comentarii
Încă nu există comentarii. Fii primul.