Docker Sandboxes 的凭证:host 代理转发,不进 microVM

Docker Sandboxes 的凭证:host 代理转发,不进 microVM

Docker Sandboxes 实测系列(共 5 篇)

  1. Docker Sandboxes 上手:从安装到第一次跑 Agent
  2. Docker Sandboxes 工作区怎么接:Direct、Clone 和它们的边界
  3. Docker Sandboxes 的隔离例外:共享 Skills 与宿主机 MCP
  4. Docker Sandboxes 的凭证:host 代理转发,不进 microVM(本篇
  5. Docker Sandboxes 的网络策略:balanced 挡住了什么,怎么放行一条例外

TL;DR

sbx secret 存的 API Key 从不进 microVM。Agent 环境变量里看到的是固定占位符 proxy-managed,真实请求由宿主机侧代理转发签名,GitHub token 也是同样套路的假字符串。手动写进 /etc/sandbox-persistent.sh 的值是例外——那是真值,直接躺在 VM 里,不走代理。

SSH 走另一条路:SSH_AUTH_SOCK 被转发进 sandbox,ssh-add -l 能列出宿主机上真实的私钥指纹和路径,Agent 能拿它签名——但 ~/.ssh 目录本身读不到,私钥文件从没进过 microVM。能用,摸不到。

上一篇留的口子

上一篇 讲完共享 Skills 和宿主机 MCP,留了一句没展开:SSH_AUTH_SOCK 会转发进 sandbox。这是官方五层隔离里最后一层——凭证隔离——具体怎么做的,这篇补上,顺带把 API Key 那条也讲清楚。

API Key:Agent 看到的是假的

起一个干净的 sandbox,看它环境变量里的凭证长什么样:

$ sbx exec my-sandbox bash -c 'env | grep -E "API_KEY|GH_TOKEN"'
ANTHROPIC_API_KEY=proxy-managed
OPENAI_API_KEY=proxy-managed
GOOGLE_API_KEY=proxy-managed
XAI_API_KEY=proxy-managed
GH_TOKEN=redacted:gho_...

proxy-managed 是固定哨兵值,不是真 Key 的一部分。真实凭证留在宿主机上,Agent 发起的模型请求经过一个宿主机侧代理,代理拿真 Key 签好再转发出去——Agent 进程本身,包括它能读到的环境变量,从头到尾看不到明文。GH_TOKEN 也是同一套:redacted:gho_... 这种占位符,不是真的 GitHub token。

SBX_CRED_<PROVIDER>_MODE 这组变量能看出每个 provider 当前走的是哪种注入方式(我这台机器上配过的几个都是 apikey);没存过 Key 的 provider 会显示别的值,代表这条凭证根本没注入。

手动塞进去的值是真的,不是代理

这条例外容易被忽略:sbx secret 管的是官方支持的那几个 provider,如果 Agent 需要一个不在名单里的环境变量(比如自定义的内部 token),官方给的路径是写进 /etc/sandbox-persistent.sh

sbx exec my-sandbox bash -c "echo 'export MY_TOKEN=real-secret-value' >> /etc/sandbox-persistent.sh"

这条路径不经过代理,real-secret-value 是明文,直接躺在 VM 文件系统里。我测了一下它到底在什么条件下能读到:

$ sbx exec my-sandbox env | grep MY_TOKEN
# 什么都没有

$ sbx exec my-sandbox bash -c 'echo $MY_TOKEN'
real-secret-value

sbx exec <name> <command> 不经过 shell,sandbox-persistent.sh 不会被 source,环境变量读不到;包一层 bash -c 才会读到。这条不是 bug,是 sbx exec 本来就不保证起一个登录 shell。用 sbx secret 的凭证全程不进 VM;写进 sandbox-persistent.sh 的值一旦落地就是明文,Agent 进程能直接读——这是两种完全不同的信任模型,别把后者当成前者的替代品用。

SSH agent:能签名,读不到私钥

Agent 要用 Git 走 SSH 免密,最短路径是转发宿主机的 SSH agent,而不是把私钥文件拷进 sandbox:

$ sbx exec my-sandbox bash -c 'echo $SSH_AUTH_SOCK; ssh-add -l'
/run/ssh-agent.sock
4096 SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx /Users/你的用户名/.ssh/id_rsa (RSA)

这行输出看着矛盾,其实很说明问题:ssh-add -l 报告的密钥路径是宿主机上的真实路径(/Users/你的用户名/.ssh/id_rsa),但 sandbox 里既没有 /Users 这个目录,~/.ssh 也读不到:

$ sbx exec my-sandbox bash -c 'ls ~/.ssh; ls /Users'
ls: cannot access '/home/agent/.ssh': No such file or directory
ls: cannot access '/Users': No such file or directory

SSH_AUTH_SOCK 转发的是一个到宿主机 ssh-agent 的 socket 连接,签名请求经这条 socket 发回宿主机由真正持有私钥的进程处理,私钥文件本身从没进过 microVM。Agent 能借这把钥匙开门(签 commit、连 SSH 服务器),拿不走钥匙——指纹和声明路径能看到,文件字节看不到。

删除 sandbox,清的是 VM,不是宿主机侧状态

凭证隔离还有一条容易忽略的边界:sbx rm 之后,VM 内部状态清空,但宿主机侧配置原地不动——sbx secret 存的凭证、上一篇 注册过的 MCP Server、共享 Skills store,都不会因为删掉某个 sandbox 而跟着清掉。这些是宿主机侧持久化的状态,跟单个 sandbox 的生命周期是两回事;清理凭证要单独 sbx secret rm,清理 MCP 注册要单独 sbx mcp rm

小结

五层官方隔离里,凭证这一层做得最干净:Agent 摸到的自始至终是代理和占位符,真 Key 不下发。SSH 走的是同一个思路——转发一个能用的连接,不转发底层材料。这条边界唯一会被打穿的地方,是你自己手动写进 sandbox-persistent.sh 的东西:那不是代理,是明文,进了 VM 就是进了 VM。

四篇写下来:装、连、挂工作区、共享 Skills 和 MCP、凭证,Docker Sandboxes 的隔离边界基本摸完了。剩下没验证的是 Kimaki、omp 这类非官方 Agent 能不能接进这套体系——上一篇也提过,产品级支持只有官方那份 Agent 列表,这是另一个问题,留着以后有机会再测。

乱世浮生微信公众号二维码

(转载本站文章请注明作者和出处乱世浮生,请勿用于任何商业用途)