
OpenShell 是 NVIDIA 开源的 agent 运行时,上 Hacker News 拿到 489 分。它管的事很具体:autonomous agent 要读文件、装包、调 API、用密钥,OpenShell 在 kernel 层拦下每一个动作。策略不靠 agent 自觉,而是靠 syscall 过滤、Landlock 文件隔离,再加一张 L7 网络策略网。和常规沙箱还不太一样,它多做了一层形式化验证:策略变更前先过 SMT 求解器,验证这次变更允许了什么新访问,人再批。我在本机把 CLI 和 gateway 都编译跑通了,机器、版本、踩的编译坑全放在文末。
为什么 agent 需要一层「抓现行」
agent 能力越大,越需要碰真实系统:装依赖、写输出目录、调付费 API。常规做法是扔进一个容器,容器本身就是安全边界,越狱就靠打镜像漏洞。OpenShell 的边界不在容器上:每个 agent 跑在独立 sandbox 里,kernel controls 直接限制它能访问哪些文件、能调哪些 syscall;每个出站连接在离开 sandbox 前,还要先过一道策略检查。agent 从头到尾看不到真实密钥,OpenShell 只在请求绑定到被批准的端点时才注入凭证。两条防线拆得很清:运行时拦越权,策略层在变更前做形式化证明。
机制拆到源码层

仓里 28 个 Rust crate,安全相关的是五个。openshell-sandbox 是执行体,linux/seccomp.rs 生成 syscall 白名单,linux/landlock.rs 把文件访问限制到声明的目录;openshell-supervisor 管进程生命周期和命名空间;openshell-network 做 L7 代理,每个 HTTP 请求逐条过策略引擎,拒绝事件带 OCSF 结构化日志(NetworkActivityBuilder,Severity 分四级);openshell-policy 是策略引擎本体,YAML 声明式;openshell-prover 是形式化验证器,背后是 SMT 求解器(z3 0.21,默认链系统 libz3,仓里留了 vendored-z3 和 prebuilt-z3 两个 feature 切编译方式)。
一条最小策略长这样(仓内 examples/policy-advisor/sandbox-policy.yaml):
version: 1
network_policies:
anthropic:
name: Anthropic API
endpoints:
- { host: api.anthropic.com, port: 443 }
只有这一个端点放行,其他出站连接全被 proxy 拦掉。agent 想访问别的 host,要么策略变更走 prover 验证再人工批,要么直接拒绝。这条「凭证只在批准的端点注入」的设计,把 agent 泄露密钥的爆炸半径压到了策略声明的那几行里。
本机把编译链跑通:z3 是第一道坎
本机 2 核 EPYC、rustc 1.95。仓 clone 下来 52MB(不含 target),workspace 默认 features 下 cargo build --release 第一挂点就在链接:rust-lld 找不到 -lz3,因为 openshell-prover 依赖 SMT 求解器 z3,默认走系统库。这台机器没 sudo 装 libz3-dev,切到仓里预留的 feature:
cargo build --release -p openshell-gateway --features vendored-z3
vendored 模式让 z3-sys 源码编译 C++ 版 z3(z3-src 501),它要 cmake,系统没有,用 uv 装静态 cmake(uv tool install cmake,落到 ~/.local 不碰系统)再跑。z3 C++ 全量 release 在这台 2 核上编了 29 分钟(out 目录最终 314MB,arith/solver 子模块是大头)。gateway 二进制 105,963,480 字节(106MB,链了 z3 静态库 + 全家桶依赖),CLI 二进制 26,573,136 字节(26.6MB),CLI 冷启动 --help 实跑 12ms。
编译时长账:openshell-cli 首编 wall 10 分 24 秒(其中 8 分 36 秒耗在 prover 依赖树,链接挂在缺 -lz3);带 vendored-z3 的 gateway 全量 build wall 33 分 38 秒(z3 C++ 本体 29 分钟 + 28 个 Rust crate + 链接),峰值内存 2.85GB。对照 Proa 基准仓首编 6 分 33 秒,OpenShell 的依赖树重了一个档次(gRPC/tonic + SMT + 容器驱动全家桶)。
起本地 gateway + 沙箱:越权序列实跑
Docker 驱动 + 本地 mTLS gateway 的最小起法(命令全文见文末):gateway 起在 127.0.0.1:17670,CLI 走 mTLS 注册(client 证书放 XDG_CONFIG_HOME/openshell/gateways/<name>/mtls/),sandbox create 后 60 秒内进 Ready。
沙箱起好后自动套了一层默认策略,sandbox get demo 直接把它打出来:/bin、/usr、/lib、/etc、/var/log 全只读,/tmp 读写,Landlock compatibility 设成 best_effort。三条越权序列:
| 动作 | 结果 |
| sandbox exec echo 正常命令 | 通,单次 exec wall 278ms |
| touch /etc/probe(只读区) | Permission denied,被 Landlock 拦 |
| echo probe > /tmp/wool.txt | 通,写入成功读回 |
278ms 是一次 exec 的完整链路:CLI → mTLS gRPC → gateway → supervisor → 沙箱内进程 → 结果回传,全过一遍代理层。默认策略的 Landlock 段是声明式 YAML,agent 要访问新目录得走「策略变更请求 → 形式化验证 → 人工批」的流程。这一层本机没独立驱动 prover 跑,按官方 README 描述引用。
还没复跑的部分
Kubernetes 多租户形态没验(本机无集群);形式化验证器(prover)在本机没有现成入口独立驱动它跑一条策略变更证明(prover-cli 依赖 z3 编译成功,但仓内 e2e 走 with-docker-gateway.sh 全套,单机跑通最小证明的路径还在挖)。本文背书编译数字、机制拆解与最小沙箱 demo 的三条越权序列输出,形式化验证(prover)一节按官方 README 描述引用,未独立复跑。
FAQ
问:agent 被关在 sandbox 里,它怎么调 API?
答:出站流量全走 openshell-network 的 L7 代理,代理逐条过策略;被批准的端点由 OpenShell 注入凭证,agent 进程本身拿不到密钥明文。
问:Landlock 和 seccomp 分工是什么?
答:Landlock 管文件路径级读写权限(agent 只能碰策略声明的目录),seccomp 管 syscall 白名单(禁掉的系统调用直接被 kill 或 seccomp-notify 拦截),两层正交,源码在 openshell-sandbox/src/sandbox/linux/ 下两个独立文件。
问:为什么 NVIDIA 做这个?
答:NV 的 agent 负载跑在自家 GPU 集群上,agent fleet 的凭证/文件边界是运维真问题;OpenShell 0.1.x 主打 stable 发布节奏 + 形式化策略变更审查,走的是「给 agent 集群画图」而不是「给单个 agent 加壳」。
问:普通开发者能直接用吗?
答:能。单机 Docker 起 gateway 加 sandbox create demo 即可,K8s 场景走 Helm。前提是你愿意写策略 YAML——agent 每要一个新 host,走一次「变更请求 → prover → 人工批」的流程。
问:z3 依赖会不会拖慢所有部署?
答:只有需要形式化验证策略变更的 gateway 才链 z3;不开 vendored/prebuilt 的默认构建链系统 libz3,装了系统库的机器无感。
你是哪一派
在写 agent 产品、要管凭证边界的,OpenShell 是目前唯一把「策略变更前形式化证明」做成默认流程的开源件,值得拉下来跑一遍 demo 再评估;纯跑本地单 agent、没有 fleet 概念的,一层容器就够了,形式化验证是 overkill;做合规审计的,OCSF 结构化安全日志(四级 Severity)直接对得上 SIEM 输入格式。这类 agent 运行时安全边界的讨论,在云栈社区也能找到更多实战样本。
资料出处
NVIDIA/OpenShell 官方仓(28 crate,Apache-2.0,rustc 1.94 要求,本机 1.95):crates/openshell-sandbox/src/sandbox/linux/{seccomp,landlock}.rs、examples/policy-advisor/sandbox-policy.yaml、Cargo.toml z3=0.21 段、e2e/with-docker-gateway.sh。本机实测:openshell-cli 与 openshell-gateway 编译时长、二进制大小、CLI 冷启动(/usr/bin/time -v 原始输出在项目 results/ 落盘),机器 2 核 EPYC / 8GB / 2026-10-23。形式化验证一节引用官方 README「Formally verified policy changes」段,未独立复跑。
可复现命令(本机 2 核 EPYC / rustc 1.95 / Docker 29.7)
# 编译(z3 走 vendored,避免系统 libz3 缺失;cmake 用 uv 装不碰系统)
git clone --depth 1 https://github.com/NVIDIA/OpenShell
cd OpenShell
uv tool install cmake
export PATH="$HOME/.local/share/uv/tools/cmake/bin:$PATH"
cargo build --release -p openshell-cli
cargo build --release -p openshell-gateway --bin openshell-gateway --features vendored-z3
# 拉运行时镜像
docker pull ghcr.io/nvidia/openshell/sandbox:dev
docker pull ghcr.io/nvidia/openshell/supervisor:dev
docker pull nvcr.io/nvidia/base/ubuntu:24.04
# 起本地 mTLS gateway(certificate/JWT 配置照仓内 e2e/with-docker-gateway.sh 的模板手搓)
./target/release/openshell-gateway generate-certs --output-dir state/pki
# ...state/gateway.toml(绝对路径,gateway_jwt 段用 Ed25519 密钥对)...
./target/release/openshell-gateway --config state/gateway.toml --bind-address 127.0.0.1 \
--port 17670 --health-port 17671 --compute-driver docker \
--tls-cert state/pki/server/tls.crt --tls-key state/pki/server/tls.key \
--db-url "sqlite:state/gateway.db?mode=rwc" --tls-client-ca state/pki/ca.crt
# CLI 注册 + 建沙箱 + 越权序列
export XDG_CONFIG_HOME=$PWD/state/xdg
openshell gateway select local1023
openshell sandbox create --name demo
openshell sandbox get demo # 打出默认策略(/etc 只读 /tmp 读写)
openshell sandbox exec demo -- touch /etc/probe # → Permission denied
踩过的两个编译坑:① 默认 features 链接挂在 -lz3(prover 依赖 SMT solver),这台机器没 sudo 装 libz3-dev,切 --features vendored-z3 让 z3-sys 源码编译;② 源码编译 z3 要 cmake,uv tool install cmake 落 ~/.local 不碰系统。跑通后 gateway 端日志能看到 gateway-minted sandbox JWT 这行,launch-scoped 认证就通了。