使用本清单决定哪些值属于运行时环境、哪些生成到数据库、哪些由插件存储。每一节说明轮换如何影响正在运行的站点。
在 Node.js 上,将运行时机密放入托管平台的密钥管理器,以便进程启动时进入 process.env。对于 Worker,使用 wrangler secret put。不要把机密值放进 astro.config.mjs、wrangler.jsonc 或 import.meta.env;Vite 可能将构建时值嵌入服务器捆绑包。
概览
| 机密 | 来源 | 存储位置 | 丢失密钥的影响 |
|---|---|---|---|
EMDASH_ENCRYPTION_KEY | 运维人员(emdash secrets generate) | 仅环境 / Worker 机密 | 在恢复匹配密钥之前,无法读取已加密的插件设置 |
| 预览机密 | 自动生成(环境覆盖) | options 表(emdash:preview_secret) | 未使用的预览链接停止工作;新的没问题 |
| IP 盐 | 自动生成(环境覆盖) | options 表(emdash:ip_salt) | 评论速率限制的连续性重置 |
| 会话与 API 令牌 | 按会话/令牌生成 | 会话存储 / 数据库(仅哈希) | 无 — 从不存储明文 |
| OAuth 提供方凭证 | 你(Google/GitHub 控制台) | 环境 | 通过该提供方登录会停止,直到替换 |
| Turnstile 机密 | 你(Cloudflare 控制台) | 环境 | 评论 CAPTCHA 验证失败 |
| S3 凭证 | 你(存储提供方) | 运行时环境 | 媒体上传/下载失败,直到替换 |
| 插件机密 | 你(管理设置 UI) | 加密的数据库设置 | 恢复匹配的加密密钥或重新输入值 |
| CLI 凭证 | emdash login / emdash plugin publish 设备流 | ~/.config/emdash/auth.json(模式 0600) | 再次运行设备流 |
| 注册表 CLI 凭证 | emdash-plugin atproto OAuth | ~/.emdash/oauth/、~/.emdash/credentials.json(模式 0600) | 重新登录;身份位于你的 PDS |
加密密钥
EMDASH_ENCRYPTION_KEY 加密以 type: "secret" 声明的插件设置。EmDash 使用 AES-GCM,并以插件 ID 与设置键作为认证数据。格式错误的值会产生面向运维人员的启动消息,需要加密插件设置的操作会 fail closed。无关的站点请求继续工作。
以下命令生成格式正确的值。将其存入运行时环境, 或在部署使用该变量时存为 Worker 机密。
npx emdash secrets generate
# emdash_enc_v1_<43 base64url chars>
# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY
格式为 emdash_enc_v1_ 后跟 32 个随机字节的无填充 base64url。该值由运维人员提供,不存入数据库。将其保存在密钥管理器以及单独的恢复备份中。
要轮换密钥,将新值放在前面,并在逗号后保留旧值:
EMDASH_ENCRYPTION_KEY=emdash_enc_v1_<new-key>,emdash_enc_v1_<old-key>
EmDash 用第一把密钥加密新的与重新保存的值。读取时使用存储的 kid 指纹选择较旧的密钥。在移除旧密钥之前重新保存每个插件机密,然后从仅含新密钥的部署验证这些集成。EmDash 目前不报告哪些密钥 ID 仍在使用,因此请保留你重新保存的凭证清单,并在每个集成通过该验证之前不要移除旧密钥。
生成的站点机密
两个机密在首次使用时自动生成并持久化到 options 表,因此在请求、部署与 isolate 之间保持稳定。生成是原子的——并发冷启动会收敛到一个值。
预览机密
签署预览 URL(HMAC)。存储为 emdash:preview_secret;32 个随机字节,base64url。
- 覆盖: 若需要跨多个进程使用同一机密,或出于审计原因固定它,请设置
EMDASH_PREVIEW_SECRET(旧别名:PREVIEW_SECRET)。环境始终优先于存储值。 - 轮换: 删除
emdash:preview_secret行(或更改环境变量)并重新部署。影响:先前签发的预览链接停止验证。其他不会坏——下次预览请求会生成(或从环境读取)新机密。 - 若丢失: 没有不可恢复的内容。预览链接设计上是短命的。
预览 URL 如何构建与验证见预览指南。
IP 盐
为用于评论速率限制的评论者 IP 地址 SHA-256 哈希(评论上的 ip_hash)加盐。存储为 emdash:ip_salt。特定于站点,因此哈希无法跨 EmDash 安装关联。
- 覆盖: 设置
EMDASH_IP_SALT。为向后兼容,也会查阅EMDASH_AUTH_SECRET/AUTH_SECRET——历史上从它们派生盐的安装会保持稳定哈希。 - 轮换: 更改环境变量或删除
emdash:ip_salt行。影响:新评论提交会哈希到不同值,因此所有人的速率限制计数重新开始。现有评论及其存储的哈希不受影响。 - 若丢失: 无数据丢失。仅速率限制连续性重置。
会话与 API 令牌
- 会话 使用 Astro 的会话存储(Cloudflare 上为 Workers KV,Node 上为文件系统)。Cookie 携带不透明会话 ID;没有需要管理的签名机密。退出登录结束会话,或清空会话存储(例如 KV 命名空间)强制所有人重新登录。
- API 令牌(前缀
ec_pat_、ec_oat_、ec_ort_)是不透明的 256 位随机值;仅存储其 SHA-256 哈希。明文在创建时显示一次。通过在管理后台撤销并重新创建来轮换。 - 邀请、魔术链接与恢复令牌 是单用途的,以 SHA-256 哈希存储在
auth_tokens中,并有时限(邀请 7 天,魔术链接 15 分钟)。
没有需要主动备份或轮换的内容:数据库泄露只暴露哈希,每个令牌都可从管理后台撤销或重新签发。
用户提供的服务凭证
外部服务的凭证从环境读取,从不写入数据库。在提供方轮换,更新变量,重新部署。
| 服务 | 变量 |
|---|---|
| Google 登录 | EMDASH_OAUTH_GOOGLE_CLIENT_ID、EMDASH_OAUTH_GOOGLE_CLIENT_SECRET(或无前缀别名) |
| GitHub 登录 | EMDASH_OAUTH_GITHUB_CLIENT_ID、EMDASH_OAUTH_GITHUB_CLIENT_SECRET(或无前缀别名) |
| Marketplace 发布(CI) | EMDASH_MARKETPLACE_TOKEN |
| Turnstile(评论) | EMDASH_TURNSTILE_SECRET_KEY(或 TURNSTILE_SECRET_KEY) |
| S3 兼容存储 | S3_ACCESS_KEY_ID、S3_SECRET_ACCESS_KEY、S3_ENDPOINT、S3_BUCKET、S3_REGION |
在 Cloudflare 上用 wrangler secret put 设置;本地开发放入 .env。Wrangler 读取 .dev.vars 或 .env,不同时读取,存在时 .dev.vars 优先。通过绑定的 R2 不需要访问密钥变量,因为绑定授予运行时访问。见媒体存储。
插件机密
插件以 type: "secret" 声明的设置(邮件提供方的 API 密钥、表单 CAPTCHA 等)在管理 UI 中输入,并加密到 options 表的 plugin:<id>:settings:<key> 下。即使匹配的加密密钥不可用,管理后台也只收到机密是否已设置,以便管理员替换无法读取的凭证。插件代码在其隔离运行时通过 ctx.settings 读取明文。存储在已声明设置模式之外的值,包括任意插件 KV 与状态条目,不使用此加密路径。
- 凭证轮换: 在提供方轮换凭证,并将新值粘贴到插件的设置页。保存会写入新的加密信封。
- 明文迁移: 早期 EmDash 版本存储的机密仍可读。再次保存每个值以加密它。
- 若加密密钥丢失: 从单独的密钥备份恢复匹配的
EMDASH_ENCRYPTION_KEY。若无副本,请在每个受影响提供方替换凭证,并在配置新加密密钥后输入替换值。
CLI 凭证
emdash CLI 保存两类凭证,均位于 ~/.config/emdash/auth.json(遵循 XDG_CONFIG_HOME),以仅所有者权限(0600)创建:
- 站点令牌 —
emdash login通过 OAuth 设备流对你的 EmDash 实例认证,并按实例 URL 存储结果令牌。emdash logout移除它;每次调用时,--token或EMDASH_TOKEN覆盖存储的令牌。 - Marketplace 令牌 —
emdash plugin publish通过 GitHub 设备流对 EmDash Marketplace 认证,并按marketplace:<origin>存储结果 JWT。CI 发布请改设EMDASH_MARKETPLACE_TOKEN——它优先于存储的凭证。
丢失该文件无害:再次运行 emdash login(或会重新运行设备流的 emdash plugin publish)。
插件注册表 CLI 凭证
单独的 emdash-plugin CLI(包 @emdash-cms/plugin-cli)面向实验性的 AT Protocol 注册表。在那里发布与你的 AT Protocol 身份(发布者 DID)绑定——站点本身不持有发布凭证,安装会对照归因于该 DID 的发布记录校验和验证产物。
- 通过 atproto OAuth 认证。OAuth 会话/状态 blob 位于
~/.emdash/oauth/,发布者身份(DID、handle、PDS)缓存在~/.emdash/credentials.json;二者均以仅所有者权限写入。 - 在 CI 中通过
EMDASH_PUBLISHER_DID、EMDASH_PUBLISHER_HANDLE与EMDASH_PUBLISHER_PDS提供身份;EMDASH_REGISTRY_URL覆盖注册表主机。来自 CI 的自动publish仍需要运行器上~/.emdash/oauth/中的 OAuth 会话文件——仅环境变量不携带 OAuth 会话。 - 轮换或撤销发布访问发生在你的 AT Protocol 账户(例如应用密码),而非 EmDash 内。见 Atmosphere 认证。
轮换速查
| 我想… | 这样做 |
|---|---|
| 轮换插件设置加密 | 将新密钥放在前面,重新保存插件机密,然后移除旧密钥 |
| 使所有预览链接失效 | 删除 emdash:preview_secret 选项行(或更改环境覆盖) |
| 重置评论速率限制哈希 | 更改 EMDASH_IP_SALT(或删除 emdash:ip_salt 选项行) |
| 撤销泄露的 API 令牌 | Admin → Users → API tokens → 撤销,然后创建替换 |
| 结束所有会话 | 清空会话存储(Workers KV 命名空间 / 会话目录) |
| 替换提供方凭证 | 在提供方轮换,更新环境变量,重新部署 |
| 替换插件 API 密钥 | 在提供方轮换,在插件管理设置中重新输入 |