Smail/docs/部署后自动归档与证书保留.md
smail a045a0cd17
Some checks are pending
Security Checks / security (push) Waiting to run
实现部署启动自动归档密钥与证书双版本保留
2026-09-08 20:34:38 +08:00

7.3 KiB
Raw Blame History

部署后自动归档与证书保留

已确认要求

  • 正式程序在任意部署目录启动后自动创建目录,不依赖手动整理或开发脚本。
  • 已采用 config/ssl/data/log 布局的旧部署,启动时自动归档三把业务密钥,保留原字节。
  • ssl/managed 自动保留两套受管证书材料,后续导入、续期、应用及重启继续执行。
  • 域名证书原文件继续保存在 ssl/ 根目录,不与业务加密密钥混放。
  • 模拟部署使用 yunx-test/,修改完成后必须完整构建并核验最新二进制。

程序创建的目录

部署目录/
├── config/                         # 初始化完成后的五个生效 JSON
├── ssl/
│   ├── credentials/
│   │   └── credential.key
│   ├── external-email-encryption/
│   │   └── external-email-encryption.key
│   ├── external-email-fingerprint/
│   │   └── external-email-fingerprint.key
│   ├── dkim/
│   ├── managed/                    # default 与 upload 合计保留两套
│   ├── 域名.crt
│   └── 域名.key
├── data/
├── log/
├── smail
└── smail-admin

目录由主服务启动入口 InitializeDeployment 创建;密钥由对应业务首次需要时创建,不能为凑齐文件生成无用密钥。Windows 二进制带 .exe 后缀。初始化未完成时不会伪造五个完成态配置文件。

三个目录分别保存配置凭据加密密钥、外部邮箱加密密钥、外部邮箱检索指纹密钥。ACME 账户密钥的进一步归档不在本次三个业务目录改动中,原文件继续保留。

启动迁移

启动先检查再移动:已初始化部署缺少密钥或数据库、新旧密钥重复、密钥不是 32 字节、存在链接或无效目标目录时拒绝继续,不覆盖、不重新生成替代密钥。Linux 还检查密钥文件权限。

有效的 ssl/credential.key 等旧文件使用重命名归档到业务目录,内容不变,因此旧配置密文、外部邮箱密文及指纹仍有效。每次移动后同步目录;迁移中断后允许下次启动继续,重复启动不会再次生成密钥。

更早的 config/ 或 data/ 混放部署仍须执行原有完整迁移流程,不能只搬三把密钥而遗漏数据库、证书和历史引用。

两份保留规则

  • 一份是完整的证书和私钥组合,不是两个单独文件。
  • 当前生效证书优先保留;提交新版本时保留上一份材料;其余按版本目录时间排序补足两份。
  • 待应用候选、正在导入或续期的材料、磁盘已提交引用受到保护;操作进行时可能暂时超过两份,应用或取消后再次清理。
  • 启动后、定期证书维护、配置应用、回滚、取消候选及重新加载时自动执行。
  • 仅删除程序识别的历史版本。未知文件、链接、无法安全检查的目录保留并告警;事务恢复未完成时暂停清理。
  • 私钥文件锁保护跨进程暂存,配置状态锁协调提交与清理。停止或替换管理器时释放暂存锁。
  • 上一份证书过期不会阻止正常清理,但运行加载和回滚仍执行完整证书有效期、强度、配对检查。
  • 已清理证书的历史配置不能回滚,预览和执行均返回明确中文错误,必须重新导入有效证书。

域名文件与运行引用的边界

ssl/域名.crt、ssl/域名.key 是用户放置的证书原文件,自动归档和清理不删除它们。

本次没有将服务运行引用改成根目录文件。 自定义证书仍经校验后导入 ssl/managed/.../version-...,配置事务切换成对的受管引用,避免外部文件变化或两文件替换期间配对不一致。若要求运行引用也固定为 ssl/域名.crt 与 ssl/域名.key,还需实现完整的成对发布、失败恢复和备份引用迁移,不能只复制文件或直接改 JSON 冒充完成。

验证与边界

  • 自动化回归覆盖新建目录、旧密钥字节不变、中断续迁、重复启动、冲突拒绝、跨模式总数两份、暂存保护、未知文件保护、过期前版本、旧 current 清理及历史回滚拒绝。
  • test/deployment/verify_ssl_startup.py 在原前后端停服且最新包已部署后运行,将原 yunx-test 暂存至 test-log,用同一二进制在空 yunx-test 正式启动两次,再恢复原部署。所有测试产物保留,不删除业务库。
  • 空目录正式启动只验收自动目录创建和初始化页面可达,不等于完成整个首次初始化、管理员恢复权限或插件生产隔离验收。
  • Linux 编译通过不等于 Linux 生产运行验收。正式管理员恢复通道的保护不降低。

本轮实测记录(2026-09-08)

以下记录来自本轮最新源码构建,不以手工创建当前目录代替启动验证。

验证项目 实测结果 本地记录
空目录正式启动两次 仅放两个程序,使用 smail.exe -p 15201,两次均自动创建部署目录及五个 SSL 子目录,初始化页面返回 200 test-log/ssl-startup-20260908-202756/result.json
旧部署自动升级 三把业务密钥归档前后字节不变,旧位置不再保留重复文件 test-log/ssl-upgrade-result-20260908.json
旧证书自动清理 由新程序启动完成,受管材料从 11 套收敛为 2 套,当前证书和私钥仍存在 同上
原文件保护 五个生效 JSON、根目录证书、ACME 密钥及其他原 SSL 文件字节不变;已有运行目录完整恢复 同上及空目录启动记录
邮件 TLS 465、993、995 均完成 TLS 1.3 握手,实际证书指纹与当前配置指向的证书一致 test-log/ssl-upgrade-tls-20260908.log
全量自动化回归 前端 140/140、部署 4/4、Go 全量通过 test-log/run-2026-09-08T12-25-13-445Z-12312/
专项并发检查 配置、运行路径、配置凭据、外部邮箱及 SSL 设置包的 -race 测试通过 test-log/run-2026-09-08T12-26-15-343Z-27176/
最新部署包 前端、三个插件、Windows 内嵌资源主程序及管理员程序完成构建,源码指纹和部署哈希通过 node deploy/build-state.mjs verify --deployed 核验 out/build-state.json

当前页面优化环境保留为前端源码热更新、后端最新编译程序,运行配置统一读取 yunx-test/config/。前端 HTTPS 及后端 /api/ping 均返回 200;后端使用已明确标记的开发恢复通道豁免参数,与上表不含该参数的空目录正式启动测试分开记录。

本轮没有进行浏览器页面交互验收,也没有宣称完整生产初始化或 Linux 运行验收通过。前端已有富文本编辑器分包体积提醒不在本次修改范围内。

任务状态

  • [✓] 正式主程序自动创建业务目录,不依赖部署脚本创建。
  • [✓] 已采用 SSL 布局的旧部署自动迁移三把业务密钥,重复启动不更换密钥。
  • [✓] 受管证书正常稳定状态保留两套,保护生效、暂存和恢复所需材料。
  • [✓] 最新包部署、空目录启动、旧部署升级及邮件 TLS 验证完成。
  • [!] 根目录域名文件直接作为运行引用尚未改造;本轮只保证原文件保留,并继续使用已校验的受管副本。
  • [!] Linux 正式运行、完整首次初始化及正式管理员恢复流程尚未完成本轮实机验收。