Smail/docs/续期维护窗口演练记录.md
smail 94173bf765
Some checks are pending
Security Checks / security (push) Waiting to run
完成授权维护窗口内的远程续期与超时自动恢复演练
2026-09-17 23:54:30 +08:00

75 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 续期维护窗口演练记录
## 授权与范围
2026-09-17 用户明确允许测试期间暂停其他服务、测试后恢复。本轮仅临时暂停共享的 Nginx;Smail 邮件服务、Scert 后端、MySQL 和 PostgreSQL 没有停止。该授权适用于本次测试,不自动代表接受今后自动续期的常规中断窗口。
- 基线提交:`2287001`,测试前已推送。
- 测试服务器:47.108.78.12,所有语法检查、测试脚本和应用探测均在远程执行。
- 新增工具:`test/deployment/renewal_drill.py`。加载线上续期脚本,将测试目录和临近到期判断替换为隔离输入,真实调用 lego 与 ACME 测试环境。
- 未修改线上续期源码、应用双程序、正式证书、Nginx 配置或业务数据库;未清库、未执行首次安装。
- 测试环境目录从原有 staging 状态复制至独立 0700 目录,未复制正式 ACME 账号或密钥。未下载测试账号和私钥,也未删除原始数据。
## 恢复保护
执行前记录服务状态及正式文件摘要,检查 Nginx 配置和两个项目 HTTPS 入口。仅在 Nginx 已运行的情况下开始演练。
1. 原续期脚本在正常异常路径中执行 `finally` 恢复 Nginx。
2. 临时 systemd 单元设置 `ExecStopPost=/usr/bin/systemctl start nginx.service`,覆盖测试进程被终止的情况。
3. 每轮开始前创建并确认独立延时恢复定时器处于 active,作为外层兜底。确认服务恢复后停止定时器,避免稍后意外启动服务。本次未实际触发此第三层兜底。
两轮使用 MemoryHigh 96 MiB、MemoryMax 128 MiB、MemorySwapMax 0、CPUQuota 100%、TasksMax 64、GOMEMLIMIT 64 MiB,并保留 PrivateTmp、ProtectHome、NoNewPrivileges。正式应用、正式 ACME 目录和 Nginx 配置目录只读挂载,测试证书部署钩子被阻止,不能进入正式证书路径。
## 真实续期
证据目录:`/var/tmp/smail-renewal-drill-20260917-234758`。
隔离 ACME 目录:`/var/lib/smail-acme-drill-20260917-234758`,权限 0700。主机上的测试密钥和账号继续受保护,不提交仓库。
| 项目 | 结果 |
| --- | --- |
| 线上续期源码 SHA256 | `6d0abbe9466f8becd61b1cb3c750bfffb938d16c5a9bcae0b96d1451227d4216` |
| 运行模式 | 测试环境 `renew`,模拟临近到期,使用 `--days 91 --ari-disable` 确定触发更新,保留 `--reuse-key --no-random-sleep` |
| Nginx 停止请求 | 北京时间 23:48:46.946 |
| Nginx 恢复完成 | 北京时间 23:48:56.215 |
| 停止请求至恢复 | 约 9.27 秒,不代表浏览器端精确中断时长 |
| systemd 结果 | success,退出码 0,运行 10.052 秒 |
| 峰值内存 | systemd 输出约 72.6 MiB,无交换空间使用 |
| 续期产物 | 证书内容已改变,原密钥复用,密钥匹配,五个 SAN 完全一致 |
| 正式文件 | 程序、正式证书、正式私钥及现有站点配置摘要未变 |
CA 日志明确记录五个域名授权仍有效并跳过挑战。因此本轮证明了真实测试环境续期、资源限制和服务恢复,但不证明在相同限额下完成了全新公网 TLS-ALPN-01 挑战。未更改系统时间,也未等待证书自然临近到期。
测试证书没有部署到正式服务。本轮不覆盖正式 CA 到期换证、正式部署钩子的完整执行或外部失败告警。
## 超时自动恢复
证据目录:`/var/tmp/smail-renewal-drill-20260917-235019-timeout`。
在 Nginx 停止后模拟续期任务挂起,由测试单元的 20 秒启动超时终止进程。正式续期服务的 240 秒总超时未改动;本轮缩短的是临时测试单元期限。
| 项目 | 结果 |
| --- | --- |
| 停止请求 | 北京时间 23:50:21.740 |
| systemd 结果 | 预期 timeout,进程由 SIGTERM 终止,ExecMainStatus 15 |
| 单元运行时间 | 20.126 秒 |
| 峰值内存 | 76,128,256 字节,约 72.6 MiB |
| 自动恢复证据 | 执行任何人工兜底启动前,Nginx 已 active;启动时间为 23:50:41,PID 578671 |
| 两个项目入口 | Smail 443 和 Scert 8004 均返回 200,系统证书校验结果均为 0 |
被终止的子进程没有机会写最终 JSON,`result.json` 中仍为 `running`。最终结论来自 `execution.log`、`unit-result.txt`、`automatic-recovery-state.txt` 及两个 HTTPS 恢复探测文件,不能仅凭子进程 JSON 判定仍在运行。
## 结束复核与任务状态
- [✓] 真实测试环境续期成功,正式部署文件未变。
- [✓] 实际超时终止后,systemd 自动恢复 Nginx;两个项目 HTTPS 入口恢复。
- [✓] Smail PID 574584 保持不变,NRestarts 0;Scert PID 576928、MySQL PID 549584、PostgreSQL PID 313101 的进程与监听仍存在。
- [✓] 七个 TLS/STARTTLS 入口及 Host/SNI 边界复测通过,正式叶证书指纹仍为 `608fb55e3b8add3426a63f672debd86a58389a1a78d0961b9603b2e1abecae43`。
- [✓] 原 128 MiB 保留预算的资源预检通过,无 OOM;生产批准仍为 false。
- [✓] 两个临时恢复定时器 inactive;正式续期定时器 active,下一计划执行时间为 2026-09-18 04:21:56 CST。
- [✓] 演练工具拒绝缺少维护授权、使用正式 ACME 目录、覆盖已有演练结果三种调用,均在停止服务之前以参数错误退出。
- [!] 全新挑战、正式换证完整链路、外部失败与到期告警、常规共用维护窗口仍需独立验证或确认。
- [!] 代理客户端 IP、公网恢复地址、完整浏览器流程、管理员恢复撤销、凭据轮换、容量与异机恢复等原有验收项不因本轮测试自动通过。
本轮解决的是授权维护窗口内的测试环境续期及任务终止恢复验证,不能签署整体生产放行。