Features

添加外部密钥(BYOK)

自带供应商密钥——本地模式下从环境变量自动检测,云端模式下采用 sealed-box 加密。

BYOK(Bring Your Own Key,自带密钥)让你的请求走你自己的供应商账号,而不是 BitRouter 的。你按上游的标价直接付费——BitRouter 不抽成、不加每 token 费用,且在云端写入路径上从不接触明文密钥。

按部署模式的不同,密钥流转方式也不同。

本地模式——环境变量自动检测

启动二进制、把供应商密钥设到环境里,就完事了。无需配置文件。

export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...
export GOOGLE_API_KEY=AIza...
bitrouter

BitRouter 在启动时检测密钥,仅暴露当前已配置密钥的供应商。当某供应商的密钥缺失时,路由到该供应商的请求会返回 402 Payment Required,错误体里会指明缺失的环境变量名。

识别的环境变量

供应商推荐名兼容名
OpenAIBITROUTER_OPENAI_API_KEYOPENAI_API_KEY
AnthropicBITROUTER_ANTHROPIC_API_KEYANTHROPIC_API_KEY
GoogleBITROUTER_GOOGLE_API_KEYGOOGLE_API_KEYGEMINI_API_KEY
自定义(registry 内)BITROUTER_<PROVIDER_ID>_API_KEY

BITROUTER_* 名称的优先级高于兼容名——当你的 shell 已经为别的工具设置了 OPENAI_API_KEY,又想让 BitRouter 走另一个账号时很有用。

对于在 registry 中以 id: my-provider 注册的自定义供应商,请设置 BITROUTER_MY_PROVIDER_API_KEY(全大写,连字符变下划线)。

密钥可热更新。 BitRouter 监听父进程的环境;更新密钥后(重新 export 并 kill -HUP $(pgrep bitrouter)),下一次请求即生效,无需重启。

云端模式——Sealed-box 加密

cloud.bitrouter.ai 上,你的供应商密钥会在客户端用节点的 X25519 sealed-box 公钥加密之后再提交。节点在写入路径上从不看到明文;密文仅在请求时于内存中解密、且永不落日志。

流程如下:

  1. 拉取节点公钥。 GET /v1/byok/encryption-pubkey 返回当前的 X25519 公钥及其 kek_id 指纹。按指纹缓存,并以 If-None-Match 形式回传,可在密钥未变时直接拿到 304 Not Modified
  2. 用公钥加密明文密钥。 使用 libsodium 的 crypto_box_seal(或任何 sealed-box 实现)。
  3. 提交密文。 console 在你粘贴密钥时,就在浏览器里完成第 1、2 步——你不需要离开 dashboard。同样的提交 API 也可用于脚本化的入网;详见 API 参考

加密示例

如果你用脚本提交密钥,下面是最小化的 sealed-box 步骤。其输出的密文就是提交端点期望的内容。

import sodium from 'libsodium-wrappers';

await sodium.ready;

const meta = await fetch(
  'https://cloud.bitrouter.ai/v1/byok/encryption-pubkey'
).then(r => r.json());

const ciphertext = sodium.crypto_box_seal(
  sodium.from_string(process.env.OPENAI_API_KEY),
  sodium.from_base64(meta.public_key, sodium.base64_variants.ORIGINAL)
);

const ciphertextB64 = sodium.to_base64(ciphertext, sodium.base64_variants.ORIGINAL);
// 提交 { provider: 'openai', kek_id: meta.kek_id, ciphertext: ciphertextB64 }
import os, base64, requests
from nacl.public import PublicKey, SealedBox

meta = requests.get('https://cloud.bitrouter.ai/v1/byok/encryption-pubkey').json()
pubkey = PublicKey(base64.b64decode(meta['public_key']))
ciphertext = SealedBox(pubkey).encrypt(os.environ['OPENAI_API_KEY'].encode())

payload = {
    'provider': 'openai',
    'kek_id': meta['kek_id'],
    'ciphertext': base64.b64encode(ciphertext).decode(),
}
# 将 `payload` POST 到 BYOK 提交端点。
META=$(curl -s https://cloud.bitrouter.ai/v1/byok/encryption-pubkey)
PUBKEY=$(echo "$META" | jq -r .public_key)
KEK_ID=$(echo "$META" | jq -r .kek_id)

CIPHERTEXT=$(printf '%s' "$OPENAI_API_KEY" \
  | sodium-seal --pubkey "$PUBKEY" \
  | base64)

# 提交 { provider: "openai", kek_id: "$KEK_ID", ciphertext: "$CIPHERTEXT" }

公钥端点支持 If-None-Match 缓存——把上一次响应中的 kek_id 钉住后回传,密钥未变时即可拿到 304 Not Modified

密钥作用域

默认情况下,密钥的作用域是 工作区——工作区内的成员都可以发起经由这把密钥路由的请求,但任何人都无法读到密文或原始密钥。

若要做一次性覆盖,可以通过 X-BitRouter-Key 头把密钥附在单次请求上:

curl https://cloud.bitrouter.ai/v1/chat/completions \
  -H "Authorization: Bearer $BITROUTER_TOKEN" \
  -H "X-BitRouter-Key: openai=sk-..." \
  -d '{...}'

单次请求密钥以明文形式经 TLS 传输。 云端节点解 TLS、在请求期间将密钥保留在内存里、随后丢弃——它不会被持久化。这对临时脚本和 CI 任务很方便,但若每次请求都同一把密钥,更建议走 sealed-box 上传通道:既更省(请求里不用每次带密钥字节),也更难因调试日志而泄漏。在本地模式下,回环跳的存在让明文头永不离开本机网络。

轮换、撤销与审计

  • 轮换 — 对同一供应商提交一份新密文即可,旧记录会原子性地被覆盖。
  • 撤销 — 在 dashboard 里操作。使用旧密钥的在途请求会跑完;新请求开始返回 402 Payment Required
  • 审计 — 工作区的密钥历史视图记录了每一次提交的成员、时间和所用 kek_id。任何人——包括 BitRouter 运维——都不可见明文。

当节点的 kek_id 轮换时(每 90 天一次),已提交的密文会在内存中用前一个密钥重新封装;除非你显式选择,无需重新加密。

自定义供应商

只要 registry 中的供应商在其 manifest 的 payment.modes 里声明了 byok,就可以走 BYOK。提交时使用的 provider 字段必须与 registry 里的 id 完全一致。本地模式的环境变量识别遵循 BITROUTER_<PROVIDER_ID>_API_KEY 约定。

How is this guide?

Last updated on

On this page