← 全部学习页

10 虚拟机与沙箱 · 进程的运行环境

只隔离一个命令,
也能划清环境边界

进程级沙箱给命令一份受限的目录视图和网络环境,无需准备整套容器镜像。

约 15 分钟 · 截至 2026-11-06,Ubuntu 26.04 LTS · 命令实验未实测

宿主机 · 同一个 Linux 内核 根目录 / · 只读视图/usr · /etc · /home仍可读取有权限读的文件 一个命令及其子进程 读取 工作目录 · 可读写~/bwrap-lab/work绑定宿主目录,产物会留下 写入 外网:无出口 bwrap 配置这份进程环境 宿主机 · 同一个 Linux 内核 根目录 / · 只读视图/usr、/etc、/home 仍可读取 读取 一个命令及其子进程 写入 工作目录 · 可读写~/bwrap-lab/work 外网:无出口
  • 宿主与只读根目录
  • 工作目录与产物
  • 出口代理与请求见图 4
图 1 同一个命令可以读取系统文件、只向指定宿主目录写入,同时没有直接通向外网的路由。

学完你能

命令边界

沙箱改变环境,命令仍用同一个内核

进程级沙箱是围绕一个命令及其子进程设置的运行边界。比如让 agent 编译项目:它需要读编译器和依赖、写构建产物,却未必需要写整个主目录或连接外网。边界明确后,同一台电脑上的任务也更容易各自运行。

bubblewrap(命令名 bwrap)是 Linux 上用来搭这份环境的低层工具。它先创建空的挂载命名空间,也就是这组进程自己的“路径到文件”的视图,再把选定路径挂进去。你可以复用宿主的软件,无需先制作镜像;相应地,它也不会替你锁定软件版本。[1–2]

命令的环境 · 逐步收紧 普通命令 读取 写入 根目录 /原有用户权限 写入 工作目录原有用户权限 网络出口共享宿主网络 原有进程环境 加只读根目录 读取 写入 根目录 /只读,仍可读取 写入 工作目录只读 网络出口共享宿主网络 原有进程环境 放开工作目录 读取 写入 根目录 /只读,仍可读取 写入 工作目录可读写,产物保留 网络出口共享宿主网络 原有进程环境 再隔离网络 读取 写入 根目录 /只读,仍可读取 写入 工作目录可读写,产物保留 网络出口无外网路由 原有进程环境 补齐运行环境 读取 写入 根目录 /只读,仍可读取 写入 工作目录可读写,产物保留 网络出口无外网路由 独立 PID、最小环境变量 命令退出 读取 写入 根目录 /只读,仍可读取 写入 工作目录可读写,产物保留 网络出口无外网路由 临时视图回收,产物留下
  1. 先看普通命令:“完全放开”指没有额外沙箱,仍受原有用户权限约束。它能使用宿主允许的文件与网络。
  2. 把 / 只读挂入新视图:--ro-bind / /。系统程序还在,但通过这份挂载不能写。先猜:工作目录也在 / 下,此时还能保存构建产物吗?
  3. 再用 --bind 把工作目录覆盖为可写挂载。保存位置明确了,写入会落到宿主的原目录。
  4. 用 --unshare-net 创建独立网络命名空间,不接宿主网卡,也不配置外网路由。先猜:只读的主目录会因此变得不可读吗?
  5. 补上独立的进程编号空间及对应的 /proc、最小 /dev,清理继承的环境变量。路径、进程和变量是不同的设置项。
  6. 命令退出,临时视图随沙箱进程结束回收。工作目录是绑定的宿主目录,产物仍在;这不是把写入回滚。
图 2 文件、网络和进程环境分别收紧;增加一条限制,并不会自动补齐其他边界。

只读不等于不可读。图中的 --ro-bind / / 仍暴露当前用户本来能读的文件,包括主目录里的文件。如果任务还要求“只看见项目”,就要从空视图只挂入必要路径,或另外配置读取限制;不能把这张教学图当作完整产品配置。

预测与验证

先读配置,再预测每一次访问

先准备两个相邻目录:work 存产物,other 留在只读视图中。以下命令在你自己的 Bash 终端运行,不要给 bwrap 加 sudo。安装包用系统管理员权限,运行沙箱用普通用户身份。选项含义依据 Ubuntu 的 bwrap(1)。

sudo apt install bubblewrap curl
mkdir -p "$HOME/bwrap-lab/work" "$HOME/bwrap-lab/other"
printf 'readable\n' > "$HOME/bwrap-lab/other/note.txt"
cd "$HOME/bwrap-lab/work"
workdir="$(pwd -P)"

命令中的两次 "$workdir" 分别是宿主来源与沙箱目标:同一路径、同一批文件。--chdir 只设置起始工作目录;允许写入的是前面的挂载配置。

bwrap --ro-bind / / --bind "$workdir" "$workdir" --unshare-net --unshare-pid --proc /proc --dev /dev --new-session --die-with-parent --clearenv --setenv PATH /usr/bin:/bin --setenv HOME "$workdir" --chdir "$workdir" /bin/bash --noprofile --norc

启动成功后,哪组预测符合这份配置?假设原有文件权限允许读取,work 归你所有。

选第二组。--bind 只为 work 建立可写挂载,其他宿主目录仍在只读视图中。--unshare-net 改变网络环境,和你 cd 到哪个目录无关。

现在在新打开的沙箱 Bash 中逐行验证。预期是:第一行创建文件,第二行写入被拒绝,第三行能读到先前准备的文本;第四行不能建立到外网的 HTTP 连接。curl 需已安装,若提示找不到命令,只说明缺工具,不能作为断网证据。--clearenv 清除了继承的代理变量,这里又用 IP 地址避开域名解析;不把 DNS 失败误当成网络隔离。

touch ./inside.txt
touch ../other/outside.txt
cat ../other/note.txt
curl --head --connect-timeout 3 http://1.1.1.1
exit

退出后,在原终端用 ls ./inside.txt 查看产物。它应仍然存在,因为可写挂载指向宿主目录。--setenv HOME 只是让程序把这里当作主目录,--clearenv 只清变量;它们都不会让原主目录从只读视图中消失。

深入一点:启动失败时,先检查哪一层?

如果连新 Bash 都没打开,先区分工具是否安装、内核是否允许用户命名空间、外层容器是否限制相关系统调用,以及 Ubuntu 的 AppArmor 策略是否允许该程序使用用户命名空间。这和“沙箱内写文件被拒绝”是不同阶段。不要为了跑通实验全局关闭隔离;换到合适的虚拟机,或对照官方排查说明检查配置。

/proc 是内核提供的进程信息接口,/dev 提供基础设备接口。这里的“只放开工作目录”指普通宿主目录的写入;这些新建的内核接口不能当作普通磁盘文件来理解。此例没有另设 CPU/内存配额,也没有完整过滤系统调用或文件套接字。

同伴说:“把 --ro-bind 改成 --bind / /,再保持 HOME 指向 work,就能保留相同的写入边界。”你怎么判断?

HOME 是程序读取的环境变量,不是内核的挂载权限。

文件与网络分别配置,断网不会把文件系统变成只读。

--bind / / 会撤掉这层只读挂载限制。原有用户权限仍在,所以它不会让普通用户随意写系统文件,但会重新允许许多原本能写的个人文件。限制来自挂载方式,不来自 HOME。

内核规则

Landlock 限制动作,不必重画目录树

Landlock 让普通进程也能为自己和未来的子进程追加访问限制。例如程序保留原来的路径视图,却只允许写项目目录。已有用户权限和其他内核策略仍要同时满足:Landlock 不能凭空授予原本没有的权限。[3]

bwrap:重组“看见的目录树”

命令调用写文件 经过挂载视图 其他目录:只读工作目录:可读写同一文件可映射到指定位置

Landlock:追加“允许哪些动作”

命令调用写文件 经过内核规则 路径视图可以不变规则允许写,才继续原有用户权限仍然有效
图 3 重组挂载与限制动作是两种方法,都仍由当前 Linux 内核执行。

因此,判断边界时要问两个问题:进程看到什么?它可以对这些资源做什么? bwrap 主要帮你组装视图,Landlock 在支持的动作上追加规则;工具也可以组合多种机制。它们都不会自动提供虚拟机那样的独立内核。

把四个描述归到负责的机制。按“由谁实现这个具体动作”分类。

  • 将宿主 work 挂到沙箱内指定路径
  • 把根目录以只读方式挂入
  • 进程为自己追加文件访问规则
  • 未来子进程继承这些追加限制
bwrap 的挂载配置
Landlock 的访问规则

前两项回答“文件树如何呈现”,后两项回答“进程受到哪些额外动作限制”。路径仍然可见,并不保证对它的每种操作都允许。

深入一点:有 Landlock,就能限制所有网络访问吗?

不能这样推断。运行器要探测内核提供的接口版本,再选择支持的规则;不同版本支持的文件、网络等动作范围不同。Landlock 也不是按域名维护白名单的 HTTP 代理。看到产品写“使用 Landlock”,仍要继续查它实际启用了哪些规则,以及不支持时如何处理。

实际案例

agent 的运行环境由几层边界共同组成

把 agent 当作能干的协作者:你给它项目、工具链和完成任务所需的访问范围。本地命令沙箱回答“这一条命令能接触哪里”;云端会话回答“这一整份环境放在哪里、如何与其他任务分开”。两者可以叠加,出口代理和凭据管理又各有职责。

会话边界 · 容器或虚拟机 命令进程的权限边界(可叠加) agent 的命令 工作目录 读写 工具链、依赖与临时文件在这里任务结束前提交或导出需要的产物 出口 发出请求 出口代理检查目标 · 代为认证 放行请求 远端服务验证凭据 凭据存储(边界外) 取出匹配凭据凭据加入离开会话后的请求,不写进工作目录或环境变量 会话边界 · 容器或虚拟机 命令进程的权限边界(可叠加) agent 的命令 工作目录 读写 工具链、依赖与临时文件任务结束前提交或导出产物 出口 发出请求 出口代理 · 检查目标允许后代为认证 凭据存储会话之外 取凭据 放行请求此时已加入匹配凭据 远端服务验证凭据 原始凭据不进入会话不写进工作目录或环境变量
图 4 分层组合示意:命令在会话内执行,请求在会话外经过检查和认证,原始凭据保留在边界外。
  1. 本地运行时:限制命令的文件与网络。截至 2026-11-06,Claude Code 官方说明其命令沙箱在 Linux 使用 bubblewrap,在 macOS 使用 Seatbelt(macOS 的进程访问限制机制)。规则会作用到命令及其子进程;这不等于每种文件工具、插件或外部服务都在同一边界里。[4–5]
  2. 云端会话:为任务准备一份环境。平台可以按任务创建临时容器或虚拟机,再回收环境;需要留下的代码和产物先提交或导出。容器共享宿主内核,虚拟机有自己的来宾内核。microVM 是设备模型经过裁剪的轻量虚拟机,例如 Firecracker;不能仅凭“云端沙箱”就判断用了哪种实现。[7]
  3. 网络出口:让必要的请求有路可走。完全断网适合离线构建;要拉依赖时,可以只经代理访问允许的目标。代理按目标放行,具体协议、地址和规则仍以产品配置为准。
  4. 凭据边界:允许使用服务,不一定交出密钥。代理可以在请求离开会话后加入匹配的认证信息。命令能完成授权范围内的访问,原始 token 却不用写进项目文件或环境变量。凭据的作用范围还可回看密钥与凭据怎么保管。

把示意落到一个具体案例:截至 2026-11-06,Claude Code 云端官方文档说明,Anthropic 托管会话运行在隔离的 VM 中,提供网络访问控制;Git 凭据与签名密钥留在沙箱外,由代理代为认证。其 network secrets(按请求目标使用的网络密钥)同样在请求离开会话后加入。这里按文档写 VM,不推断它是 microVM;自托管环境的凭据与出口由部署方负责。[6]

这些是特定产品、特定功能的配置方式,不是所有 agent 的共同默认值。尤其是你自己放进环境变量的 token,不会因为“用了沙箱”就自动搬到外部代理。并且云端的“关闭网络”仍可能保留模型服务通信,不能把它等同于上面的 bwrap 实验。

一个云端任务能读取私有仓库,但环境变量里没有 Git token。用两句话解释可能的结构,并说出还要检查哪个边界。

Git 请求可以经会话外的代理,由代理加入限定范围的凭据;命令因此无需持有原始 token。还要检查请求是否必须走代理、代理允许哪些仓库或操作,以及其他工具是否也走相同路径。

  • 区分“能使用服务”和“持有原始凭据”
  • 指出认证发生在会话之外
  • 指出出口与授权范围需要分别检查

取舍与回顾

隔离越细,越要明确任务依赖什么

边界收紧通常能减少共享与可访问范围,但会增加准备工具、挂入缓存、放行网络的工作。目标是让环境一致、并行任务互不干扰、权限范围可解释。因此先列任务依赖,再选边界:离线转换文件可能只需进程沙箱;需要固定系统依赖时用容器;需要独立内核时再看虚拟机。

同一个构建任务,收紧边界会改变哪些便利
收紧的边界得到什么要补充什么
系统目录只读,项目可写产物位置清楚工具的缓存与临时目录安排
不接外网,或只经出口代理联网范围清楚预备依赖,或列出所需域名与协议
每个任务一份容器环境工具链与文件环境可按任务配置镜像、依赖版本与产物保存
增加虚拟机边界使用独立来宾内核镜像、启动与资源管理

agent 已能在 work 保存文件,但安装依赖失败。任务确实需要访问一个包仓库。哪种调整更符合“明确边界”?

写目录和建立网络连接属于不同边界,调整前先看失败发生在哪一层。

虚拟机提供内核边界,网络出口和认证仍需各自配置。

已能保存文件,说明项目写入路径可用;取依赖还需要网络出口,私有仓库可能另需认证。先区分缺工具、缺路由、代理未放行和缺凭据,再补任务需要的那一项,才能解释调整后的环境。

运行边界说清之后,还需要知道长期运行的程序由谁启动、状态在哪里看。下一页进入服务与日志:systemd、systemctl、journalctl。

来源

来源与实测范围

核对日期:2026-11-06。Ubuntu 26.04 LTS 的命令语义按对应 man 页;产品实现按下列官方文档。此页没有声称实测通过的 Ubuntu 终端输出,练习依据配置语义预测。

  1. Ubuntu 26.04 LTS:bwrap(1):空挂载视图、绑定挂载、网络命名空间、环境设置与命令生命周期。
  2. bubblewrap 官方 README:工具定位、由调用者定义配置,以及示例与局限。
  3. Linux 内核:Landlock:无特权进程追加限制、子进程继承和内核接口兼容性。
  4. Anthropic:Claude Code sandboxing:Linux bubblewrap、macOS Seatbelt 与边界外代理。
  5. Claude Code:Sandboxing:命令沙箱的覆盖范围、网络控制、凭据配置和 Ubuntu 排查。
  6. Claude Code 云端:Security and isolation:托管 VM、出口控制、Git 凭据、签名密钥与 network secrets。
  7. Firecracker 官方介绍:使用 KVM 构建 microVM,与容器共享内核的结构不同。