在加固的隔离环境中执行不受信任的 Python、JavaScript 和 Bash 代码,并设有 5 秒、128 MB、0.5 核、PID 及输出限制。
由内核强制执行的不可信代码执行——每个载荷都被 cgroups v2、命名空间、seccomp-BPF 和只读 rootfs 隔离,且每次运行都在 PostgreSQL 中审计。
python · javascript · bash → 5 秒、128 MB、0.5 核、32 PID、512 KB 输出的隔离环境
一个针对你不信任的代码的安全加固执行服务。调用方通过一个小型 REST API 提交源代码;守护进程将每个载荷启动到一个临时内核隔离环境中,由 Linux 内核本身——而非应用逻辑——保证隔离:
pivot_root 到只读 rootfs),lo 关闭 + seccomp 终止 socket),PID · MOUNT · NET · IPC · UTS · USER)、严格的 seccomp-BPF 允许列表、cgroups v2 资源隔离,以及带 16 MB tmpfs 暂存空间的只读 pivot_root 文件系统。5 秒墙钟超时、128 MB 内存上限(禁用 swap,立即 OOM 终止)、0.5 个 CPU 核、pids.max = 32 的 fork 炸弹免疫能力,以及 stdout/stderr 的 512 KB 输出上限。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
| 组件 | 职责 | 源码 |
|---|---|---|
| 摄取守护进程 | REST 接口:POST /api/v1/execute + /health;请求校验;异步审计事件发送 | cmd/server/main.go |
| 热运行器池 | 信号量限定的执行槽位(16 个),获取超时为 3 秒 → 以 503 风格的耗尽背压响应 | internal/runner/pool.go |
| 进程运行器 | 构建语言命令,附加 cgroup,通过截断写入器流式传输管道,执行 5 秒看门狗,采集 cgroup 指标,对结果进行分类 | internal/runner/process.go |
| 内核隔离 | cgroups v2 限制器(memory.max、cpu.max、pids.max),命名空间标志(CLONE_NEWPID/NET/NS/IPC/UTS/USER),seccomp-BPF 过滤器编译器 | internal/isolation/ |
| sandbox_init | 子进程跳板:只读 pivot_root + tmpfs /dev//tmp,网络分离(lo 关闭),应用 seccomp,然后对目标执行 syscall.Exec | cmd/sandbox_init/main.go |
| 不可信代码 | 客户负载。剥离宿主设备,隐藏 /proc(hidepid=2),终止所有未列入允许列表的系统调用 | runtimes/ rootfs 镜像 |
| PostgreSQL 16 | 每次运行的持久审计日志,包括安全违规 | migrations/001_init_sandbox_schema.sql |
| Redis 7 | sandbox:jobs 队列 + BRPop 工作进程排空到池中 (模块已实现,尚未接入守护进程——见已知限制) | internal/queue/redis_consumer.go |
| 边界 | 分隔内容 | 执行机制 |
|---|---|---|
| 客户端 ↔ 守护进程 | 来自控制平面的未认证负载提交 | 模式校验(tenant_id、language、code) |
| 控制平面 ↔ 隔离环境 | 可信 Go 代码 vs. 恶意负载 | fork 进入私有命名空间;pivot_root;seccomp 在 exec 时继承 |
| 隔离环境 ↔ 内核限制 | 客户资源消耗 vs. 宿主容量 | cgroups v2 memory.max=128MB、swap.max=0、cpu.max="50000 100000"、pids.max=32 |
| 隔离环境 ↔ 网络 | 任何出站流量或宿主侧可达性 | 私有 NET 命名空间,lo 关闭,socket 系统调用被终止 |
🔍 此图表的交互式、主题感知版本(支持 PNG/SVG 导出)由
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
C->>A: POST /api/v1/execute
A->>P: acquire slot · 16 max, 3 s timeout
P->>R: Run(req, limits)
R->>I: fork under CLONE_NEWPID·NET·NS·IPC·UTS·USER
R->>R: create cgroup scope → attach PID<br/>128 MB · 0.5 CPU · 32 PIDs
I->>I: pivot_root RO rootfs · lo down · seccomp-BPF
I->>G: syscall.Exec target interpreter
G-->>R: stdout / stderr via pipes (512 KB cap)
R->>R: watchdog: SIGKILL at 5 s → exit 137
R-->>P: result + cgroup metrics (peak mem, CPU)
P-->>A: ExecutionResult
A-->>C: 200 JSON
A-)DB: async audit INSERT (non-blocking)
分步说明:
POST 提交 JSON(tenant_id、language、code,可选 stdin/limits)。格式错误或不支持的载荷会快速失败,返回 400/422。sandbox_init 切换到只读 rootfs,挂载带配额的 tmpfs,拆除 lo,安装 seccomp-BPF 允许列表,然后 exec 解释器 — 载荷永远不会以父进程的权限运行。memory.max(干净的 OOM 终止);fork 炸弹在 pids.max = 32 处被拒绝;socket/ptrace/mount 调用被内核终止(SIGSYS/SIGKILL → SECURITY_VIOLATION)。execution_runs 中,该 goroutine 有自己的 2 秒预算,因此持久化永远不会阻塞或泄漏到响应延迟中。| 层级 | 技术 | 作用 |
|---|---|---|
| 语言 | Go 1.27(github.com/kavaryx/sandboxed-runner) | 守护进程、运行器、隔离、测试 |
| 内核隔离 | cgroups v2 · namespaces · seccomp-BPF(libseccomp-golang) · pivot_root | 遏制执行 |
| 运行时镜像 | 最小化 Python / Node rootfs(Docker 构建,runtimes/*.tar) | 只读客户机文件系统 |
| API | net/http 标准库(REST,JSON) | 摄取 + 健康检查 |
| 队列 | Redis 7(go-redis/v9)— 在 sandbox:jobs 上使用 LPUSH/BRPop | 异步作业管道 (模块) |
| 持久化 | PostgreSQL 16(lib/pq) | 持久化执行审计 |
| 工具 | Docker Compose · Makefile · go test | 开发、构建、安全测试 |