« Lance-le dans une sandbox » ressemble à une seule consigne. En pratique, on désigne par là quatre frontières courantes, qui arrêtent des choses très différentes. Mal choisir vous laisse exposé ou rend chaque exécution plus lente et plus chère que nécessaire.
Cette comparaison suppose que le code est vraiment non fiable : écrit par un modèle de langage, soumis par un utilisateur ou arrivé dans une pull request d'un inconnu. Le code que vous avez écrit vous-même a d'autres besoins.
Ce qui peut mal tourner
Avant de comparer les frontières, il est utile de nommer ce contre quoi elles servent. Du code non fiable peut :
- Lire ce qu'il ne devrait pas : variables d'environnement, clés SSH, fichiers de votre répertoire personnel, points de terminaison de métadonnées du cloud.
- Épuiser les ressources : boucler à l'infini, forker jusqu'à bloquer la machine, remplir le disque.
- Abuser du réseau : scanner d'autres hôtes, envoyer du spam, miner de la cryptomonnaie, appeler vos services internes.
- Persister : installer une tâche cron ou un service qui survit à la tâche.
- S'échapper : exploiter un bug de la couche inférieure pour exécuter du code sur l'hôte lui-même.
Chaque niveau ci-dessous gère une partie de ces risques, pas tous.
Niveau 1 : un processus
La sandbox la plus simple est un processus enfant : subprocess.run avec un délai, éventuellement sous un utilisateur dédié, avec des limites de ressources et un filtre seccomp si l'on est rigoureux.
Arrête : l'exécution sans fin (le délai), une partie de l'épuisement des ressources (limites), certains appels système dangereux (seccomp). N'arrête pas : la lecture de tout ce que cet utilisateur peut lire, l'accès réseau, la persistance via tout ce que l'utilisateur peut écrire, et n'importe quel bug du noyau. Échec typique : le code lit un fichier dont on avait oublié qu'il était lisible, ou un interpréteur « restreint » se révèle avoir une porte dérobée. L'histoire regorge de sandboxes internes à un langage qui n'ont pas tenu.
Le démarrage est quasi instantané. Bien pour votre propre code ; pas une frontière pour le code des autres.
Niveau 2 : un conteneur
Les namespaces donnent au code sa propre vue des fichiers, des processus et du réseau ; les cgroups plafonnent CPU et mémoire ; les capabilities retirées et seccomp réduisent ce qu'il peut demander au noyau.
Arrête : la lecture des fichiers de l'hôte (sauf montage), la vue des autres processus, la consommation illimitée de ressources, l'essentiel du problème de persistance si le conteneur est jeté. N'arrête pas : un bug dans le noyau partagé de l'hôte. Tous les conteneurs de la machine parlent au même noyau, donc une vulnérabilité noyau accessible est une sortie. Échec typique : la configuration plutôt que des exploits exotiques. Un conteneur privilégié, le socket du runtime de conteneurs monté à l'intérieur, le réseau de l'hôte activé « juste pour déboguer ». Chacun supprime discrètement la frontière.
Le démarrage se fait en millisecondes. Il existe des variantes durcies, dont des noyaux en espace utilisateur qui interceptent les appels système avant qu'ils n'atteignent l'hôte, au prix de vitesse et de compatibilité. Pour du code de personnes en qui vous avez confiance, un conteneur bien configuré est un choix par défaut raisonnable.
Niveau 3 : une microVM
Une microVM exécute son propre noyau sous un hyperviseur, comme une VM complète, mais presque sans matériel émulé. L'exemple le plus connu est Firecracker.
Arrête : tout ce qu'arrête un conteneur, plus le problème du noyau partagé. Pour atteindre l'hôte, le code doit casser l'hyperviseur ou l'un d'une poignée de périphériques virtuels, une surface bien plus petite que l'interface d'appels système d'un noyau. N'arrête pas : l'abus de ce que vous lui confiez. Un trafic sortant ouvert reste exploitable ; des secrets injectés peuvent toujours fuiter. Échec typique : la politique, pas l'isolation. Quelqu'un transmet un jeton de production « pour que les tests passent », ou laisse le trafic sortant sans restriction là où il n'est pas nécessaire.
Le démarrage va d'une fraction de seconde à environ une seconde, avec quelques mégaoctets de surcoût. C'est assez rapide pour en créer une par tâche et la supprimer ensuite, ce qui règle au passage la persistance : il n'y a plus rien vers quoi revenir.
Niveau 4 : une machine virtuelle complète
Une VM classique, ou un VPS, a le même type de frontière qu'une microVM : virtualisation matérielle et hyperviseur. La différence tient à tout le reste : un modèle de périphériques complet, un OS entier, une IP publique si vous le souhaitez, et un cycle de vie compté en jours ou en mois.
Arrête : les mêmes classes de problèmes qu'une microVM, avec une surface d'attaque un peu plus grande puisque plus de matériel est émulé. N'arrête pas : l'abus de sa propre identité réseau. Une VM avec IP publique qui exécute du code malveillant fait inscrire son IP sur des listes de blocage, ce qui compte si cette même IP envoie vos e-mails. (Si c'est déjà arrivé, voir que faire quand votre IP est sur une liste de blocage.) Échec typique : elle vit trop longtemps. Une VM créée pour une expérience accumule identifiants et état, et devient peu à peu la machine de confiance qu'elle devait protéger.
Le démarrage prend de dizaines de secondes à quelques minutes, et la facturation est généralement mensuelle. C'est la bonne forme pour un service durable qui a besoin de ports entrants, et la mauvaise pour exécuter du code pendant 20 secondes.
La comparaison
| Processus | Conteneur | MicroVM | VM complète | |
|---|---|---|---|---|
| Noyau propre | non | non | oui | oui |
| Frontière principale | droits utilisateur | namespaces + noyau partagé | hyperviseur, modèle de périphériques minuscule | hyperviseur, modèle de périphériques complet |
| Démarrage | ~0 | ms | ~0.1–1 s | 10 s – minutes |
| Surcoût | aucun | faible | quelques Mio | dizaines–centaines de Mio |
| Jeter après chaque tâche | facile | facile | facile | lent, coûteux |
| Ports entrants / IP publique | ceux de l'hôte | ceux de l'hôte | généralement aucun | oui |
Choisir
- Code écrit par vous ou votre équipe : un processus ou un conteneur suffit.
- CI pour vos propres branches : un conteneur sur votre runner.
- Code d'agents, soumissions d'utilisateurs, pull requests externes : une microVM par tâche, supprimée ensuite.
- Un service non fiable qui doit accepter des connexions ou tourner des semaines : une VM séparée avec sa propre IP, à l'écart de tout ce qui détient vos identifiants ou envoie vos e-mails.
Quel que soit votre choix, deux règles s'ajoutent : ne mettez rien à l'intérieur que vous ne confieriez pas à l'auteur du code, et décidez délibérément de ce que le réseau a le droit de faire.
Où se situent nos produits
Pour le niveau 3, nous proposons des sandboxes de code : des microVM Firecracker qui démarrent en une seconde environ, avec Internet en sortie, sans port entrant et facturées à la seconde. Elles visent précisément le troisième point ci-dessus ; la page des garde-fous MCP explique comment limiter ce qu'un agent peut en faire. Pour le niveau 4, un VPS comme le tarif AI agent vous donne une machine entière au mois. Les exemples détaillés de sandbox pour agents IA montrent le schéma microVM de bout en bout, et ce dont les agents IA ont vraiment besoin côté infrastructure aborde l'isolation comme une exigence parmi d'autres.
Commentaires
Pas encore de commentaires. Soyez le premier.