OpenSandbox 多沙箱 Egress 控制平面(OSEP-0022)深度解析:Subject 抽象、双控制通道与 Fail-Closed 生命周期
【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox
本文围绕 OpenSandbox 仓库中的设计文档 OSEP-0022 Multi-Sandbox Egress Control Plane 展开,系统讲解如何在"一个主机/网络域内共享 N 个沙箱"的场景下,用单个 egress 控制平面为每个沙箱提供相互隔离的出向策略、凭据与内核规则。读者将掌握 OSEP-0022 提出的 Subject 抽象、双控制通道(Sandbox Actions Handler 协议 + 代理路由)、deny-first 的 fail-closed 生命周期状态机,以及该设计在 egress 组件 中的源码级落地方式——这对部署 fast-sandbox Fastlet Pod 或 bwrap 隔离会话、并需要多沙箱统一出向管控的 AI Agent 运行时场景尤为关键。
背景与动机:为什么单沙箱 sidecar 模型不够了
当前 egress 的实现形态是单 sidecar 与单个沙箱共享同一 netns,依赖CAP_NET_ADMIN做隔离(对应 RFC #1582 的信任边界分析)。这种一对一模型在两种平台形态下会被打破:
- fast-sandbox Fastlet Pod:一个 Pod 承载 N 个沙箱,且沙箱 guest root 是特权用户。控制平面必须停留在主机域(Pod netns),而不能放进沙箱内——因为沙箱内运行的 AI Agent 是不可信的,让它拥有改写自身策略的能力等于没有策略。
- bwrap(setpriv)隔离会话:多个会话共享宿主机 netns,没有自己的 IP,无法用源 IP 做分发;宿主 uid 是唯一可用的身份键。
两种形态的共同诉求是:一个控制平面,多个相互独立的策略域。而 OSEP-0022 明确指出,egress 的核心引擎已经具备复用条件:pkg/nftables有可注入的 runner、pkg/dnsproxy有可配置的监听地址、pkg/credentialvault是纯内存实现——缺的只是一层策略路由层(policy-routing layer),这正是 OSEP-0022 要补齐的部分。从当前源码看,这层路由层已经在 egress 组件中落地:pkg/subject提供了 Subject 抽象与状态机,pkg/fleetnft提供了多沙箱 nftables 规则构建,pkg/actionhandler提供了 Fastlet 动作协议的服务端模型(详见下文)。
目标与非目标
目标
- Subject 抽象:以平台无关的身份作为策略、凭据和规则所有权的单位;分发键可插拔(源 IP / 宿主 uid / cgroup 路径)。
- 多沙箱分发:一个 egress 进程承载 N 个相互独立的 Subject。
- 单沙箱模式零影响:当
fleetprofile 关闭时,sidecar profile 的环境变量、API、行为完全不变。 - 消费而非修改(Consume, don't modify):fast-sandbox 的 CRD、RPC 协议和 fastlet 进程原样使用,集成走公开的Sandbox Actions Handler 协议;早期基于 slot-store 文件观测的方案被明确弃用。
- 不新增自己的公开契约:
specs/egress-api.yaml不变;策略由平台自己的actionBindings承载(不新增 egress 专属的载体);egress 侧不做本地持久化。 - 引擎复用:
pkg/dnsproxy、pkg/nftables、pkg/credentialvault、pkg/mitmproxy内部行为零改动。
非目标
不支持按进程粒度策略;不使用 eBPF;不在沙箱 guest 内运行控制平面;不做限流;不改 DNS 协议;不在集群上存储策略;凭据绝不进入 action binding(binding 的输入会持久化在 Sandbox CRD 中,不是机密传输通道)。
核心设计
Subject 抽象:一个沙箱一个不透明身份
Subject是每个沙箱的一个不透明标识符(如s-<sandboxUID>),拥有相互隔离的策略、凭据和内核规则切片。分发键(dispatch key)是平台提供的身份材料:fast-sandbox 使用沙箱源 IP(来自 action 的 attachment);bwrap 使用宿主 uid(cgroup 路径预留给未来)。
分发热路径是纯 map 查找(身份键 → Subject);注册表(registry)持有进程内状态机(absent → denying → active);规则构建器是冷路径,负责产出每个 Subject 的独立内核规则。
在源码中,这一抽象定义于 components/egress/pkg/subject/subject.go:Subject就是string类型,FromSandboxUID生成"s-" + sandboxUID;SubjectKey结构体承载四类分发键(NetNSPath/SourceIP/UID/Cgroup);Resolver接口定义了Resolve(key SubjectKey) (Subject, bool)这一热路径契约。单沙箱模式本质上是进程作为一个隐式 Subject(无操作层),fleetprofile 则是 N 个 Subject。
"谁是谁"的判定权永远不属于 egress——每个适配器必须证明自己的键不可伪造:fast-sandbox 依靠 IPAM + 无NET_ADMIN的每沙箱独立 netns;bwrap 依靠 execd 分配的 uid。
状态机:Fencing 与三态转换
Subject 的进程内状态机由 components/egress/pkg/subject/registry.go 的MemoryRegistry实现,状态枚举为StateAbsent/StateDenying/StateActive。
其中最关键的概念是Fencing(身份围栏):由revision.runtimeInstanceId+revision.attachmentId组成。任何一项变化都意味着沙箱被重新绑定(rebind),必须丢弃该 Subject 的全部历史状态——重置永远不能把旧策略带进新沙箱。注意specGeneration被刻意排除在 fence 之外:它每次 spec 更新都会递增(包括纯策略更新),而策略更新应当在原 Subject 上原地生效,绝不能触发 deny-first 重置。
并发契约是 fail-closed 的基石:RegisterAndEnforce在持有写锁的情况下执行 deny-first 安装,这与ApplyPolicy用来切换到 active 的锁是同一把——因此策略推送永远不会被重试的 deny-first 安装覆盖,且 deny-first 安装总是先于ApplyPolicy可见 Subject。对未知 Subject 的操作会返回ErrUnknownSubject,调用方据此把推送缓存为 pending(详见下文竞态处理)。
双控制通道:策略与凭据分离
fleetprofile没有任何沙箱可达的策略面(fast-sandbox guest root 不可信,绝不能允许它改写自己的策略)。全部策略/凭据状态经由两条互不相交的通道流转,两者都不涉及早期 slot-store 文件观测(/run/fast-sandbox/network/*.json不再被消费):
| 通道 | 方向 | 认证 | 承载内容 |
|---|---|---|---|
1. Sandbox Actions Handler 协议/_fastlet/v1/actions+/_fastlet/v1/actions/status | Fastlet → egress handler(Pod-loopback HTTP,actiontargetHTTPPort18080) | Pod netns loopback;信封携带沙箱 UID + revision 围栏;Fastlet 是唯一调用方 | Subject 生命周期(SET_BINDING/LIFECYCLE_HOOK/REMOVE_BINDING)与策略(binding 输入,经 Sandbox CRDactionBindings声明式下发) |
2. 代理路由/v1/sandboxfleets/{sandboxId}/egress/* | server/SDK → fastlet-proxy → egress 监听器(127.0.0.1:18080,Pod netns) | Ed25519 路由凭据(proxy 校验)+ proxy 注入的X-Fast-Sandbox-Uid头 | 凭据推送(/credential-vault,egress 侧纯内存)与既有运行时策略/凭据操作(沿用egress-api.yaml语义) |
监听器只绑定127.0.0.1:18080(Pod netns loopback)——沙箱 netns 无法触达,Fastlet 的 action 分发器与 fastlet-proxy 是仅有的两个对端;egress 对未知 UID 一律返回 404。凭据由 server 以完整 vault revision的形式经代理路由推送,与 OSEP-0012 Credential Vault and Credential Proxy 保持一致:不依赖 Kubernetes Secret,不依赖 kubelet 同步。没有 unix socket、没有 Secret volume、没有 egress 管理的状态文件。
源码中协议模型定义于 components/egress/pkg/actionhandler/actionhandler.go:APIVersion固定为sandbox.fast.io/actions/v1;操作码为SET_BINDING/LIFECYCLE_HOOK/REMOVE_BINDING;Hook 名只接受sandbox.runtime-ready与sandbox.data-plane-ready,未知 Hook拒绝而非静默忽略。Binding.Input特意使用json.RawMessage,以便区分三种状态:字段缺失(畸形)、JSON 字面量null(binding 从仍在运行的沙箱上被移除)与普通 JSON 字符串(不透明策略输入;空串和字面量字符串"null"都是普通值)。Validate()强制要求sandbox.uid、runtimeInstanceId、attachmentId必填,并且SET_BINDING必须携带 attachment 网络块——空 fence 会让所有 rebind 看起来相同,重置将永远无法被检测。
Action 信封字段消费清单
egress 只从 action 信封中读取以下字段(其余一律忽略),它们取代了早期基于文件设计中的 slot-record 字段:
| 信封字段 | 用途 |
|---|---|
sandbox.uid | Subject 身份(s-<uid>) |
revision.runtimeInstanceId、revision.attachmentId | 身份围栏(任一变化 = rebind,丢弃全部历史状态) |
revision.specGeneration | 待推送围栏(X-Fast-Sandbox-Generation比对) |
attachment.network.ip | 分发键(ip saddr) |
attachment.network.hostVeth | 预留(不再使用:在 bridge 拓扑下 IP hook 看到的是skb->dev = bridge,基于 pod 侧 veth 的 iifname 匹配永远不会命中) |
attachment.network.gateway | 网关 DNS REDIRECT 目标 / MITM DNAT 目标 |
attachment.network.privateCidr | 兄弟沙箱隔离规则 |
binding.input | 策略(不透明;由 egress 按自己的策略格式解析) |
hook.name/hook.sequence | 生命周期检查点投递顺序(sandbox.runtime-ready、sandbox.data-plane-ready) |
契约状态——已解决:早期悬而未决的问题(slot-store 的路径/JSON 形态/阶段语义属于 fastlet 内部实现细节)通过采纳 Sandbox Actions Handler 协议得到解决:binding 投递、Hook 投递、身份围栏与重放语义都是 fast-sandbox拥有并公开支持的契约,经由 Pod-loopback HTTP 而非共享文件存储交付,无需任何 fastlet 侧的稳定性改造。
生命周期与 Fail-Closed 保证
SET_BINDING arrives />不变量:deny-first 在SET_BINDING时安装,先于sandbox.runtime-readyHook——沙箱在其 runtime 尚不存在时就已经处于受控状态;Hook 可以迟到,绝不早开。
运行时更新
![]()
卸载是声明式的:沙箱删除 → Fastlet 发送REMOVE_BINDING→ egress 拆除该 Subject。代理路由上不存在生命周期动词。
系统边界
Profile 分离
两个 profile 是互斥的部署形态:
sidecar:沙箱网络域内的服务,拥有公开契约(18080、/policy、/credential-vault)——保持不变。fleet(OPENSANDBOX_EGRESS_PROFILE=fleet):主机域的控制平面组件——Subject 生命周期与策略来自 Fastlet 的 action 协议,凭据由 server 经代理路由推送。
profile 常量与启用环境变量定义于 components/egress/pkg/constants/configuration.go:ProfileSidecar/ProfileFleet,OPENSANDBOX_EGRESS_PROFILE;fleet 监听器默认地址为127.0.0.1:18080(DefaultFleetServerAddr),HTTP 地址可用OPENSANDBOX_EGRESS_HTTP_ADDR覆盖。
安全边界
边界 保证 无沙箱可达的策略面 监听器仅绑定 Pod netns loopback;沙箱 guest 无法触达;Fastlet action 分发器与 fastlet-proxy 是仅有的对端——UID 头信任依赖这种对端排他性 控制平面位于沙箱之外 egress 守护进程绝不运行在 guest 内(RFC #1582 信任边界分析);沙箱用户即使特权运行也无法触碰它 凭据仅驻留内存 完整 vault revision 经代理路由推送(OSEP-0012 模型),只保存在 egress 内存中,绝不落 egress 磁盘;无跨 Subject 凭据复用(破坏半径隔离)。action binding 输入永不携带凭据(持久化在 Sandbox CRD 中)。传输说明:代理路由是 Pod 网络 HTTP——与既有 route-credential 机制假设的信任域相同 每个转换都 fail-closed denying状态、原子策略切换、deny-first 注册、data-plane-ready是唯一激活信号管理面独立于 Subject 状态 Subject 处于denying(或active)期间,凭据推送与运行时策略/凭据操作完全可用:代理路由在主机域(Pod netns loopback)终结,从不穿越沙箱流量路径——只有应用流量被封锁(DNS NXDOMAIN + forward drop) egress 不可用时无创建窗口 OpenSandbox runtime 驱动在EnsureSandbox内、创建沙箱容器之前先探测 egress healthz(127.0.0.1:18080/healthz,同 Pod netns);未就绪的 egress 拒绝创建。正常路径本身也无窗口:deny-first 在SET_BINDING安装,先于sandbox.runtime-ready,且 deny-first 安装远快于容器启动;若要完全确定性的保证(与时机无关),还需驱动在容器创建前确认 Subject 已注册——这被记录为已知取舍 分发键不可伪造 IPAM + 无NET_ADMIN的每沙箱独立 netns(既有能力);新的 OpenSandbox 驱动额外丢弃NET_RAW;Pod netns rp_filter 严格模式拒绝伪造源 IP(bridge 拓扑下 iifname 绑定不可用——IP hook 看到skb->dev = bridge) 强制点位置 Pod netnshook forward(ACCEPT 策略 + 未标记即 drop 的尾部;放行流量在每 Subject 的hook prerouting链中用meta mark set 0x2打标——因为在bridge-nf-call-iptables=1的 Firecracker bridge 拓扑下,显式 forwardaccept无法通过:帧会回到 bridge L2 路径并在 postrouting 之前被丢弃),外加用于被拦截 MITM 流量的 Pod-netns INPUT 链;Kata 经 TAP 覆盖(同一 forward 面)。早期"每沙箱 netns OUTPUT 纵深防御层"被弃用(action 信封不携带 netns 路径;Pod-netns 各层对转发与拦截流量都是权威的)
pkg/fleetnft的规则注释(components/egress/pkg/fleetnft/fleetnft.go)对这套强制模型给出了精确的 nft 脚本蓝图:dispatch主链policy accept、ct state established,related accept回流放行、853端口(DoT 绕过)全局丢弃、按ip saddr <ip> jump subj_<id>逐 Subject 分发、末尾meta mark & 0x2 != 0x2 dropfail-closed 尾巴;markingprerouting 链只在 allow/dyn 集合命中时打0x2标记(与 DNS 代理的SO_MARK 0x1旁路标记刻意区分)。deny-first Subject 不装任何 mark 规则、且 Subject 链追加裸 drop;未知源与 deny-first Subject 都因未打标而被主链尾部丢弃。MITM 场景下,被 DNAT 的流量走input链并依据 conntrack ORIGINAL 目的地址执行同一套策略判定,直接连 MITM 端口(无 DNAT)则落入 drop——堵住透明拦截绕过。
平台适配器
关注点 fast-sandbox bwrap(setpriv) SubjectKey 源 IP(来自 action attachment) 宿主 uid 强制 hook Pod netnshook forward+ Pod-netns INPUT 链(MITM 流量) 宿主 netnshook output DNS 网关 REDIRECT → 共享代理:15353 每 Subject 端口 REDIRECT-m owner --uid-owner(端口 = Subject) MITM 共享 mitmdump,按客户端 IP 取 vault 每 Subject 端口 生命周期权威 Fastlet action 分发器(SET_BINDING/LIFECYCLE_HOOK/REMOVE_BINDING,sandbox.fast.io/actions/v1) execd 会话注册表,同一协议模式(TBD,另行详述) 凭据 代理路由 vault 端点(OSEP-0012 模型) 代理路由 vault 端点 端点 /_fastlet/v1/actions(Fastlet,Pod loopback)+ 经ResolveEndpoint的/v1/sandboxfleets/{sandboxId}/egress/*(代理路由,主机投递模式)TBD(execd 适配器另行详述)
扩展性约束
两个尺度彼此独立:
- 集群级无中心瓶颈:binding 由各 Fastlet点对点投递,凭据按 Fastlet Pod 点对点推送——无 watch 风暴、无 etcd 写放大、控制路径不依赖 API-server(Fastlet 读自己的 bindings,server 从不 watch)。
- 每 Pod 密度(目标 64 Subjects/Pod,≤100 策略更新/秒/Pod):nft 分发 O(1),配合按 Subject 的增量集合更新;连接刷新循环按 Subject 分桶;单个共享 mitmdump;DNS 代理是无状态 map 查找。server 编排必须幂等——失败的凭据推送让 Subject 停留在
denying(安全),server 在标记沙箱可用前重试。
对 fast-sandbox 的影响
对既有实现的要求(已核对源码验证)
OSEP-0022 对照 fast-sandbox 当前实现核验了以下前提(原文档引用internal/runtime/containerd/driver.go与 Sandbox Actions 协议文档):
要求 状态 备注 Sandbox Actions Handler 协议:GET /_fastlet/v1/actions/status+POST /_fastlet/v1/actions(SET_BINDING/LIFECYCLE_HOOK/REMOVE_BINDING)、有序投递、instanceId重放 ✅ 已具备 egress 原样消费;handler 绑定 Pool 声明的targetHTTPPort(18080) Pool/Sandbox spec 中的actionHandlers/actionBindings ✅ 已具备 egress 声明为 Handler;输入携带策略 slot 预置:沙箱创建前 netns/veth/MASQUERADE 就绪;网络 attachment(IP、网关、veth)随SET_BINDING在 runtime 创建前投递 ✅ 已具备 无创建窗口保证的基础 沙箱无NET_ADMIN(分发键不可伪造) ✅ 已具备 spec 不设置 capabilities;runc 默认排除NET_ADMIN 路由凭据签发/校验 + Pod netns 内的 fastlet-proxy ✅ 已具备 凭据通道原样复用 egress 容器经FastletTemplate挂载 ✅ 部署级 无需代码变更
内部新增(仅凭据通道)
生命周期/策略通道零fast-sandbox 改动(Actions 协议是公开的)。只有代理路由上的凭据通道需要以下内部新增,全部不涉及 API/CRD/协议变更:
- 基础设施目录中的主机投递模式(
InfraDeliveryMode,如host-process,与 bind-mount/image-layer/guest-copy 并列,internal/catalog/runtime/catalog.go):编译进 Pool revision,但从沙箱内sandbox-init的 supervisor 配置中排除;守护进程由FastletTemplate置备;就绪探针改为指向 Pod-netns 监听器而非沙箱 IP。 - fastlet-proxy 中的主机上游:当前 proxy 只向沙箱
Access地址转发(DirectIP/LocalForward);egress 路由必须改向 Pod-netns 监听器(127.0.0.1:18080)。 - UID 传播:proxy 只把出站路径重写为后缀,因此必须注入
X-Fast-Sandbox-Uid(在stripRouteHeaders之外)——这正是回答"凭据推送给哪个 Subject"的机制。 - 路由解析:
parseTarget目前只识别/v1/sandboxes/(端口)与/v2/sandboxes/(组件)前缀;需新增/v1/sandboxfleets/{sandboxId}/egress/*分支,解析沙箱路由、校验凭据并指向 egress——独立于组件Componentsmap。该分支中凭据的目标语义必须与ResolveEndpoint为 egress 目标签发的语义一致(组件目标egress,或专用 sandboxfleets 目标——两侧必须对齐)。
部署配置:egress 容器放在 PoolFastletTemplate中(Pod-netns 特权;不再需要 slot-store 或 netns-mount 卷)。
OpenSandbox runtime 驱动:集成以新的internal/runtime/contract.Driver实现落地(在 runtime 工厂中与 containerd/boxlite 并列注册)。其容器 spec 丢弃NET_RAW(runc 默认会授予它 → UDP 源地址伪造会削弱源 IP 分发键;Pod netns rp_filter 严格模式是防御伪造源 IP 的剩余手段)。egress healthz 探针放在其EnsureSandbox内(容器创建之前):egress 未就绪 → 以 runtime 不可用错误拒绝。既有驱动不受影响;没有 egress 组件的既有 Fastlet Pod 行为与今天完全一致。
明确不动的部分
fast-sandbox 的 CRDs、RPC 协议、SandboxSpec、fastlet 的 phases/admission/deletion 路径、数据面 reconcile 循环、路由凭据签发/校验、sandbox-initsupervisor、既有 containerd/boxlite runtime 驱动。Sandbox Actions 协议原样消费(无 fast-sandbox 代码变更;早期 slot-store 文件格式保持为 fastlet 内部细节,egress 不再读取)。specs/egress-api.yaml与各 SDK 不变。server 的 K8s 模式 egress sidecar 辅助脚本(egress_helper.py)不动。
OpenSandbox Server
- Fleets 映射移除 phase-1a 对
networkPolicy/credentialProxy的拒绝(server 的 fleets 创建映射逻辑):networkPolicy映射进 Create 请求的action_bindings(egress handler 输入);返回的沙箱声明式携带策略。凭据 revision 仍经代理路由以幂等重试推送。 - 策略更新走
UpdateSandbox(完整有序的 binding 替换)——无单独推送;Fastlet 投递新的SET_BINDING。 - 凭据通道端点复用:
fastpath_client.resolve_endpoint(...)指向 egress 目标;返回的代理路由使用/v1/sandboxfleets/{sandboxId}/egress/*前缀。路由凭据签发与 proxy 校验不变。 - egress 就绪状态经平台的
InfraComponentStatus通道上报(可选、非阻塞)。
测试计划
- 单元:Subject 注册表转换与 fail-closed 不变量;action 信封解析/校验(未知 apiVersion/操作/Hook 拒绝、null 输入与普通字符串输入区分);规则构建器确定性;分发(DNS 每 Subject、nft 集合、mitm vault 选择)。
- fast-sandbox e2e(Kind):单 Fastlet Pod 上 N 个沙箱配不同策略;每 Subject 在 DNS/nft 层的 allow/deny;兄弟沙箱隔离;fail-closed 的 create-then-configure 窗口(
SET_BINDING起 deny-first,data-plane-ready后策略才生效);凭据 vault 推送绑定正确的 Subject 且更新时 rebind;egress 重启恢复(新instanceId→ Fastlet 重放SET_BINDING+ 已到达 Hook →denying→ active,无陈旧规则);SET_BINDING(null)移除策略;陈旧REMOVE_BINDING(fence 不匹配)被忽略;沙箱无法触达任何策略变更面;UID 头伪造被拒绝。 - bwrap:按 uid 分发且宿主 uid 白名单完好。Kata:策略经 Pod netns forward hook 生效。
- 兼容性:
sidecarprofile 下完整 egress 套件;test_egress_helper.py不变。 - 手动:转换中途 kill;重启风暴;失败推送使 Subject 停留在
denying,重试成功。
源码中已落地与测试计划对应的部分:pkg/actionhandler的校验测试覆盖信封解析/失败路径;pkg/subject的 registry 测试覆盖状态转换与 fence 语义;pkg/fleetnft的测试覆盖脚本生成与刷新逻辑(见 components/egress/pkg/subject/registry_test.go、components/egress/pkg/actionhandler/actionhandler_test.go、components/egress/pkg/fleetnft/fleetnft_test.go)。egress 组件还提供了面向整机的验证脚本,如 smoke-fleet.sh、e2e-fleet-firecracker.sh,以及 fleet_upstream.py 等辅助,可作为端到端验证的起点。
权衡与备选方案
权衡:Pod 域守护进程比每沙箱进程拥有更大的信任域(以每 Subject 隔离 + deny-first 缓解);可用沙箱依赖 binding + Hook 流程完成(Handler 卡住会让沙箱保持非 Ready——fail-closed 且可观测);凭据通道仍依赖代理路由,所以凭据不能搭载在 action binding 上(binding 输入持久化在 Sandbox CRD 中,不是机密传输通道)。
考虑过的备选方案:slot-store 文件观测(否决——store 是 fastlet 内部实现细节,无稳定性契约;被公开的 Sandbox Actions 协议取代);每 Subject 宿主侧进程(保留为部署变体);沙箱 guest netns 内的每沙箱 sidecar(否决——控制平面位于它自己控制的信任边界之内,不构成安全控制);eBPF/cgroup 分发(推迟);egress 专属的策略载体 CRD/ConfigMap(否决——语义不匹配、etcd 写放大、watch 风暴、凭据暴露风险,且把通用组件与集群 API 耦合;平台自己的actionBindings声明式承载策略而无这些代价);凭据经宿主域 unix socket 或 Kubernetes Secret volume 交付(被经代理路由的直接 vault-API 推送取代,与 OSEP-0012 一致)。
基础设施与迁移
- fast-sandbox:无新仓库、无 API 变更——即上面四项内部新增(仅凭据通道)加部署配置。跨仓库依赖:以 Go module 方式导入
egress/pkg/...(replace 指令),或将pkg/subject与各引擎抽取为共享 module。 sidecar是默认 profile,既有部署零配置升级。fleetprofile 为可选启用(OPENSANDBOX_EGRESS_PROFILE=fleet);未带 egress 组件的 Fastlet Pod 在 operator 启用前行为与今天完全一致。- 推出顺序:egress
fleetprofile 先置于 feature gate 之后(actions 协议无需 fast-sandbox 代码)→ fast-sandbox 凭据通道的代理路由新增(惰性)→ server fleets 映射与编排。
环境变量速查
fleet profile 相关的关键环境变量定义于 components/egress/pkg/constants/configuration.go:
环境变量 说明 默认 OPENSANDBOX_EGRESS_PROFILEsidecar(默认)或fleetsidecarOPENSANDBOX_EGRESS_HTTP_ADDRfleet 策略服务器监听地址 127.0.0.1:18080OPENSANDBOX_EGRESS_PENDING_PUSH_TTL未知 UID 的凭据推送缓存 TTL(秒) 30OPENSANDBOX_EGRESS_BLOCK_DOH_443丢弃 TCP 443(无 blocklist 时为严格全丢弃) 关闭 OPENSANDBOX_EGRESS_DOH_BLOCKLIST逗号分隔的 DoH 端点 IP/CIDR 列表 空 OPENSANDBOX_EGRESS_MITMPROXY_TRANSPARENT启用透明 MITM(fleet 中启用共享 mitmdump 与 INPUT 强制链) 关闭 OPENSANDBOX_EGRESS_MITMPROXY_PORT共享 mitmproxy 端口 18081
从源码实现看,fleet 的 DoH 选项(fleetDoHOptions)与 sidecar profile 语义一致,MITM 关闭时还会清除上一代可能遗留的拦截表,避免 DNAT 黑洞。
结语
OSEP-0022 用"一个控制平面、N 个独立策略域"重新组织了多沙箱场景下的出向管控:Subject 抽象把策略/凭据/规则的所有权锚定到不透明的沙箱身份,双控制通道把声明式策略(Sandbox Actions 协议)与内存凭据(代理路由)彻底分离,而 deny-first 生命周期保证策略投递可以迟到、绝不早开。该设计在 egress 组件中已形成可运行的骨架(pkg/subject、pkg/actionhandler、pkg/fleetnft与 fleet.go 的组装),并为 bwrap/execd 适配器预留了同一协议模式的扩展点。结合 specs/egress-api.yaml 的既有 API 语义与 OSEP-0012 的凭据模型,它构成了一条从"单沙箱 sidecar"平滑演进到"多沙箱主机域控制平面"的路径。
【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.
项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考