
Exécute du code Python, JavaScript et Bash non fiable dans une prison renforcée avec des limites de 5 secondes, 128 Mo, 0,5 cœur, de PID et de sortie.
Exécution de code non fiable imposée par le noyau — chaque charge utile est confinée par cgroups v2, namespaces, seccomp-BPF et un rootfs en lecture seule, et chaque exécution est auditée dans PostgreSQL.
python · javascript · bash → bac à sable de 5 secondes, 128 Mo, 0,5 cœur, 32 PID, sortie de 512 Ko
Un service d'exécution renforcé pour la sécurité, destiné au code auquel vous ne faites pas confiance. Les appelants soumettent le code source via une petite API REST ; le démon lance chaque charge utile dans une prison éphémère au niveau du noyau où le noyau Linux lui-même — et non la logique applicative — garantit le confinement :
pivot_root vers un rootfs en lecture seule),lo désactivé + seccomp qui tue socket),PID · MOUNT · NET · IPC · UTS · USER), une liste blanche seccomp-BPF stricte, des prisons de ressources cgroups v2, et un système de fichiers pivot_root en lecture seule avec un espace de travail tmpfs de 16 Mo.5 s en temps réel, plafond mémoire de 128 Mo (swap désactivé, OOM kill instantané), 0,5 cœur CPU, immunité aux fork bombs via pids.max = 32, et plafonds de sortie de 512 Ko sur stdout/stderr.execution_runs).flowchart LR
CLI["👤 API Client<br/><i>tenant / CI job</i>"]
subgraph CP["🔐 Trusted Control Plane — Go daemon"]
API["Ingestion Daemon<br/><i>net/http :8080</i>"]
POOL["Warm Runner Pool<br/><i>16 slots · 3 s cap</i>"]
RUN["Process Runner<br/><i>watchdog + pipes</i>"]
ISO["Kernel Isolation<br/><i>cgroups v2 · namespaces · seccomp-BPF</i>"]
end
subgraph JAIL["⛓️ Ephemeral Kernel Jail — untrusted"]
INIT["sandbox_init<br/><i>exec trampoline</i>"]
GUEST["💀 Untrusted Code<br/><i>python · node · bash</i>"]
end
PG[("🗄️ PostgreSQL 16<br/><i>execution_runs</i>")]
RD[("📮 Redis 7 Queue<br/><i>sandbox:jobs</i>")]
CLI -->|"POST /api/v1/execute"| API
API -->|"validate + acquire"| POOL
POOL -->|"spawn + limits"| RUN
RUN -.->|"apply jail"| ISO
ISO ==>|"seccomp · pivot_root"| GUEST
RUN -->|"fork / exec"| INIT
INIT -->|"syscall.Exec"| GUEST
RUN -.->|"stdout / stderr ≤ 512 KB"| POOL
API -.->|"async audit INSERT"| PG
RD -.->|"BRPop drain · worker module"| POOL
style JAIL fill:#2a1215,stroke:#f87171,stroke-width:2px
style CP fill:#0d1b2a,stroke:#38bdf8,stroke-width:1px
| Composant | Responsabilité | Source |
|---|---|---|
| Démon d'ingestion | Surface REST : POST /api/v1/execute + /health ; validation des requêtes ; émission d'audit asynchrone | cmd/server/main.go |
| Pool de runners préchauffés | Emplacements d'exécution bornés par sémaphore (16) avec un délai d'acquisition de 3 s → backpressure d'épuisement de type 503 | internal/runner/pool.go |
| Runner de processus | Construit la commande du langage, attache le cgroup, diffuse les pipes via des writers tronquants, applique le watchdog de 5 s, collecte les métriques du cgroup, classe les résultats | internal/runner/process.go |
| Isolation du noyau | Limiteur cgroups v2 (memory.max, cpu.max, pids.max), drapeaux de namespaces (CLONE_NEWPID/NET/NS/IPC/UTS/USER), compilateur de filtres seccomp-BPF | internal/isolation/ |
| sandbox_init | Trampoline enfant : pivot_root en lecture seule + tmpfs /dev//tmp, détachement réseau (lo désactivé), application de seccomp, puis syscall.Exec de la cible | cmd/sandbox_init/main.go |
| Code non fiable | La charge utile invitée. Périphériques hôtes retirés, /proc masqué (hidepid=2), tous les appels système non autorisés tués | images rootfs runtimes/ |
| PostgreSQL 16 | Journal d'audit durable de chaque exécution, y compris les violations de sécurité | migrations/001_init_sandbox_schema.sql |
| Redis 7 | File sandbox:jobs + worker BRPop drainant vers le pool (module implémenté, pas encore câblé dans le démon — voir Limitations connues) | internal/queue/redis_consumer.go |
| Frontière | Ce qu'elle sépare | Application |
|---|---|---|
| Client ↔ Démon | Soumission de charge utile non authentifiée depuis le plan de contrôle | validation de schéma (tenant_id, language, code) |
| Plan de contrôle ↔ Prison | Code Go de confiance vs. charge utile hostile | fork dans des namespaces privés ; pivot_root ; seccomp hérité à l'exécution |
| Prison ↔ Limites du noyau | Consommation de ressources de l'invité vs. capacité de l'hôte | cgroups v2 memory.max=128MB, swap.max=0, cpu.max="50000 100000", pids.max=32 |
| Prison ↔ Réseau | Toute sortie ou accessibilité côté hôte | namespace NET privé, lo désactivé, appel système socket tué |
🔍 Une version interactive et adaptée au thème de ce diagramme (avec export PNG/SVG) est générée à partir des candidats étayés par des preuves dans
docs/archify/.
sequenceDiagram
autonumber
participant C as Client
participant A as REST API
participant P as Warm Pool
participant R as Process Runner
participant I as sandbox_init
participant G as Untrusted Code
participant DB as PostgreSQL