凭据与传输边界
代理编码会话需要凭据——用于与 Claude 通信的 Anthropic 密钥、用于推送的 GitHub 令牌、用于部署的 AWS 密钥。它还会运行任意代码、安装任意软件包,并遵循它自己并未编写的文件中的指令。把你真实的机密交给这样的环境,正是密钥最终落入窃密者收件箱的原因。
Bromure Agentic Coding 通过传输边界化解了这种矛盾:VM 内部的代理只会看到伪造的占位符令牌。你真实的凭据以加密形式存放在 macOS 宿主机上,并由宿主机侧的 MITM 代理服务器在最后可能的时刻——在请求已经离开 VM 之后,且仅当它发往凭据所属的主机时——将其替换到传输线路上。VM 内部的任何文件、环境变量或进程都绝不会包含真实的 API 密钥、OAuth 令牌、AWS 机密或 SSH 私钥。
本章从头到尾解释这一机制,然后逐一介绍每种受支持的凭据类型及其生命周期、按次使用的审批系统、入侵检测器,以及如何自行验证边界。
注意: 本章介绍概念与运行时行为。有关设置窗格逐字段的参考,请参阅设置 → 凭据。
传输边界概览
三条原则定义了这个模型:
- VM 中是伪造值。 你配置的每个凭据在 VM 内部都会被一个保留结构的伪造值替换。伪造值保持验证器所期望的形状——Anthropic 伪造值以
sk-ant-api03-brm-开头,GitHub 伪造值是ghp_加 36 个字符——因此claude、gh、doctl等工具会毫无怨言地接受它们。 - 仅在传输线路上使用真实值。 VM 发出的每个 HTTPS 请求都会被隧道传输到宿主机代理服务器,后者将其解密、把伪造值替换为真实值,然后在上游重新加密。替换的作用域限定为该凭据所铸造的目标主机。
- 失败即关闭。 如果有任何东西绕过了代理服务器,请求就只携带一个伪造值,上游身份验证将失败。不存在任何真实机密会意外泄露的路径。
伪造值是确定性的:每个伪造值都通过 HKDF-SHA256 从真实值加上每次安装独立的 32 字节盐派生而来。同一个真实密钥在你的 Mac 上始终映射到同一个伪造值,因此对其密钥进行指纹识别的客户端(例如 Claude Code 会缓存密钥哈希)绝不会看到凭据在会话之间"轮换"。
| 凭据 | VM 中的伪造形状 |
|---|---|
| Anthropic API 密钥 | sk-ant-api03-brm-… |
| OpenAI API 密钥 | sk-brm-… |
| xAI API 密钥 | xai-brm-… |
| GitHub 令牌 | ghp_ + 36 个字符(共 40 个) |
| GitLab 令牌 | glpat- + 20 个字符 |
| DigitalOcean PAT | dop_v1_ + 十六进制(共 64 个字符) |
| Linear API 密钥 | lin_api_ + 40 个字符(共 48 个) |
| MCP bearer 令牌 | brm-mcp_… |
| Docker 注册表密码 | brm-docker-…(至少 40 个字符) |
| Kubernetes bearer 令牌 | brm-k8s-… |
| 数据库机密 | brm-db-…(至少 32 个字符) |
| 通用手动令牌 | brm_… |
边界没有开关。代理服务器是 VM 唯一的出口路径;替换就是本应用中凭据的工作方式。
替换如何端到端工作
一个经过身份验证的请求的完整往返:
- 会话启动——令牌方案。 当工作区 VM 启动时,应用会构建一个按工作区的令牌方案,将每个真实凭据与其派生的伪造值配对。伪造值被写入 VM:环境变量(
ANTHROPIC_API_KEY、GH_TOKEN、LINEAR_API_KEY等)和配置文件(~/.git-credentials、~/.docker/config.json、~/.kube/config、~/.aws/config、~/.config/doctl/config.yaml、MCP 配置)。真实值被加载到代理服务器的内存替换映射中,每个都以其所属的目标主机作为键。 - 请求离开 VM。 客户机的 HTTPS 流量通过 virtio 套接字(vsock 端口 8443)隧道传输到宿主机代理服务器。VM 没有其他通往网络的路由。
- TLS 终止。 代理服务器出示一个伪造的按主机叶证书——以目标主机名作为 CN 和 SAN,使用按主机的 EC 密钥——由 Bromure Agentic Coding Root CA 签名。由于该 CA 的公开证书在启动时已安装到 VM 的信任存储中,客户机的 TLS 客户端会接受该连接,代理服务器便可以读取明文请求。
- 替换。 代理服务器查找请求中出现的每个伪造令牌(请求头,以及对于已选择加入的凭据类型,还包括请求体),如果目标主机与凭据的作用域匹配,就将其替换为真实值。
- 上游重新加密。 重写后的请求通过 Apple 的
URLSession(即 macOS 自己的 TLS 栈)重新发送到真实目标,该栈会验证上游服务器的真实证书。响应通过隧道流回客户机。
如果目标与某个伪造值的作用域不匹配,伪造值就原样发出(并在上游身份验证失败)——或者,当这种不匹配看起来像是数据外泄时,请求会被直接阻止(参见下文入侵检测器)。
Bromure Agentic Coding Root CA
该 CA 是每次安装独立的,位于 ~/Library/Application Support/BromureAC/ca/(cert.pem 加上一个 mode-0600 的 key.pem)。它的主题为 "Bromure Agentic Coding Root CA",组织为 "Bromure"。值得了解的属性:
- CA 有效期为 10 年。伪造的按主机叶证书有效期为 1 年,并回溯 24 小时,因此在挂起/恢复期间时钟漂移的客户机仍然会接受它们。叶证书在应用进程的生命周期内按主机缓存。
- 公开证书在启动时安装到每个 VM 的信任存储中(通过 meta 共享传递,并用
update-ca-certificates应用)。它绝不会离开你的机器,除了你的 VM 之外没有任何东西信任它。 - 要轮换 CA,请退出应用并删除
ca/目录。下次启动时会铸造一个新的 CA,每个 VM 在下次启动时获取新的公开证书。轮换不会使其他任何东西失效——工作区机密和profile.json元数据保持不变。
主机作用域
每个替换条目都绑定到一个主机作用域。匹配是精确或子域匹配且不区分大小写,绝不是子串匹配:作用域限定为 openai.com 的凭据匹配 api.openai.com,但不匹配 openai.com.evil.example——一个仿冒主机无法诱骗代理服务器用真实密钥装点其请求。手动令牌规则可以有意使用空白主机过滤器,这意味着"在任何主机上注入";这是你为每个条目做出的明确选择(参见通用 API 密钥)。
从构造上失败即关闭
这个设计从不依赖代理服务器不可绕过来保证保密性——它依赖于机密根本不在那里:
- 一个以某种方式跳过代理服务器的请求携带的是伪造令牌;上游 API 会拒绝它。
- 在 VM 内部签名的 AWS 请求是用伪造的机密密钥签名的;如果它们直接到达 AWS,会因
InvalidSignatureException而失败(参见下文 AWS)。 - SSH 私钥字节根本不在 VM 中;只有签名会跨越边界。
在工作区编辑器中管理凭据
凭据是按工作区配置的。打开工作区的编辑器(编辑工作区)并在侧边栏中选择凭据。
该窗格打开时首先是 Git 身份(写入 VM 中 ~/.gitconfig 的姓名和电子邮件;两者都留空以保持 git 的默认值——占位符只是示例,不是凭据),接着是一个仅列出你已配置的凭据的列表,按类别标题分组(代理、Git、云、数据库、SSH、其他)。底部有两个按钮:添加凭据 会打开一个凭据类型的选择器——Git 令牌、SSH 密钥、AWS 凭据、DigitalOcean 令牌、Linear API 密钥、Kubernetes、容器注册表、数据库和其他 API 密钥——而 导入 env 文件… 则从 .env 或 ~/.bashrc 批量导入。主代理自己的密钥位于 代理 窗格中,接下来会介绍。点击存储;下一次会话启动会将伪造值写入 VM 并将真实值加载到代理服务器中。
按凭据的审批门控(使用前询问)和每个服务的写入策略是在护栏窗格中设置的,而不是在这里——凭据窗格不再承载那些控件。有关逐字段的参考,请参阅设置 → 凭据。
有六个提供商是自动处理的——Anthropic、OpenAI、GitHub、GitLab、DigitalOcean 和 Kubernetes 无需手动令牌规则;它们各自的专门章节会介绍它们。其他一切都通过其他 API 密钥处理。
从 env 文件导入。 导入 env 文件… 读取现有的 .env 文件——或 ~/.bashrc——并将其变量转换为凭据。解析器处理 KEY=VALUE 和 export KEY=VALUE,去除两侧的引号和尾部的注释,并有意跳过任何需要 shell 求值的内容($VAR 插值或 $(…) 替换),因此把它指向真实的 .bashrc 是安全的。随后一个审阅面板会以掩码值显示这些变量:已识别的名称(ANTHROPIC_API_KEY、OPENAI_API_KEY、XAI_API_KEY、GH_TOKEN/GITHUB_TOKEN、GITLAB_TOKEN、AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN、DIGITALOCEAN_ACCESS_TOKEN、LINEAR_API_KEY)会自动映射到其凭据类型,而未识别的名称可以作为通用手动令牌导入,并附带你提供的以逗号分隔的主机作用域。已配置的条目会被标记并保持未选中状态,因此重新导入绝不会悄无声息地覆盖机密。
凭据类型
主代理 API 密钥(Anthropic、OpenAI、xAI)
工作区主代理的密钥在 代理 窗格中设置,其中每张代理卡片都提供一个身份验证模式选择器。
选择 API 令牌 并将密钥粘贴到字段中(Claude Code 用 Anthropic API 密钥,Codex 用 OpenAI API 密钥,Grok Build 用 xAI 密钥)。生命周期:
- 在 VM 中: 导出为
ANTHROPIC_API_KEY/OPENAI_API_KEY/XAI_API_KEY,持有与提供商形状匹配的伪造值(sk-ant-api03-brm-…、sk-brm-…、xai-brm-…)。 - 在传输线路上: 在发往提供商主机(分别为
anthropic.com、openai.com、x.ai)的请求上替换为真实密钥。 - 审批: 要对每个会话的首次使用进行门控,请在护栏窗格中为该代理的密钥开启 使用前询问(参见按次使用审批)。它默认是关闭的。
选择器上的其他身份验证模式——订阅(交互式登录)、Bedrock (AWS) 和 本地模型——将在下文以及本地模型中介绍。从 CLI 来看,同样的选择是 bromure-cli workspaces create 上的 --auth token|subscription|bedrock|local(以及用于即时工作区的 bromure-cli vm run 上的 token|subscription|bedrock)。
Claude、Codex 与 Grok 订阅
如果你拥有 Claude、ChatGPT(Codex)或 Grok 订阅而不是 API 密钥,代理通常会通过交互式 OAuth 登录进行身份验证——一个沙盒化的 VM 无法(也不应该)用真实令牌完成的浏览器流程。Bromure Agentic Coding 通过两种机制支持订阅。两者都以同一个地方结束:真实的 OAuth 令牌只存放在宿主机上,客户机以一个伪造密钥运行。
使用 Claude / ChatGPT / Grok 注册(推荐)
将代理的身份验证模式设置为 订阅(交互式登录) 并点击 注册…。会发生的情况:
- 应用检查代理服务器是否正在运行(否则注册会被拒绝),并显示一个标题为 使用 Claude 注册(或 ChatGPT / Grok)的说明面板。点击"继续"。
- 一个一次性注册 VM 启动——临时、隔离,没有工作区文件夹挂载,也没有凭据替换映射。在其内部,运行真实的登录命令(
claude login、codex login或 Grok 对应的命令)。 - 你 Mac 的默认浏览器打开提供商的登录页面。像往常一样登录。你大约有 4 分钟时间,之后流程会超时。
- 生成的 OAuth 令牌在宿主机上被捕获、加密并存储;一次性 VM 被销毁。
- 如果你是从工作区编辑器启动注册的,应用会询问 与每个工作区共享?——选择 每个工作区 将该订阅存储为共享默认值,或选择 仅此工作区。从应用的偏好设置启动的注册总是不加询问地存储共享默认值。
此后,每个会话的客户机都以 API 密钥模式运行,使用一个确定性的伪造凭据——Claude 用一个伪造的 ANTHROPIC_API_KEY,Codex 用一个植入的 ~/.codex/auth.json(其中包含一个伪造的、有效期设在遥远未来的 JWT,因此客户端绝不会自己尝试刷新它),Grok 用一个占位的 ~/.grok/auth.json。代理服务器识别这个伪造值,并在传输线路上注入一个有效的 Authorization: Bearer 访问令牌(对于 Claude,还加上 OAuth beta 请求头)。
令牌保管与刷新 完全在宿主机侧进行。宿主机会在到期前大约 5 分钟针对提供商的令牌端点刷新令牌(Claude 用 platform.claude.com/v1/oauth/token,Codex 用 auth.openai.com/oauth/token,Grok 用 auth.x.ai/oauth2/token),因此一次刷新就能服务于每个正在运行的 VM,而客户机从不持有刷新令牌。新捕获的记录会有意存储为已经过期的状态,从而在首次使用时强制刷新——在你依赖它之前就证明刷新路径可用。
身份验证模式选择器旁边的控件完成整个生命周期:重新注册… 重复捕获过程(例如在上游撤销会话之后),而 忘记 从宿主机删除已存储的订阅。
会话内令牌替换
或者,如果代理在 VM 内部自己登录(你在会话中运行 claude login),代理服务器会注意到一个真实的订阅 OAuth 令牌正发往提供商,并主动提出接管它。会出现一个面板——替换 Claude 订阅令牌?(或 Codex)——说明真实令牌可以留在这台 Mac 上,同时一个伪造值在 VM 的凭据文件中替换它。访问令牌和刷新令牌会一起被替换。你的选项:
| 按钮 | 效果 |
|---|---|
| 替换 | 真实令牌移至宿主机存储;VM 的凭据文件被重写为伪造值;代理服务器从现在起在传输线路上注入真实令牌。 |
| 暂不 | 本会话不做任何更改;下一个会话会再次出现该提示。 |
| 对此工作区永不 | 停止此工作区的提示。 |
此提示背后的按工作区状态在编辑器中显示为 Claude 订阅令牌替换 / Codex 订阅令牌替换(默认未设置;在你选择后为"已接受"或"已拒绝")。宿主机到 VM 的替换通道是有意单向的:宿主机只能向 VM 写入伪造值,而 VM 只能向宿主机发送真实值——不存在 VM 可以借以索要真实令牌的 RPC。VM 内的代理还会拒绝写入任何不带 brm- 伪造前缀的凭据,因此即便一个行为异常的宿主机也无法用真实值破坏客户机的凭据文件。
注意: Codex 在客户机内部保持订阅模式(其 API 密钥模式面向不同的后端),而 Grok 的令牌通过文件
~/.grok/auth.json传输,而不是通过 vsock 代理。这些是实现细节;保管模型是相同的。
AWS
AWS 得到了所有提供商中最深入的处理,因为 AWS 请求不是通过 bearer 令牌进行身份验证的——它们是被签名的(SigV4)。在工作区编辑器中打开 凭据 → AWS;一个分段控件在 静态密钥 和 SSO / Identity Center 之间选择。
静态密钥与宿主机重签名器
粘贴你的 访问密钥 ID 和 机密访问密钥(外加一个可选的 STS 会话令牌 和一个 默认区域)。生命周期:
- 在 VM 中:
~/.aws/config指向一个 credential_process 助手,它通过 vsock 端口 8445 提供真实的访问密钥 ID 与一个 40 字符的伪造机密访问密钥配对,并省略会话令牌。每个 AWS SDK、awsCLI、terraform 和 boto3 都会原生识别它;无需针对特定工具进行设置。 - 客户机做什么: 用伪造的机密对其请求签名,生成一个语法上有效但密码学上注定失败的 SigV4 签名。
- 在传输线路上: 宿主机的 AWS 重签名器检测发往
*.amazonaws.com和*.amazonaws.com.cn的请求(包括 GovCloud、ISO、区域性以及 bucket 风格的 S3 主机),剥离客户机的签名,在存在会话令牌时注入真实的X-Amz-Security-Token,并在请求离开你的 Mac 之前用真实机密重新签名。每次成功的重签名都会发出一个带有掩码访问密钥的credential.aws_sign审计事件,可在追踪中查看。
这在最强意义上是失败即关闭的:真实机密密钥以任何形式都绝不存在于 VM 中,而绕过代理服务器的请求会被 AWS 以 InvalidSignatureException 拒绝。
有三种请求样式不受支持,会向客户机返回一个明确的错误而不是无声的失败:分块流式 S3 上传(STREAMING-AWS4-HMAC-SHA256-PAYLOAD,以 501 应答)、SigV4A 非对称签名,以及预签名的查询字符串 URL(它们把签名嵌入在重签名器无法替换的位置)。
SSO / IAM Identity Center
如果你的组织使用 IAM Identity Center,请选择 SSO / Identity Center 而不是粘贴长期有效的密钥:
- 点击 授予对 ~/.aws 的访问权限 并批准文件夹访问提示(一个安全作用域的授权;该文件夹在宿主机上读取,绝不会挂载到 VM 中)。
- 从 SSO 配置文件 选择器中选择你的配置文件。应用会发现
~/.aws/config中带有sso_start_url、sso_account_id和sso_role_name的[profile …]部分,并解析[sso-session …]引用;账户 ID 和角色以只读方式显示。 - 在会话启动时,宿主机从 SSO 令牌缓存(
~/.aws/sso/cache)解析临时角色凭据。如果缓存的令牌已过期,你的浏览器会为aws sso login打开——在宿主机上运行,来自/usr/local/bin/aws。
解析出的临时密钥馈入与静态密钥相同的重签名器;VM 仍然从不看到机密。凭据在宿主机上会在到期前大约 5 分钟自动刷新。
Bedrock
代理身份验证模式选择器上的 Bedrock (AWS) 使用工作区已配置的任何 AWS 凭据(静态或 SSO)针对 AWS Bedrock 运行 Claude Code——它是主工具的一种身份验证模式,而不是单独的凭据。设置身份验证模式,配置 凭据 → AWS,并可选地在工作区上设置一个 Bedrock 模型 ID。签名走相同的重签名器路径,因为 Bedrock 端点是 *.amazonaws.com 主机。
Git HTTPS 令牌(GitHub、GitLab、Bitbucket、自托管)
用于 git-over-HTTPS 的个人访问令牌位于 GitHub 令牌 / GitLab 令牌 / Bitbucket 令牌 下(统称 HTTPS 令牌)。每个条目需要一个主机、一个用户名和令牌;自托管的 GitLab 或 Gitea 实例通过设置主机字段即可工作。生命周期:
- 在 VM 中: 一个伪造值被写入
~/.git-credentials以及gh/glab配置;GH_TOKEN和GITLAB_TOKEN被导出,以便 CLI 自动进行身份验证。伪造形状匹配每个厂商的验证器(GitHub 用ghp_+ 36,GitLab 用glpat-+ 20,其他用brm_…),因此gh和glab中的前缀和长度检查会通过。 - 在传输线路上: 在发往该条目 git 主机的请求上替换为真实令牌。
- 审批: 每个条目在护栏窗格中都有自己的 使用前询问 行。
如果你只需要通过 SSH 进行 git push,你可能根本不需要 HTTPS 令牌——参见下文 SSH 密钥。
通用 API 密钥(其他 API 密钥 / 手动令牌规则)
对于应用不自动处理的任何 API,在 其他 API 密钥 下添加一个条目(手动令牌规则,也以 MITM 令牌替换 的形式呈现)。点击 添加令牌 并提供:
| 字段 | 含义 |
|---|---|
| 名称 | 该条目的标签。 |
| 值 | 真实机密(在宿主机上加密存储)。 |
| 环境变量名 | 伪造值在 VM 内部导出所用的变量。在你的代码中引用它。 |
| 主机过滤器(可选) | 替换的主机作用域。 |
有两种边缘情况是有意为之的:
- 空的环境变量名: 不导出任何东西;你从会话的欢迎横幅中复制伪造值,并将其放在你的工具所需的任何位置。
- 空白的主机过滤器: 真实值会在任何主机上注入,无需询问。这是一个明确的始终开启的选择——对于有许多区域性主机名的 API 很有用——但这意味着凭据的作用域不再保护它。要门控一个无作用域的机密,请在护栏窗格中为它开启 使用前询问(或者干脆给它一个主机过滤器)。
Anthropic、OpenAI、GitHub、GitLab、DigitalOcean 和 Kubernetes 在这里从不需要手动条目。
1Password 机密引用(op://)
与其粘贴一个真实机密,一个 其他 API 密钥 的值可以是一个 1Password 机密引用——op://vault/item/field,或者 op inject 和 .env.op 文件所使用的花括号形式 {{ op://vault/item/field }}。磁盘上只会存储引用本身;机密本身绝不会被写入宿主机或 VM 的任何地方。编辑器识别该引用,将其明文显示(它不是机密),并注明它通过 1Password 解析。
在每次工作区启动时,Bromure 用 1Password CLI(op read)在宿主机侧解析该引用,从引用字符串铸造一个伪造值(因此即使机密轮换,伪造值也保持稳定),并只将该伪造值导出到 VM 中。然后 MITM 代理服务器在传输线路上把伪造值替换为解析出的值,与它对粘贴的机密所做的完全一样——而且它每 2 分钟重新解析一次,因此在 1Password 中轮换该项目会在几分钟内生效,无需重启。
这需要安装并已登录 op CLI——通过 1Password 应用进行生物识别解锁,或在终端中执行 op signin。如果找不到 op,编辑器会显示一个 获取 1Password CLI 链接,工作区在启动时会呈现安装说明;如果解析失败(未登录,或项目不存在),Bromure 会呈现该错误,以便你修复并重启工作区。
导入 .env 或 .env.op 文件(编辑器中的 从 .env 导入…)会自动识别 op:// 值——无论是像 ANTHROPIC_API_KEY 这样的已识别名称,还是像 STRIPE_KEY 这样的任意名称——并将每个值作为持有该引用的手动令牌存储。
DigitalOcean
在 凭据 → DigitalOcean 下粘贴一个个人访问令牌(在浏览器中打开 DigitalOcean 令牌页面 链接会带你到令牌生成页面)。伪造值(dop_v1_ + 十六进制,64 个字符)被导出为 DIGITALOCEAN_ACCESS_TOKEN 并写入 ~/.config/doctl/config.yaml,因此不需要 doctl auth init。替换涵盖发往 digitalocean.com 的请求,外加一个用于 docker login / doctl registry login 针对 registry.digitalocean.com 所用的 base64 Basic-auth 数据块的第二个条目,因此注册表的推送和拉取也能解析。
Linear
在 凭据 → Linear 下粘贴一个个人 API 密钥(链接:在浏览器中打开 Linear API 设置;密钥来自 linear.app → Settings → API)。伪造值(lin_api_ + 40)被导出为 LINEAR_API_KEY,Linear SDK、MCP 服务器和 CLI 工具会自动识别它;替换被严格限定在 linear.app 作用域内(GraphQL 在 api.linear.app,MCP 在 mcp.linear.app)。工作区上的 Linear 密钥也是 Linear 议题自动化触发器的前提条件——参见自动化与 CLI。
MCP 服务器 bearer 令牌
在 MCP 窗格中配置的 HTTP 传输 MCP 服务器得到相同的处理:真实的 bearer 令牌留在宿主机上,一个 brm-mcp_… 伪造值被注入到代理读取的 MCP 配置中,代理服务器在传输线路上替换它,作用域限定为该服务器的主机。只有已启用且带有非空 bearer 令牌的 HTTP 传输服务器才会收到替换条目。
一个额外的便利:对于带有 brm-mcp_ 条目的主机,代理服务器以 404 应答 OAuth/OIDC 发现路径(.well-known 授权服务器、受保护资源和 OpenID 配置端点)。Claude Code 于是将该服务器视为已预先身份验证,而不是尝试自己的 OAuth 流程——那个流程反正在 VM 内部永远无法完成。
容器注册表(Docker Hub、GHCR 等)
凭据 → 容器注册表 管理 docker pull/push 的 HTTP Basic 身份验证。预设有 Docker Hub(docker.io)、GitHub Container Registry(ghcr.io)和 GitLab Container Registry(registry.gitlab.com);任何其他注册表都可以按主机添加。生命周期:
- 在 VM 中:
~/.docker/config.json包含一个伪造的 auth 数据块——你的用户名与一个派生的brm-docker-…密码配对的 base64——因此 Docker 相信它已登录。 - 在传输线路上: 代理服务器在匹配的注册表主机上替换为真实的 base64 数据块。distribution-spec 的令牌交换也得到处理:为已知的 auth realm 添加了替换条目(Docker Hub 针对
auth.docker.io进行身份验证,DigitalOcean 的注册表针对api.digitalocean.com)。 - 导入: 点击 导入 config.json… 从宿主机上现有的
~/.docker/config.json拉取条目。委托给credsStore/credHelpers的条目会被跳过——它们的密码存放在操作系统钥匙串中,而不是文件里——导入摘要会报告跳过了多少个以及原因。 - 审批: 按注册表,通过护栏窗格中的 使用前询问。移除此注册表 会删除一个条目。
Kubernetes 上下文
凭据 → Kubernetes 将 kubeconfig 上下文转变为经代理服务器中介的集群访问。点击 导入 kubeconfig 将现有的 kubeconfig 解析为每个上下文一行(当前上下文在前,自动检测身份验证类型),或点击 添加上下文 手动输入服务器 URL、凭据、命名空间和集群 CA。在任何情况下,VM 都会收到一个合成的 ~/.kube/config:客户机中的 kubectl 与代理服务器(通过 Bromure CA 信任)通信,而绝不直接与 API 服务器通信。
按身份验证类型:
- Bearer 令牌 上下文在 VM 中获得一个
brm-k8s-…占位符,在传输线路上替换为真实令牌。 - 客户端证书 上下文在 VM 中获得一个一次性的自签名证书和密钥;真实的证书和密钥在宿主机上注册为一个
SecIdentity,用于上游 mTLS。 - Exec 插件 上下文根本不会在 VM 中运行插件。exec 插件轮询器每隔刷新间隔(默认 600 秒,下限 60)在宿主机上运行该命令,解析
ExecCredentialJSON,并将新鲜的令牌馈入替换映射。刷新会保留条目的许可状态。
如果 kubeconfig 提供了集群自己的 CA,它会被转发,以便代理服务器可以验证上游 API 服务器。导入的 kubeconfig 中的文件路径字段(CA、证书、密钥)在导入时会被急切读取——之后磁盘上这些文件的更改不会被采纳。每个上下文在护栏窗格中都有自己的 使用前询问 行,在那里写入策略还可以在任何字节被转发之前于宿主机侧剥离破坏性动词(kubectl delete、AWS Delete*/Terminate*、docker push、git push)——这是与凭据替换分开的一层。
HTTP 数据库(MongoDB、ClickHouse、Elasticsearch)
凭据 → 数据库(MongoDB / ClickHouse / Elasticsearch 部分)涵盖讲 HTTPS 的数据库端点——Mongo Data API、ClickHouse 的 HTTP 接口、Elastic。每个端点需要一个引擎、主机、机密、用户名、身份验证类型,以及一个或多个环境变量名(以逗号分隔),brm-db-… 伪造值在这些名称下导出;从你的代码或连接字符串中引用这些变量。
数据库凭据是唯一一类替换会同时扫描请求体以及请求头和查询参数的家族,因为连接机密经常随 JSON 或 SQL 载荷一起传输。代理服务器在请求体替换后修补 Content-Length;其他流量的无关 multipart 或二进制请求体绝不会被触碰(所有其他替换都是请求头范围的)。Basic-auth 端点的 base64 用户名和机密数据块也会被替换。按端点的 使用前询问 和写入策略在护栏窗格中设置。
SSH 密钥
SSH 完全无需任何令牌即可处理:VM 的 SSH_AUTH_SOCK 由一个通过 vsock(端口 8444)的 ssh-agent 桥接支撑。客户机可以列出身份并请求签名,但私钥字节只存放在宿主机上,从物理上无法从 VM 内部读取或提取。存在两个密钥来源,都在 凭据 → SSH 密钥 下:
- 按工作区的默认密钥。 一个共享的默认 ed25519 密钥对在应用启动时生成(存储在 Application Support 中的
default-ssh/下),并复制到每个新工作区的代理目录中。该窗格显示工作区的公钥,以便你把它粘贴到你的 git 主机中(对于 GitHub:github.com/settings/keys)。你也可以用 CLI 的bromure-cli workspaces ssh-keygen <workspace-id|name>铸造一个新鲜的密钥,它会打印新的公钥。 - 导入的密钥。 在 导入的 SSH 密钥 下点击 导入… / 导入文件… 并将应用指向一个现有的私钥文件——支持 RSA、ed25519 和 ECDSA,包括加密的密钥。加密的密钥在导入时会提示输入一次其口令;该口令存储在 macOS 钥匙串中(服务
io.bromure.agentic-coding.ssh-key-passphrases),并在启动时通过SSH_ASKPASS提供,绝不记录。导入密钥的签名流经应用为自己生成的一个私有 ssh-agent 进程(在临时目录下的套接字上运行ssh-agent -D)——与你系统上的其他任何东西分开。
对于每个导入的密钥,在护栏窗格中开启 使用前询问 会使每个 VM 内的签名请求都提示征求许可。每个签名——无论默认密钥还是导入密钥——都会发出一个 credential.ssh_sign 审计事件,携带密钥的 SHA256 指纹以及它是托管密钥还是导入密钥。
注意: 你的 macOS 登录 ssh-agent(launchd 的那个)被有意绝不暴露给 VM。只有按工作区的密钥和你明确导入的密钥才能从会话中访问。
按次使用审批与授权时长
本章中的任何凭据都可以被标记为 使用前询问——护栏窗格中的一个按凭据复选框(在控件本身上标注为 使用前需要审批),默认关闭,在 UI 中描述为:"在会话中首次使用此凭据时弹出一个确认对话框。"
当一个被门控的凭据在会话中首次被使用时,代理服务器会保持住请求并显示一个标题为 允许"工作区名称"使用凭据? 的许可对话框(填入你工作区的名称和凭据的标签),提供四个按钮:
| 按钮 | 授权 |
|---|---|
| 允许 5 分钟 | 有时限;凭据在 5 分钟内无需进一步提示即可流通。 |
| 允许 1 小时 | 有时限,1 小时。 |
| 允许在本会话剩余时间内 | 直到会话窗口关闭。 |
| 不允许 | 请求被拒绝;该拒绝会被记住 5 分钟,因此代理的重试风暴不会产生对话框风暴。 |
值得了解的行为:
- 合并。 需要同一凭据的并发请求会合并到一个对话框上——一个话痨的代理同时发出十二个并行 API 调用只会产生一个提示,而这十二个都会遵循你的决定。
- 拒绝优先。 一个实时的拒绝会在参考任何较早的允许之前短路。
- 设计上短暂。 授权和拒绝仅保存在内存中,并在会话拆除时被撤销。"本会话剩余时间"绝不会在窗口关闭后存续,也没有任何东西会跨应用运行持久化。
- 无头会话。 在 SSH 或无头会话中,提示会出现在工作区的 tmux 中,而不是作为 GUI 警报——参见远程访问。
对于 AWS,该门控适用于每次宿主机侧的签名调用;对于 SSH 密钥,适用于签名请求;对于其他所有一切,适用于会话的首次传输替换。
提示: 许可门控是按凭据的,而不是按主机的。如果你想让一个无作用域的手动令牌保持受控,审批就是为此设计的机制。
凭据审批窗口
窗口 → 凭据审批… 打开一个实时视图,显示当前应用运行期间做出的每个许可决定:有时限的允许(5 分钟 / 1 小时 / 本会话剩余时间)和被记住的拒绝。每一行显示工作区名称和剩余时间,并提供 撤销;全部撤销(⌘⌫)一次性清除所有内容。该列表每 2 秒自动刷新,并随着授权到期自然缩短。
由于决定仅在内存中,因此在授权到期后、会话关闭后(会话作用域的授权)以及应用退出后,该窗口为空。它是当下的控制面板,而不是审计日志——要查看历史记录,请使用追踪。
入侵检测器
伪造值身兼两职:除了替代机密之外,它们还是绊线。一个伪造令牌恰好只有一个合法的目标家族——它所铸造的主机作用域。sk-ant-api03-brm-… 出现在发往 pastebin.example 的请求中是没有任何正当理由的。因此代理服务器扫描每个出站请求——请求头和请求体,通过一个 Aho-Corasick 自动机,足够廉价,可以在所有请求上运行——查找任何发往其作用域之外的伪造值。
当它发现一个时,会将该请求视为企图外泄凭据:
- 该请求被 以 HTTP 451 阻止。没有一个字节被转发到目标。
- VM 被立即暂停。
- 触发一个警报:"Bromure 检测到一次出站企图,要将会话凭据泄露给一个并非为其铸造的主机。VM 已被暂停。"
随后该工作区被标记为已攻陷——工作区浏览器显示 已攻陷——启动时将提示擦除磁盘和主目录——下一次启动需要补救:"要继续,必须擦除 VM 磁盘映像和持久化的主目录文件夹。你的令牌、ssh 密钥和工作区设置会被保留。" 点击 擦除并启动 以继续。请留意随附的警告:共享文件夹不会被擦除,因此如果攻陷是通过共享文件夹中的某个软件包或文件进来的,它可能仍然在那里——在恢复工作之前请审查那些文件夹。
对攻陷警报的推荐响应:打开追踪检查器(⇧⌘I)或运行 bromure-cli trace leaks 查看违规的主机和请求,判断是项目依赖还是提示注入的指令负有责任(参见提示注入和供应链),然后擦除并重新启动。
作用域细节:
- 无作用域的伪造值是豁免的。 一个带有空白主机过滤器的手动令牌按设计是"任何主机",因此无法触发检测器;伪造的订阅占位符同样被排除。
- 第一方同族被容忍。 匹配镜像替换的作用域策略,但有一处放宽:与凭据提供商同处一个已注册域名下的主机(例如
anthropic.com下的 Claude 或 Codex 基础设施)使用家族匹配,因此一个合法的api.anthropic.com令牌出现在mcp-tools.anthropic.com上不算误报。其他一切都是严格的。 - 看起来真实的泄露也会被标记。 独立于伪造绊线,代理服务器会标记出站流量中未替换的、看起来真实的机密——带有已知前缀(
sk-ant-、ghp_、AKIA等)的Bearer或x-api-key值,或 20 个字符及以上的不透明令牌。这些在追踪检查器和bromure-cli trace leaks中显示为泄露警告;它们通常意味着有真实机密被手动粘贴进了 VM,而传输边界的存在正是为了让这变得没有必要。
没有什么需要启用——检测器始终开启。
机密在宿主机上的存储位置
所有敏感内容都在一个每次安装独立的 256 位主密钥下以 AES-GCM 静态加密——即机密保管库。主密钥存放在 macOS 数据保护钥匙串 中,作用域限定为应用的签名身份,可访问性为 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly 且 iCloud 同步已禁用。它从不提示、从不同步,也绝不离开 Mac。如果钥匙串不可达(未签名或未预配的构建),应用会回退到存放在密文旁边的一个 mode-0600 密钥文件——较弱,因为此时密钥和密文共享一个磁盘,但它保持静态加密正常运作;一个完全预配的发行版使用钥匙串。
实际影响:
- 备份和副本是密文。 一个 Time Machine 备份或一个复制的
Application Support文件夹只包含加密的数据块;没有这台 Mac 的钥匙串条目就无法解密它们(除非使用了文件回退密钥并一并复制了)。 - 擦除钥匙串条目会轮换密钥。 现有的加密数据块变得不可读,你需要重新输入凭据。
profile.json中的非敏感元数据不受影响。 - 没有任何东西被同步到任何地方。 应用本身不会上传、同步或备份任何凭据、令牌存储或密钥材料。
磁盘上的位置,除另有说明外均在 ~/Library/Application Support/BromureAC/ 下:
| 位置 | 内容 |
|---|---|
ca/cert.pem、ca/key.pem | Bromure Agentic Coding Root CA(密钥 mode 0600)。删除该目录以轮换。 |
fake-salt.bin | 伪造派生背后的每次安装独立 32 字节 HKDF 盐(0600)。删除它会轮换这台 Mac 上的每个伪造值。 |
claude-subscription.enc、codex-subscription.enc、grok-subscription.enc | AES-GCM 加密的订阅 OAuth 存储(共享默认值加上按配置文件的覆盖),0600。 |
secrets-master.key | 0600 的回退主密钥——仅当数据保护钥匙串不可达时才存在。 |
default-ssh/id_ed25519.raw、default-ssh/id_ed25519.pub | 复制到新工作区中的共享默认 SSH 密钥对。 |
profiles/<id>/ssh/ | 按工作区铸造的 SSH 密钥(代理目录)。 |
钥匙串:io.bromure.agentic-coding.master-key | AES-256 保管库主密钥(账户 v1),数据保护钥匙串。 |
钥匙串:io.bromure.agentic-coding.ssh-key-passphrases | 导入的 SSH 密钥口令,每个配置文件/密钥文件一项。 |
用于导入的宿主机侧读取——~/.aws/config、~/.aws/sso/cache/*.json、~/.docker/config.json、kubeconfig 文件——仅在宿主机上发生;这些文件都绝不会挂载到 VM 中。加密的追踪请求体(参见追踪)使用相同的保管库密钥。
自行验证边界
传输边界的设计是可核查的,而不是靠信任。从任何会话内部的 shell:
1. 环境持有伪造值。
echo "$ANTHROPIC_API_KEY"
# sk-ant-api03-brm-… ← a fake, not your key
env | grep -E 'TOKEN|KEY'
# every value is brm_/ghp_/glpat_/dop_v1_/lin_api_-shaped placeholder
2. 配置文件持有伪造值。
cat ~/.git-credentials # fake tokens per git host
cat ~/.docker/config.json # fake base64 auth blobs
grep -A2 credential_process ~/.aws/config # helper, not a secret key
3. 然而,一切都能工作。
aws sts get-caller-identity # succeeds — the host resigned the request
gh api user # succeeds — the fake was swapped on the wire
4. VM 内部的 TLS 终止于代理服务器。
openssl s_client -connect api.anthropic.com:443 -brief 2>&1 | head
# issuer: the Bromure Agentic Coding Root CA — not a public CA
5. SSH 密钥不存在,但签名有效。
ssh-add -L # lists public keys served by the vsock agent
ls ~/.ssh/id_* # no private key files to find
6. 在宿主机上,观察替换发生。 为工作区启用追踪,然后:
bromure-cli trace summary # per-request swap reports and leak warnings
bromure-cli trace leaks # only the suspicious ones
或打开追踪检查器(⇧⌘I),在其中被替换的请求会被标注为 绝不发送到 VM——由代理服务器替换。
如果你曾在 VM 内部发现一个真实凭据,它只可能通过两种方式到达那里:你(或代理,在你的指示下)手动把它粘贴进去,或者它通过共享文件夹到达。替换机制从不将真实值写入客户机——而入侵检测器把传输线路上看起来真实的机密视为泄露,正是因为它们本不应该存在于那里。
快速参考
客户机-宿主机边界上的 vsock 端口:
| 端口 | 用途 |
|---|---|
| 8443 | HTTPS MITM 代理服务器——客户机的全部出口。 |
| 8444 | SSH_AUTH_SOCK 背后的 ssh-agent 桥接。 |
| 8445 | AWS credential_process 助手。 |
| 8446 | Claude 订阅令牌替换代理——它与本地推理桥接共享的一个端口(它们在不同流程中设置;在诊断同时使用两者的会话时请记住这一点——参见本地模型)。 |
| 8447 | Codex 订阅令牌替换代理(访问、刷新和 ID 令牌)。 |
相关 CLI 命令(完整参考见自动化与 CLI):
| 命令 | 用途 |
|---|---|
bromure-cli workspaces create --auth token|subscription|bedrock|local | 创建一个带有其身份验证模式的工作区。 |
bromure-cli vm run --auth token|subscription|bedrock | 启动一个 VM,为即时工作区选择身份验证模式。 |
bromure-cli workspaces ssh-keygen <workspace> | 在宿主机侧铸造一个新鲜的工作区 SSH 密钥并打印公钥。 |
bromure-cli trace summary [workspace] | 汇总被追踪的流量,包括替换和泄露警告。 |
bromure-cli trace leaks [workspace] | 显示带有潜在凭据泄露的被追踪请求。 |