尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

IronClaw 沙箱出口(Sandbox Egress)拓扑 Spike 全记录:双宿主机代理、默认拒绝策略与逐运行时 TLS 信任验证

发布时间:2026/9/25 3:50:10

资讯中心
01
ARTICLE

IronClaw 沙箱出口(Sandbox Egress)拓扑 Spike 全记录:双宿主机代理、默认拒绝策略与逐运行时 TLS 信任验证

IronClaw 沙箱出口(Sandbox Egress)拓扑 Spike 全记录:双宿主机代理、默认拒绝策略与逐运行时 TLS 信任验证
人工智能AI 应用交互助手AI Agent【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址https://gitcode.com/gh_mirrors/iro/ironclaw点击查看免费下载本文基于 IronClaw 仓库中 2026-08-19 sandbox egress spike 调研文档 及同目录下的全部结果文件整理而成并结合ironclaw_sandbox领域源码对设计落地做了对照印证。读者将掌握如何用--internal网络 双宿主机iron-proxy侧车为每个线程容器构建“唯一出口”如何验证 DNS 拦截、MITM 允许列表、默认拒绝与凭证脱敏以及 curl/git/Node/Python/pip 各运行时信任自签 CA 的差异与docker exec进程管理的坑。IronClaw 的沙箱化执行以“每线程一个命令容器”为核心拓扑。为了让这些容器既不能直连公网、又不能访问云元数据地址同时仍能按策略访问允许列表内的站点IronClaw 在 2026-08-19 进行了一次代号#7732的 Throwaway spike一次性验证实验使用纯 Docker 原生命令与库存镜像无任何 Rust 改动验证“internal 网络 双宿主机代理侧车”的出口拓扑是否成立。该 spike 共验证 9 个关键假设全部获得证据支撑并产出了 8 条对后续 Step 1 实现具有直接指导意义的工程结论。一、Spike 目标与总体判定本次 spike 的拓扑设想是命令容器挂在一个--internalDocker 网络上该网络没有外部路由唯一的出口是一个同时挂载 internal 与 egress 两个网络的iron-proxy侧车容器。客户端的所有 DNS 查询与 HTTP/HTTPS 流量都必须经过该代理由代理基于允许列表决定放行或拒绝。Spike 环境为macOS OrbStackDocker server 29.4.0代理镜像固定为ironsh/iron-proxysha256:c4628019c24f4cc8d77564a26b7c9cedb00accee6f93d06270e85fb8f9c6a7da9 项验证的最终判定如下完整证据见 results-topology-dns.md、results-policy-credentials.md、results-tls-trust.md、results-exec-mechanics.md#验证项判定证据文件1internal 网络 双宿主机代理拓扑PASSresults-topology-dns.md2--dns proxy经 Docker 内嵌 DNS 生效PASSresults-topology-dns.md3经 MITMspike CA的允许列表 TLS 出口PASSresults-policy-credentials.md4默认拒绝 403 结构化 JSON 审计PASSresults-policy-credentials.md audit-denial-example.jsonl5直连出口死亡公网、元数据 IP、无默认路由PASSresults-topology-dns.md6占位符→真实凭证替换、require: true、主机绑定、日志无真实字面量PASS4/4 子检查results-policy-credentials.md7逐运行时 TLS 信任矩阵curl/git/node/python/pipPASSresults-tls-trust.md8docker exec流/杀进程/僵尸/延迟机制PASS with findingsresults-exec-mechanics.md9internal 网络无 IPv6 路由PASSresults-topology-dns.md此外spike 明确记录了参与镜像的不可变身份并诚实标注了证据边界alpine:3.20与alpine/openssl:latest两个历史 tag 没有记录运行时摘要RepoDigest因此这两个输入的精确复现是证据缺口后续 spike 必须在执行前记录RepoDigests。文中的real-secret-value-42是确定性本地替换 canary哨兵值并非真实运营凭证。二、标准复现配方与 CA 生成Spike 文档给出了可复用的标准配方。要点是并发实例必须使用唯一子网用 N 区分以免网络冲突。docker network create --internal --subnet 172.28.N.0/24 pfx-int docker network create --subnet 172.29.N.0/24 pfx-egress docker run -d --name pfx-proxy --network pfx-int --ip 172.28.N.2 \ -v $DIR/proxy.yaml:/etc/iron-proxy/proxy.yaml:ro \ -v $DIR/ca.crt:/etc/iron-proxy/ca.crt:ro -v $DIR/ca.key:/etc/iron-proxy/ca.key:ro \ ironsh/iron-proxysha256:c4628019c24f4cc8d77564a26b7c9cedb00accee6f93d06270e85fb8f9c6a7da \ -config /etc/iron-proxy/proxy.yaml docker network connect pfx-egress pfx-proxy docker run -d --name pfx-client --network pfx-int --dns 172.28.N.2 alpine:3.20 sleep 900其中pfx-intinternal与pfx-egress两个网络分别承担“命令容器面”与“公网出口面”代理固定 IP 如172.28.N.2同时作为客户端 DNS 指向。CA 材料每次运行临时生成、刻意不提交仓库。CA 生成有一个重要经验macOS 宿主上的 LibreSSL 行为异常必须改用容器内的 OpenSSL 实现docker run --rm -v $DIR:/work -w /work alpine/openssl genrsa -out ca.key 4096 docker run --rm -v $DIR:/work -w /work alpine/openssl req -x509 -new -nodes \ -key ca.key -sha256 -days 3650 -subj /CNiron-proxy-spike-CA \ -addext basicConstraintscritical,CA:TRUE -addext keyUsagecritical,keyCertSign \ -out ca.crt生成的 CA 经容器化openssl x509校验subjectCNiron-proxy-spike-CA、issuerCNiron-proxy-spike-CA、4096 位 RSA、criticalCA:TRUE、criticalCertificate SignKeyUsage。代理启动日志确认了三个监听面与变换管线running 0 {level:INFO,msg:upstream deny list active,cidrs:[169.254.169.254/32,fd00:ec2::254/128,127.0.0.0/8,::1/128]} {level:INFO,msg:iron-proxy starting,dns_listen::53,http_listen::80,https_listen::443,metrics_listen::9090} {level:INFO,msg:transform pipeline,transforms:allowlist}值得注意upstream deny list默认就把云元数据地址169.254.169.254/32、IPv6 链路本地元数据fd00:ec2::254/128、回环地址等纳入拒绝 CIDR这与项目“防止沙箱窃取云实例凭证”的定位一致。三、拓扑与 DNS 验证唯一出口确实成立3.1 双宿主机拓扑Item 1docker inspect证实代理同时挂载两个网络而命令面网络是 internal{s7a-egress:{Gateway:172.29.10.1,IPAddress:172.29.10.2,...},s7a-int:{Gateway:,IPAddress:172.28.10.2,...}} trueInternaltrue且 internal 网络无网关说明该网络上没有任何外部路由。3.2--dns proxy经内嵌 DNS 生效Item 2客户端/etc/resolv.conf显示nameserver 127.0.0.11Docker 内嵌 DNS但其注释明确记录了转发目标ExtServers: [172.28.10.2]。实测中包括故意不存在的anything.invalid在内所有名字都解析到代理 IPServer: 127.0.0.11 Address: 127.0.0.11:53 Name: example.com Address: 172.28.10.2 Name: anything.invalid Address: 172.28.10.2这意味着即使客户端尝试访问未允许域名DNS 也会把它送到代理由代理在 7 层决定放行或拒绝——拓扑“按设计工作”。3.3 直连出口死亡Item 5internal 网络上的客户端ip route只有一行172.28.10.0/24 dev eth0 scope link src 172.28.10.3没有默认路由。显式直连尝试全部失败Network unreachableEXIT1包括http://1.1.1.1、TCP 443 到1.1.1.1、以及云元数据地址169.254.169.254:80。作为阳性对照走代理访问http://example.com返回 200证明失败并非拓扑整体故障而是直连路径确实被切断。3.4 无 IPv6 路由Item 9客户端仅有 IPv6 回环地址ip -6 route无任何输出连接 Cloudflare IPv6 DNS2606:4700:4700::1111失败。Docker 29.4.0 的docker infoGo 模板不暴露.IPv6字段模板求值直接报错因此正确做法是逐网络检查EnableIPv6——本 spike 的两个网络均为false。四、策略与审计允许列表、默认拒绝与凭证脱敏4.1 MITM 允许列表出口Item 3客户端使用--cacert /ca.crt访问https://example.com得到 200-v详细输出证实完整链路* Host example.com:443 was resolved. * IPv4: 172.28.20.2 * Server certificate: * subject: CNexample.com * issuer: CNiron-proxy-spike-CA * subjectAltName: example.com matches certs example.com * OpenSSL verify result: 0 HTTP/1.1 200 OK即DNS 把客户端送到代理 → 代理为example.com动态签发由 spike CA 签发的叶子证书 → 客户端信任该 CA 完成验证 → 代理放行上游请求。代理审计日志同时记录mode: mitm, action: allow, status_code: 200。4.2 默认拒绝与结构化审计Item 4访问未允许域名https://denied.invalid/返回403且 verbose 输出证明这是代理拒绝而非 DNS 失败连接成功建立到代理 IP。代理随后输出结构化 JSON 审计记录完整样例见 audit-denial-example.jsonl{time:2026-08-19T11:26:00.564519806Z,level:WARN,msg:request,audit:{host:denied.invalid,method:GET,path:/,remote_addr:172.28.20.4:34558,sni:denied.invalid,mode:mitm,action:reject,status_code:403,duration_ms:0.005},rejected_by:allowlist,request_transforms:[{name:allowlist,action:reject,duration_ms:0.001}]}审计记录包含rejected_by字段与逐变换的request_transforms轨迹这为后续 Step 1 的审计可观测性trace 溯源提供了直接模板。4.3 占位符→真实凭证替换Item 64/4 子检查通过这是本 spike 最具“产品价值”的验证代理在出站请求中把占位符 token 替换为真实凭证同时保证真实凭证永不落日志。工作配置见 proxy.credentials.yaml核心是secrets变换transforms: - name: allowlist config: domains: [example.com, capture.test, other.test] - name: secrets config: secrets: - source: { type: env, var: REAL_TOKEN } proxy_value: icsbx_spike_placeholder_123 match_headers: [Authorization] require: true rules: [{ host: capture.test }]四个子检查全部通过6a 占位符仅对绑定主机替换向capture.test发送Authorization: Bearer icsbx_spike_placeholder_123echo 服务收到的授权头已变为Bearer real-secret-value-426brequire: true拒绝替代 token向绑定主机发送some-other-token得到 403审计记录rejected_by: secrets并带 secrets 变换拒绝注解6c 同一占位符在未绑定主机原样保留向other.test发送相同占位符echo 显示授权头仍是icsbx_spike_placeholder_123未被替换6d 真实凭证零次出现在代理日志对完整代理日志做字面量、区分大小写的搜索real-secret-value-42命中次数为 0成功替换的审计只记录变量名与位置{name:secrets,action:allow,annotations:{swapped:[{secret:REAL_TOKEN,locations:[header:Authorization]}]}}spike 也诚实标注了边界只测试了字面量精确匹配未测试编码、转义或变换后的表示。4.4 测试专用覆盖项的警示proxy.credentials.yaml中的upstream_deny_cidrs: []是仅限测试的覆盖项它允许代理访问私有 echo 容器地址capture.test/other.test生产环境必须保留默认拒绝 CIDR。这一警示与 3.2 节中代理启动日志默认激活的 deny list 相互印证。五、逐运行时 TLS 信任矩阵Item 7允许列表 MITM 的前提是各运行时信任 spike CA。spike 使用nikolaik/python-nodejs:python3.12-nodejs22摘要sha256:88c41488c1…内含 curl 8.14.1 / git 2.47.3 / Node v22.23.2 / Python 3.12.13 / pip 26.1.2实测得出关键矩阵运行时系统证书库即可需要额外环境变量说明curl是否安装前也可用--cacert /spike/ca.crtgit HTTPS是否浅克隆只实际访问了github.comNodefetch否是必须NODE_EXTRA_CA_CERTS/spike/ca.crtPythonurllib.request是否3.12.13 使用 Debian 系统库pip 26.1.2是意外否CA 入系统库后无环境变量即可SSL_CERT_FILE/spike/ca.crt为可用备选几个关键实验细节未信任前 curl 返回(60) SSL certificate problem: self-signed certificate in certificate chainEXIT60--cacert显式指定后 200cp /spike/ca.crt /usr/local/share/ca-certificates/spike.crt update-ca-certificates后 curl、git、Python 均通过系统库信任git 浅克隆github.com/octocat/Hello-World成功代理日志仅记录 3 个对github.com的 smart-HTTP 请求info/refs 2 个git-upload-pack更深的克隆 / LFS 需要完整资产主机星座codeload、objects.githubusercontent 等它们在允许列表里但本 fixture 未用到Node v22 忽略系统证书库即使update-ca-certificates成功fetch(https://example.com)仍报SELF_SIGNED_CERT_IN_CHAIN设置NODE_EXTRA_CA_CERTS/spike/ca.crt后返回 200pip 26.1.2 是“意外惊喜”CA 进入系统库后无需任何环境变量即可pip download six控制实验移除系统库中的 spike CA证明失败确实来自系统信任缺失而仅用SSL_CERT_FILE也能成功。由此得出 Step 1 的两条明确工程指令不要全局设置SSL_CERT_FILE指向仅含代理 CA 的 bundle——它会影响所有运行时且覆盖面不对称应采用合并 CA bundle或将覆盖范围限定到确实需要的运行时Nodeworker 镜像必须校验NODE_EXTRA_CA_CERTS指向的路径真实存在。六、docker exec进程与流机制Item 8该任务回答“每线程容器 每次命令一次 exec”经济模型下的关键问题。测试容器为alpine:3.20PID 1 是刻意选择的不回收non-reaping命令sleep 1800。6.1 后台子进程继承 stdout 的“挂起”假设未复现原假设是“后台子进程继承 stdout 会导致 exec 无限挂起”。在 Docker 29.4 上未复现sh -c sleep 300 echo done返回done且约2.08 秒完成而非 20 秒超时。结论该版本下继承流只带来约 2 秒代价不产生挂起。6.2 重定向足以立即关闭流setsid 用于杀进程树仅重定向setsid之前先测sleep 300 /dev/null 21 /dev/null echo done→ 0.067 秒完成重定向 setsid0.127 秒完成因此ironclaw-exec需要两者兼得重定向负责流即时关闭延迟setsid负责形成独立进程组以便组杀。6.3 组杀与僵尸退出码传播精确exit 7→code7BusyBox 语法坑kill -TERM -- -34被 Alpine BusyBoxsh内建拒绝sh: invalid number --kill_code1正确写法是kill -TERM -34kill_code0组杀信号确实送达PGID 34 的 shell 与两个 sleep 全部从Ssleeping变为Zzombie而无关的分离进程PGID 17不受影响严格判定下该子检查 FAIL由于 PID 1 不回收被杀进程全部残留为僵尸无法满足“进程条目消失”的严格条件。5 秒后僵尸仍存在僵尸累积被直接演示。worker 镜像必须引入 tini 或等效的 reaping init否则每次组杀都会堆积僵尸。6.4 exec 延迟基准5 次docker exec ... true实测60 / 40 / 30 / 30 / 30 ms均值 38 ms、中位数 30 ms。这为“每线程容器 每命令一次 exec”的开销提供了量化依据。七、与 IronClaw 源码的落地印证该 spike 的结论已经在ironclaw_sandbox领域代码中落地可从源码佐证其工程化方向managed_egress.rs 中以常量钉死代理镜像摘要ironsh/iron-proxysha256:c462…与 spike 完全一致并强制要求镜像必须按 sha256 摘要 pin、pull 后必须校验不可变镜像 ID对应 spike 的“记录 RepoDigests”要求代理配置与材料统一挂载到宿主机侧/run/ironclaw-proxy/目录proxy.yaml、ca.crt、ca.key、credentials.json、invocation-id并定义PROXY_LABEL_PREFIX ironclaw.proxy标签前缀用于识别侧车容器代码中暴露给用户的 CA 路径为/run/ironclaw/egress-ca.crtUSER_PROXY_CA_PATH与 spike 中“把 spike CA 挂进客户端供各运行时信任”的做法一脉相承策略侧network_allowlist.rs与managed_egress.rs共同保证“托管出口策略必须至少包含一个允许目标、必须拒绝私网 IP 段”对应 spike 中默认 deny list 与upstream_deny_cidrs测试覆盖项的生产警示。八、Step 1 落地清单Spike 结论汇总综合全部结果Step 1 实现应满足以下要求每线程命令容器挂在--internal网络无默认路由唯一的出口是双宿主机iron-proxy侧车客户端--dns proxy-ip指向代理借助 Docker 内嵌 DNS 将所有名字含.invalid统一送到代理代理默认拒绝非允许列表域名403并输出含rejected_by与变换轨迹的结构化 JSON 审计凭证注入采用“占位符 → 真实值”的主机绑定替换require: true防替代 token真实值永不落日志worker 镜像信任代理 CA系统证书库覆盖 curl/git/python/pipNode 必须显式NODE_EXTRA_CA_CERTS禁止全局SSL_CERT_FILE指向仅代理 CA 的 bundleironclaw-exec同时使用全重定向流即时关闭与setsid进程组隔离组杀采用 BusyBox 兼容写法kill -TERM -PGID镜像引入 tini 级 reaping init 防止僵尸累积网络层同时关闭 IPv6 路由避免 internal 网络出现第二条出口复现实验必须记录全部输入镜像的不可变摘要RepoDigests并保留所有审计与日志证据。九、结论这是一次证据链完整、边界标注诚实的工程 spike9/9 假设通过其中“组杀后进程消失”在非 reaping PID 1 下按严格标准判为 FAIL属于“信号生效但僵尸残留”的机制性发现为 IronClaw 的“每线程容器唯一受控出口”架构扫清了从设计到落地的关键风险。文档中所有命令块保持“当时实际执行”的原貌未用事后拉取的摘要改写历史证据这种可审计性本身就是值得复用的实验方法论。若需复现或深化完整配方、配置样例与证据文件均可从 spike 目录 直接获取。赞分享人工智能AI 应用交互助手AI Agent【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址https://gitcode.com/gh_mirrors/iro/ironclaw点击查看免费下载相关推荐IronClaw Sandbox 出口网络拓扑验证基于 Docker internal 网络与双网卡 iron-proxy 的 DNS/egress spike 剖析IronClaw Sandbox 出口网络拓扑验证基于 Docker internal 网络与双网卡 iron proxy 的 DNS/egress spik人工智能AI 应用交互助手AI AgentIronClaw 沙箱出口策略验证基于 iron-proxy 的默认拒绝、TLS 拦截与凭据占位符交换实战IronClaw 沙箱出口策略验证基于 iron proxy 的默认拒绝、TLS 拦截与凭据占位符交换实战 本篇技术指南围绕 IronClaw 开源仓库中的沙人工智能AI 应用交互助手AI AgentIronClaw 沙箱出口 Spike 实录通过 iron-proxy 实现 per-runtime TLS 信任矩阵curl / git / Node / Python / pipIronClaw 沙箱出口 Spike 实录通过 iron proxy 实现 per runtime TLS 信任矩阵curl / git / Node /人工智能AI 应用交互助手AI Agent上一篇Trigger.dev Webhook Provider 调研实战签名方案分类、预设复用与 Webhook 目录工程化下一篇终极指南screenFetch系统信息工具安全风险评估与防护创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。