
Sandbox microVM éphémère pour agents d'IA avec liste blanche réseau, injection de secrets via proxy MITM, et isolation au niveau de la VM. Démarre en moins d'une seconde, prend en charge les SDK Go, Python et TypeScript.
Expérimental : Ce projet est encore en développement actif et peut subir des changements majeurs.
Matchlock est un outil en ligne de commande (CLI) pour exécuter des agents IA dans des micro-VM éphémères – avec une liste blanche réseau, une injection de secrets via un proxy MITM et un isolement au niveau de la VM. Vos secrets n’entrent jamais dans la VM.
Les agents IA ont besoin d’exécuter du code, mais leur donner un accès sans restriction à votre machine est risqué. Matchlock vous permet de fournir à un agent un environnement Linux complet qui démarre en moins d’une seconde – isolé et jetable.
Lorsque vous passez --allow-host ou --secret, Matchlock verrouille le réseau – seul le trafic vers les hôtes explicitement autorisés passe, tout le reste est bloqué. Quand votre agent appelle une API, les vraies identifiants sont injectés en vol par l’hôte. Le sandbox ne voit jamais qu’un espace réservé. Même si l’agent est trompé en exécutant quelque chose de malveillant, vos clés ne fuient pas et il n’y a nulle part où envoyer les données. À l’intérieur, l’agent dispose d’un environnement Linux complet pour faire ce dont il a besoin. Il peut installer des paquets, écrire des fichiers et faire du désordre. À l’extérieur, votre machine ne ressent rien. Les montages par overlay de volume sont des instantanés isolés qui disparaissent une fois terminés. Même CLI et même comportement, que vous soyez sur un serveur Linux ou un MacBook.
Voir docs/install.md pour les détails complets d’installation.
Installation rapide
Le script ci-dessous détecte le système d’exploitation et installe Matchlock avec Homebrew sur macOS et avec rpm/deb sur les distributions Linux Debian/RHEL.
curl -fsSL https://raw.githubusercontent.com/jingkaihe/matchlock/main/scripts/install.sh | bash
# Ou installer une version spécifique
curl -fsSL https://raw.githubusercontent.com/jingkaihe/matchlock/main/scripts/install.sh | bash -s -- --version 0.2.4
Homebrew
L’installation via Homebrew est prise en charge aussi bien sur macOS que sur Linux :
brew tap jingkaihe/essentials
brew install matchlock
Debian / Ubuntu (.deb)
sudo dpkg -i ./matchlock_<version>_linux_amd64.deb
sudo apt-get install -f
matchlock diagnose
Fedora / RHEL / CentOS Stream (.rpm)
sudo dnf install ./matchlock_<version>_linux_amd64.rpm
matchlock diagnose
Si matchlock diagnose signale une configuration hôte manquante, exécutez :
sudo matchlock setup linux
Pour enrôler explicitement un utilisateur spécifique, exécutez :
sudo matchlock setup user <name>
# Basique
matchlock run --image alpine:latest cat /etc/os-release
matchlock run --image alpine:latest -it sh
matchlock run --image alpine:latest --no-network -- sh -lc 'echo offline'
# Liste blanche réseau
matchlock run --image python:3.12-alpine \
--allow-host "api.openai.com" python agent.py
# Garder l’interception activée même avec une liste blanche vide,
# afin que les hôtes puissent être ajoutés/supprimés en cours d’exécution.
matchlock run --image alpine:latest --rm=false --network-intercept
matchlock allow-list add <vm-id> api.openai.com,api.anthropic.com
matchlock allow-list delete <vm-id> api.openai.com
# Injection de secrets (n’entre jamais dans la VM)
export ANTHROPIC_API_KEY=sk-xxx
matchlock run --image python:3.12-alpine \
--secret [email protected] python call_api.py
# Sandbox longue durée
matchlock run --image alpine:latest --rm=false # affiche l’ID de la VM
matchlock run --image nginx:latest -d # identique à ci-dessus, détaché
matchlock exec vm-abc12345 -it sh # s’y attacher
matchlock port-forward vm-abc12345 8080:8080 # forward hôte:8080 -> invité:8080
# Publier des ports au démarrage
matchlock run --image alpine:latest --rm=false -p 8080:8080
# Cycle de vie
matchlock list | kill | rm | prune
# Construire à partir d’un Dockerfile (utilise BuildKit-in-VM)
matchlock build -f Dockerfile -t myapp:latest .
# Pré-construire le rootfs à partir d’une image registre (met en cache pour un démarrage plus rapide)
matchlock build alpine:latest
# Gestion des images
matchlock image ls # Lister toutes les images
matchlock image rm myapp:latest # Supprimer une image locale
docker save myapp:latest | matchlock image import myapp:latest # Importer depuis une archive tar
Matchlock propose des SDK en Go, Python et TypeScript pour intégrer des sandbox directement dans votre application. Vous pouvez lancer des VM, exécuter des commandes, diffuser la sortie et gérer des fichiers par programme.
Go
package main
import (
"context"
"fmt"
"os"
"github.com/jingkaihe/matchlock/pkg/sdk"
)
func main() {
ctx := context.Background()
client, err := sdk.NewClient(sdk.DefaultConfig())
if err != nil {
panic(err)
}
defer client.Close(0)
defer client.Remove()
sandbox := sdk.New("alpine:latest").
AllowHost("dl-cdn.alpinelinux.org", "api.anthropic.com").
AddSecret("ANTHROPIC_API_KEY", os.Getenv("ANTHROPIC_API_KEY"), "api.anthropic.com")
if _, err := client.Launch(sandbox); err != nil {
panic(err)
}
if _, err := client.Exec(ctx, "apk add --no-cache curl"); err != nil {
panic(err)
}
// La VM ne voit jamais qu'un espace réservé - la vraie clé n'entre jamais dans le sandbox
result, err := client.Exec(ctx, "echo $ANTHROPIC_API_KEY")
if err != nil {
panic(err)
}
fmt.Print(result.Stdout) // affiche "SANDBOX_SECRET_a1b2c3d4..."
curlCmd := `curl -s --no-buffer https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-haiku-4-5-20251001","max_tokens":1024,"stream":true,
"messages":[{"role":"user","content":"Explain TCP to me"}]}'`
if _, err := client.ExecStream(ctx, curlCmd, os.Stdout, os.Stderr); err != nil {
panic(err)
}
}
Comportement des IP privées dans le SDK Go (10/8, 172.16/12, 192.168/16) :
.WithBlockPrivateIPs(true) (ou .BlockPrivateIPs())..AllowPrivateIPs() ou .WithBlockPrivateIPs(false).sandbox := sdk.New("alpine:latest").
AllowHost("api.openai.com").
AddHost("api.internal", "10.0.0.10").
WithNetworkMTU(1200).
AllowPrivateIPs() // surcharge explicite : block_private_ips=false
// Interception réseau SDK (mutation requête/réponse, mise en forme du corps, transformation des lignes de données SSE)
sandbox = sandbox.WithNetworkInterception(&sdk.NetworkInterceptionConfig{
Rules: []sdk.NetworkHookRule{
{
Phase: sdk.NetworkHookPhaseBefore,
Action: sdk.NetworkHookActionMutate,
Hosts: []string{"api.openai.com"},
SetHeaders: map[string]string{"X-Trace-Id": "trace-123"},
},
{
Phase: sdk.NetworkHookPhaseAfter,
Action: sdk.NetworkHookActionMutate,
Hosts: []string{"api.openai.com"},
BodyReplacements: []sdk.NetworkBodyTransform{
{Find: "internal-id", Replace: "redacted"},
},
},
},
})
Si vous utilisez client.Create(...) directement (sans le constructeur), définissez :
BlockPrivateIPsSet: trueBlockPrivateIPs: false (ou true)Pour des sandbox totalement hors ligne (pas de carte réseau invitée / pas de trafic sortant), utilisez :
--no-network.WithNoNetwork().with_no_network().withNoNetwork()Python (PyPI)