第32章 Omnigent OS 沙箱配置指南
OS 沙箱配置
Omnibox 是 Omnigent 为任意 Agent 提供的操作系统级安全沙箱。在 Linux 和 macOS 上,它在操作系统层面限制文件系统和网络访问,隐藏 Agent 的凭证,并代理对凭证的访问权限。你可以以最小权限运行 Agent,或在无人值守的 YOLO 模式下将其锁定执行。
OS 沙箱限制了 Agent 可执行的命令和文件操作。它控制 Agent 可读取和写入哪些文件、是否可访问网络,以及 Agent 能看到哪些环境变量。
这与云沙箱主机不同——后者控制 runner 的执行位置。OS 沙箱则控制 Agent 能访问什么,无论其运行在哪里。
OS 沙箱适用于内置的 OS 工具(sys_os_read、sys_os_write、sys_os_edit、sys_os_shell)以及你在 Agent 配置中声明的任何终端。
要求:Linux 需安装 bubblewrap(apt install bubblewrap 或 dnf install bubblewrap)。macOS 自带 sandbox-exec。若请求沙箱但后端不可用,Omnigent 会报错而非无沙箱运行。Windows 的作业对象(job objects)仅用于 OS 工具辅助进程树清理,不限制文件系统或网络访问。要在 Windows 上实现完整沙箱,请在 WSL 下运行 Omnigent或使用云沙箱主机。
最小配置
最基础的实用 OS 沙箱。将工作目录设为可写,并让 Omnigent 为当前平台选择后端:
os_env: type: caller_process cwd: . sandbox: write_paths: [.] # cwd 默认只读,此处显式恢复写入 allow_network: true
在 Linux 上,Omnigent 使用 bubblewrap(bwrap);在 macOS 上使用 Seatbelt(sandbox-exec)。省略 type 或设为 type: auto 均会选择平台默认值,两者解析结果相同。
平台 | 后端 | 机制 ---|---|--- Linux | linux_bwrap | Bubblewrap 命名空间 + seccomp macOS | darwin_seatbelt | sandbox-exec SBPL 配置文件 Windows | windows_jobobject | 作业对象(进程清理) 其他 | none | 无沙箱(显式退出)
选择或禁用后端
通常无需设置 type——Omnigent 会自动选择平台默认值。若需刻意指定,有两个显式值可用:
type: auto 显式请求平台默认值,与省略 type 效果相同,因此同一份 YAML 可跨平台移植。 type: none 和 type: null 均显式禁用沙箱。将 sandbox: 块设为 false 效果等同。
若按名称请求特定后端(如 type: linux_bwrap),仍会路由到该后端;若平台无法提供,Omnigent 会大声报错——因为作者明确按名称请求了它。
可限制项
文件系统
默认情况下,在加固后端中 cwd 为只读,需显式开启写入。
sandbox: read_paths: [~/.gitconfig, ~/.ssh] # cwd 之外的只读访问 write_paths: [.] # 可写目录 write_files: [~/.ssh/known_hosts] # 单个可写文件 cwd_allow_hidden: [.venv, .git, .env] # 允许显示的点文件(其余被屏蔽) mask_paths: [config/production.key] # 按名称/深度隐藏特定路径
cwd 和 read_paths 下的点文件默认隐藏,除非列在 cwd_allow_hidden 中。这使得宽泛的读取授权更安全:授予 ~ 不会暴露 ~/.aws/credentials 或 ~/.ssh/id_rsa。在 macOS 上,~/Library 也默认被拒。
默认情况下,点文件屏蔽非递归——仅扫描 cwd 及每个 read_paths 根目录的顶层。顶层机密(.env、.git/、.aws/、.ssh/)仍被隐藏,但嵌套在一级以下的点文件(例如 services/api/.env)仍可见。这是可扩展的默认设置:递归遍历中大型目录树会访问海量条目,容易触发 cwd_hidden_scan_max_entries。
对于不可信源树,若深层嵌套的凭证文件泄露不可接受,请设置 cwd_hidden_scan_recursive: true 以遍历整棵树。此时 cwd_hidden_scan_max_entries 和 cwd_hidden_scan_overflow 限制全遍历的开销。
sandbox: cwd_hidden_scan_recursive: true # 任意深度的点文件均被屏蔽
若要隐藏基于名称的屏蔽器无法捕获的特定文件或目录——如 config/production.key 这类命名的机密,或在不启用全递归情况下隐藏某个深层嵌套的点文件——请将其列在 mask_paths 中。条目解析方式与 read_paths 相同(~ 会展开,相对路径基于 cwd,$VAR 不展开),无论名称或深度均被隐藏,叠加在点文件屏蔽之上。目录被屏蔽为空视图,文件被屏蔽为空文件。
sandbox: mask_paths: - config/production.key - ~/.config/private
一次性写时复制写入(Linux)
write_paths 条目也可设为带 copy_on_write: true 的对象。在 linux_bwrap 后端中,该目录被挂载为一次性 overlay:Agent 在原始路径下看到该目录,并可在此创建、编辑、重命名或删除文件,但宿主机上的原始文件永不改变。普通字符串条目等价于 {path: ..., copy_on_write: false}。
executor: harness: openai-agents
os_env: type: caller_process cwd: . sandbox: type: linux_bwrap write_paths: - ./artifacts # 持久:写入落地到宿主机 - path: ./dependencies copy_on_write: true # 一次性:写入保留在 overlay 中
terminals: bash: command: bash os_env: inherit
在启动会话前创建 artifacts 和 dependencies。sys_os_* 工具、shell 命令及继承的终端共享同一 overlay,包括跨轮次和终端重新打开的情况。对 artifacts 的写入正常持久化。
一次性视图属于会话的 OS 环境:
其更改在该环境关闭时丢弃,runner 重启后不恢复。独立会话获得独立视图。若需保留数据,请在会话结束前导出到持久写路径。 Overlay 数据存放在临时内存后备存储中,随文件向上复制而消耗内存/交换空间。 当其 overlay 激活期间,宿主机上的原始目录应保持未变更;OverlayFS 不快照并发的宿主机编辑。
写时复制当前受限,Omnigent 会拒绝违反以下规则的配置,而非回退到写入原始目录:
需 sandbox.type: linux_bwrap 且 executor.harness: openai-agents。其他 harness 被拒绝,因为其原生工具尚未共享会话的挂载命名空间。 每个写时复制路径必须指向已存在的目录。 拒绝嵌套的写时复制根目录、写时复制根目录内的持久 write_paths 及 write_files。支持持久父级配写时复制子级。 带写时复制路径时不支持 os_env.fork 和 sandbox 覆盖。 在写时复制会话中,文件上传、Agent bundle 下载(sys_agent_download)、本地 Agent 配置发现(sys_agent_list)、技能加载/读取,以及带 config_path 的 sys_session_create 返回显式的不支持操作错误。请使用 sys_os_* 工具和继承终端进行文件系统工作,并将结果导出到持久写路径。
宿主机要求
以下仅适用于带 copy_on_write: true 的路径;普通 read_paths 和持久 write_paths 保持原有要求。它们在运行沙箱的机器上检查,而非 UI 所在机器:
Bubblewrap 0.11+,提供 --overlay-src 和 --tmp-overlay。 支持 userxattr 的非特权 OverlayFS 挂载——上游 Linux 5.11+;部分发行版向后移植到较旧内核。 tmpfs 的 user.* 扩展属性(上游 Linux 6.6),用于 Bubblewrap 的临时 upper 层。因此上游基线为 6.6+,或发行版对上述两项功能的后移。旧版 tmpfs 可能允许挂载但后续目录操作失败。 内核设施:user/mount 命名空间(CONFIG_NAMESPACES、CONFIG_USER_NS)、OverlayFS(CONFIG_OVERLAY_FS,内置或模块形式)、带扩展属性的 tmpfs(CONFIG_TMPFS、CONFIG_TMPFS_XATTR)。 使用权限:足够的 user.max_user_namespaces 和 user.max_mnt_namespaces 配额;若该开关存在,则 kernel.unprivileged_userns_clone=1;以及允许创建命名空间和 OverlayFS 挂载的 AppArmor/SELinux/seccomp/容器策略。例如,Ubuntu 24.04 的 AppArmor 限制即使在新内核上也可能阻止非特权 user 命名空间。 Omnigent 不更改宿主机安全设置。
Omnigent 在初始化写时复制环境时尝试真实挂载并测试 tmpfs user 扩展属性——既不基于 uname 拒绝可用的发行版后移,也不仅因内核较新就接受宿主机。失败时,错误报告运行内核、这些先决条件及 Bubblewrap 原始消息;该环境在运行工具前即失败。缺失或不可启动的 bwrap 二进制文件及挂载启动超时也会产生写时复制特定错误。
要检查支持情况,请以与 runner 相同的用户并在相同的容器/VM 内运行以下命令,从包含现有 dependencies 文件夹的目录执行:
uname -r bwrap --version cow_probe_dir=$(mktemp -d) bwrap --unshare-user --ro-bind / / \ --overlay-src "$PWD/dependencies" --tmp-overlay "$PWD/dependencies" \ --tmpfs "$cow_probe_dir" \ -- python3 -c 'import os,sys,tempfile; f=tempfile.TemporaryFile(dir=sys.argv[1]); os.setxattr(f.fileno(), "user.cow_probe", b"1")' "$cow_probe_dir" cow_probe_status=$? rmdir "$cow_probe_dir" test "$cow_probe_status" -eq 0
探针应在不更改 dependencies 的情况下成功退出。未知 overlay 选项指示旧版 Bubblewrap 构建;命名空间或挂载权限错误指向宿主机策略;不支持的文件系统/选项指示缺少内核支持。参见 Bubblewrap 手册、内核 OverlayFS 文档及 Linux 6.6 tmpfs 扩展属性处理器。
网络
sandbox: allow_network: true # 基本开/关 egress_rules: # 可选 HTTP(S) 允许列表 - "GET api.github.com/repos/myorg/" # 仅 GET,单个 org - "* pypi.org/" # 任意方法 - "* *.github.com/" # 通配子域
设置 egress_rules 后,所有 HTTP(S) 流量通过默认拒绝的 MITM 代理。仅匹配规则请求被允许。需加固后端(linux_bwrap 或 darwin_seatbelt)。
每条规则格式为 "METHODS host/path-glob":逗号分隔的 HTTP 动词(或 * 表示任意)、主机名(或 *.domain 表示子域)及路径 glob,其中 匹配任意深度。
默认情况下,代理还阻止连接私有 IP(RFC1918、回环、云元数据如 169.254.169.254)。若 Agent 需访问内部服务,请设置 egress_allow_private_destinations: true。
环境变量
sandbox: env_passthrough: [GH_TOKEN, AWS_PROFILE] # 仅这些变量到达 Agent
Agent CLI 以默认拒绝的环境启动。自动继承仅两样:共享基座(HOME、PATH、代理/TLS 设置、locale、TMPDIR 及 Omnigent 会话标记)和运行 harness 自身的变量族。其余一切——包括属于其他提供商的宿主机机密——均被剥离,仅当在 env_passthrough 中命名时才到达 Agent。
以往隐式到达 CLI 的环境键现在必须显式声明。需了解两种情况:
通用 ACP Agent(type: acp)不继承任何供应商族,因为 Omnigent 无法得知任意 Agent 属于哪个供应商。通过 ACP 使用 Gemini 需 env_passthrough: ["GEMINI_API_KEY"]。 Goose 仅拥有 GOOSE_*。通过 Omnigent 提供商/网关路由配置的 Goose 不受影响,但针对环境提供商键(OPENAI_API_KEY、ANTROPIC_API_KEY 等)配置的 goose 需在此声明该名称。
若 Agent 在初始化握手期间因不明原因失败,请先检查此字段——ACP 执行器日志会提示此点。
凭证(无密钥代理)
credential_proxy 让沙箱内工具在真实密钥不进入沙箱的情况下向外部主机认证:强制 L7 出口代理在出站时附加凭证,将合成占位符替换为真实值。需 egress_rules 及加固的网络隔离后端(linux_bwrap 或 darwin_seatbelt)。
每个条目有 type。基于主机的类型——https_bearer、https_basic、git_https 及 gh_basic——将凭证绑定到 target/targets 主机,并从 source 解析密钥。
sandbox: egress_rules: - "* api.github.com/" credential_proxy: - type: https_bearer target: api.github.com source: { env: GH_TOKEN }
Databricks CLI
databricks_cli 类型代理 Databricks CLI。与基于主机的类型不同,它基于 profile:列出要代理的 profile(及可选默认值)。仅列出的 profile 被物化到沙箱——作为占位符 .databrickscfg,其 token 为合成 oa_cred_* 值——并由代理交换;其他 profile 对 Agent 不可见。Omnigent 将 DATABRICKS_CONFIG_FILE 指向占位符文件,并在提供 default 时设置 DATABRICKS_CONFIG_PROFILE。
os_env: type: caller_process cwd: . sandbox: type: linux_bwrap egress_rules: - "* pypi.org/" # 其他出口需求 - "* dbc-adb7b1a3-9097.cloud.databricks.com/" # 代理的工作区 credential_proxy: - type: databricks_cli profiles: [dbc-adb7b1a3-9097, oss] default: dbc-adb7b1a3-9097 # 可选;设置 DATABRICKS_CONFIG_PROFILE
在沙箱内,databricks --profile dbc-adb7b1a3-9097 current-user me 可正常工作;沙箱仅持有 oa_cred_* 占位符,永不持有实时 token。
与每种凭证代理类型一样,你必须自行在 egress_rules 中列出每个工作区主机——代理从不自行扩大出口。OAuth profile(auth_type = databricks-cli)在会话生命周期内刷新,长会话可度过约 1 小时 token 过期。databricks_cli 需 databricks 额外依赖(pip install omnigent[databricks])且仅在 linux_bwrap 上工作——Go CLI 在 macOS 上忽略 SSL_CERT_FILE,故 darwin_seatbelt 被拒绝。
共享策略
用 YAML 锚点声明一次沙箱并复用:
os_env: type: caller_process cwd: . sandbox: &shared write_paths: [.] read_paths: [~/.gitconfig, ~/.ssh] allow_network: true
terminals: zsh: command: zsh os_env: type: caller_process cwd: . sandbox: *shared # 与 sys_os_* 工具相同策略
或在终端或子 Agent 上使用 os_env: inherit 以继承父级完整环境(包括其沙箱)。
在多 harness 设置中,每个子 Agent 在 agents/ 子目录的 config.yaml 中定义自身沙箱。tools.agents 中的 Agent 条目仅为名称(字符串),非内联配置块。
# 父级 config.yaml tools: agents: - researcher - coder
# agents/researcher/config.yaml os_env: sandbox: write_paths: [./research] allow_network: true
# agents/coder/config.yaml os_env: sandbox: write_paths: [./src] allow_network: false
沙箱覆盖范围
OS 沙箱适用于 sys_os_* 工具调用及引用该策略的终端。不适用于:
MCP 服务器。Runner 在沙箱外生成 MCP 子进程。请在 MCP 服务器自身配置位置约束它。 Omnigent 监控进程。它运行模型循环并分发工具。仅其通过 OS 工具发出的命令在沙箱内运行。
若请求沙箱(显式或默认)但无法提供,Omnigent 报错而非静默无沙箱运行。唯一退出方式为 sandbox.type: none(等价于 sandbox.type: null 或 sandbox: false)。
字段参考
os_env 字段 | 类型 | 默认 | 说明 ---|---|---|--- type | string | caller_process | OS 环境后端 cwd | string | . | 工作目录 sandbox | block | 平台默认 | 沙箱策略(见下文) start_in_scratch | bool | false | 在可写 scratch tmpdir 中启动而非 cwd。工作区绑定为只读。需激活沙箱。
os_env.sandbox 字段 | 类型 | 默认 | 说明 ---|---|---|--- type | string | 平台默认 | auto(或省略)选择平台默认;linux_bwrap、darwin_seatbelt、windows_jobobject;none/null 禁用 write_paths | (string or object)[] | [] | 可写目录。cwd 默认只读。对象条目带 path 及 copy_on_write(bool,默认 false);见写时复制写入。 write_files | string[] | [] | 单个可写文件 read_paths | string[] | none | cwd 之外的只读授权 allow_network | bool | true | 网络访问开/关 cwd_allow_hidden | string[] | [".venv"] | 允许的点文件 basename cwd_hidden_scan_recursive | bool | false | 屏蔽点文件时递归子目录。false 仅扫描顶层。 mask_paths | string[] | none | 显式按任意路径/名称隐藏的文件/目录,叠加在点文件屏蔽之上 cwd_hidden_scan_max_entries | int | 50000 | 点文件屏蔽遍历最大条目(递归模式) cwd_hidden_scan_overflow | string | warn | error、warn 或 unlimited env_passthrough | string[] | 最小集 | Agent 可见的环境变量 egress_rules | string[] | none | HTTP(S) 允许列表。设置时默认拒绝。 egress_allow_private_destinations | bool | false | 允许连接私有/元数据 IP credential_proxy | block | [] | 无密钥认证条目;需 egress_rules