Scert/doc/生产部署与运维说明.md

11 KiB
Raw Blame History

Scert 生产部署与运维说明

1. 文档范围

本文档用于 Scert 0.1.0 的 Linux 生产部署、升级、备份、恢复、监控和故障处理。当前测试拓扑为:

主机 用途 允许部署内容
192.168.2.3 Scert 服务主机 Scert、systemd unit、Nginx 反向代理
192.168.2.4 SSH 和证书推送目标 SSH、公钥、证书目标目录、Nginx;禁止部署 Scert

开发验收端口:

  • Scert:127.0.0.1:9004
  • Nginx:0.0.0.0:9003

正式生产通常由 Nginx 监听 443。9003 只用于当前隔离网络开发测试,9004 必须保持回环监听,不得对公网开放。

2. 生产准入条件

部署前必须全部满足:

  • 使用 Go 1.26.6 或更高兼容安全版本完成发布构建。
  • go test -count=1 ./...、go test -race -count=1 ./...、go vet ./...、go mod verify 和 govulncheck ./... 通过。
  • Web 前端生产构建通过,生产依赖不存在高危或严重漏洞。
  • Linux amd64 发布包中的 scert、scert-admin、web/、systemd unit 和安装器来自同一提交。
  • 目标主机时间同步正常,系统 CA、OpenSSH、Nginx 和安全更新处于受支持状态。
  • Scert 仅绑定 127.0.0.1,Nginx 到 Scert 的 HTTPS 上游证书校验已开启。
  • 已完成一次停服完整备份、篡改拒绝、恢复和失败回滚演练。
  • 已确认 SSH 主机指纹并验证证书推送、私钥权限、Nginx 重载和失败回滚。
  • 管理员账号使用独立强密码,DNS、SMTP、HTTP 通知和 SSH 私钥没有写入代码、日志、文档或 Git。

任何一项未满足时,只能作为开发或受控试运行环境,不能宣称正式生产准入。

3. 发布构建

3.1 后端验证

cd backend
go test -count=1 ./...
go test -race -count=1 ./...
go vet ./...
go mod verify
govulncheck ./...

3.2 Web 构建

cd frontend
npm ci
npm run build
npm audit --omit=dev --audit-level=high

3.3 Linux amd64 二进制

cd backend
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
  go build -trimpath -ldflags "-s -w" -o ../release/linux-amd64/scert ./cmd/scert
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
  go build -trimpath -ldflags "-s -w" -o ../release/linux-amd64/scert-admin ./cmd/scert-admin

发布目录必须包含:

linux-amd64/
├── install-linux.sh
├── scert
├── scert-admin
├── web/
└── systemd/

发布包应额外生成 SHA-256 清单并通过可信通道核对。安装器会再次验证二进制是 Linux amd64 ELF,并拒绝符号链接或特殊 Web 文件。

4. Linux 安装与升级

4.1 首次安装

chmod +x install-linux.sh scert scert-admin
sudo ./install-linux.sh --source-dir . --certificate-dir /ssl

安装器不会自动启动服务,也不会创建公网防火墙规则。完成初始化并核对配置后执行:

sudo systemctl daemon-reload
sudo systemctl enable Scert
sudo systemctl start Scert
sudo systemctl status Scert --no-pager -l

4.2 升级

安装器禁止在 Scert.service 或 Scert-admin.service 运行时覆盖程序。升级顺序:

sudo systemctl stop Scert-admin
sudo systemctl stop Scert
sudo -u Scert /scert/scert --config /scert/conf/scert.json backup
sudo ./install-linux.sh --source-dir /tmp/scert-linux-amd64
sudo systemctl start Scert
sudo systemctl status Scert --no-pager -l

没有显式传入 --certificate-dir 时,升级会读取 /scert/conf/installation.json 并保留既有证书根目录。升级不得覆盖 /scert/conf/scert.json、数据库、主密钥、敏感配置、证书和备份。

4.3 systemd 安全边界

主服务使用独立 Scert 用户、UMask=0077、NoNewPrivileges、私有设备和临时目录、内核与控制组保护、只读系统目录和受限地址族。安装后必须验证:

sudo systemd-analyze verify /etc/systemd/system/Scert.service
sudo systemd-analyze security Scert.service
sudo systemctl show Scert -p User -p Group -p NoNewPrivileges -p ProtectSystem

不得为方便调试改成 root 运行,也不得扩大 ReadWritePaths 到整个文件系统。

5. 网络与反向代理

5.1 Scert 监听

生产配置或 systemd 环境覆盖:

SCERT_SERVER_HOST=127.0.0.1
SCERT_SERVER_PORT=9004
SCERT_SERVER_HTTPS_MODE=proxy
SCERT_WEB_ENABLED=true

验证:

sudo ss -lntp | grep 9004
curl -k --fail --silent --show-error https://127.0.0.1:9004/healthz
curl -k --fail --silent --show-error https://127.0.0.1:9004/readyz

ss 结果必须是 127.0.0.1:9004 或 [::1]:9004,不能是 0.0.0.0:9004。

/healthz 只用于存活检查;返回 HTTP 200 仅表示 Scert 进程和 HTTP 服务可响应。/readyz 才是生产就绪检查,安装、升级、恢复、配置变更、Nginx 切流和监控告警均必须以它为准。

/readyz 只有在以下条件全部满足时返回 HTTP 200:

  • 初始化已完成。
  • DNS 凭据引用存在并且可解密。
  • 已配置的 HTTP 通知和 SMTP 通知凭据可解密。
  • 内部 TLS 证书和私钥存在、是普通文件且不是符号链接。
  • 数据库连接检查成功。

失败时返回 HTTP 503,原因码不包含完整敏感信息引用:

原因码 处理要求
setup_incomplete 完成初始化流程。
dns_credential_missing 通过管理页面配置 DNS Provider 并完成在线 API 测试。
secret_store_unavailable 检查 master.key、secrets.json 和配置目录权限。
credential_unavailable 重新录入真实 DNS、HTTP 通知或 SMTP 通知凭据;禁止写入假 Token 绕过。
tls_material_unavailable 检查内部 TLS 证书和私钥路径、文件类型与权限。
database_unavailable 检查 SQLite 文件、MySQL 连通性、账户权限和连接限制。

/healthz 返回正常而 /readyz 返回 503 时,服务只能用于故障排查,不能接收生产流量。

5.2 Nginx

生产 Nginx 对外通常只开放 443/tcp;如需 HTTP 跳转,再开放 80/tcp。Nginx 到 Scert 必须配置:

proxy_ssl_server_name on;
proxy_ssl_name scert.example.com;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_ssl_verify_depth 3;

生产配置禁止 proxy_ssl_verify off。私有 CA 应使用 root 管理的独立 CA 文件。当前 9003 测试入口不得开放到公网。

6. 防火墙

生产建议:

端口 来源 用途 要求
22/tcp 管理网段 SSH 运维和证书推送 限制来源地址,优先仅允许密钥认证
443/tcp 业务访问网段 Nginx HTTPS 正式生产入口
80/tcp 可选 HTTP 到 HTTPS 跳转 不使用跳转时关闭
9004/tcp 无外部来源 Scert 内部端口 只绑定回环,不创建放行规则
9003/tcp 仅开发测试网段 当前 Nginx 测试入口 禁止公网开放

云安全组和主机防火墙必须同时核对,不能只配置其中一层。

7. 备份

7.1 备份内容

完整备份包含:

  • scert.json
  • master.key
  • secrets.json
  • scert.db 或 scert.sql
  • certificates/
  • manifest.json

SQLite 使用 VACUUM INTO 创建一致性快照并执行 PRAGMA quick_check。清单记录相对路径、权限、大小和 SHA-256。日志和数据库审计记录默认保留 30 天;文件日志每天最多写入 5 MiB,超过后停止文件写入但保留标准输出日志。

7.2 停服备份

sudo systemctl stop Scert
sudo -u Scert /scert/scert --config /scert/conf/scert.json backup
sudo systemctl start Scert

程序会获取 /scert/data/scert.lock 跨进程维护锁。即使存在维护锁,生产流程仍必须停服,因为证书目录还可能被外部部署工具修改。

备份目录必须保持 0700,并复制到加密、离线或不可变存储。manifest.json 不是数字签名,不能替代备份介质权限、异地副本和访问审计。

8. 恢复

恢复前先复制当前完整数据目录和证书目录到受保护位置,然后执行:

sudo systemctl stop Scert
sudo -u Scert /scert/scert --config /scert/conf/scert.json \
  restore --input /scert/backups/scert-YYYYMMDD-HHMMSS
sudo systemctl start Scert

恢复会拒绝:

  • 缺少或被篡改的清单。
  • 符号链接、特殊文件、异常权限、大小或 SHA-256。
  • 跨配置目录、数据目录、证书目录、备份目录或数据库目标恢复。
  • 无法解密的敏感配置引用。
  • 主服务或另一个维护任务持有进程锁。

恢复前副本使用 *.before-restore-YYYYMMDD-HHMMSS 命名。失败时程序会尝试整体回滚;完成后必须验证健康接口、登录、域名列表、证书读取、SSH 推送和 Nginx HTTPS。

9. SSH 与证书推送

192.168.2.4 仅作为推送目标,不安装 Scert。每台主机、每次配置都必须生成随机公钥名称:

/ssl/ssh/用户名+scert-随机值

验收要求:

  • 首次连接人工核对 SSH 主机指纹。
  • 主机指纹变化时拒绝连接,禁止自动接受新指纹。
  • cert.pem、fullchain.pem 权限为 0644,privkey.pem 为 0600。
  • 使用临时文件和原子重命名替换证书。
  • Nginx 配置测试成功后才执行 reload。
  • 推送、校验或 reload 失败时恢复旧证书。
  • 临时私钥、密码、Token 和完整连接串不得写入日志。

10. 监控与日常检查

建议至少监控:

  • /healthz 状态和响应时间。
  • /readyz 生产就绪状态;连续返回 503 时停止切流并立即告警。
  • systemd 服务状态、重启次数和退出码。
  • 证书剩余有效期;默认续期阈值为 6 天,3 天进入紧急状态。
  • 证书申请、部署、校验和通知任务失败数量。
  • 文件系统剩余空间、SQLite/MySQL 可用性和备份最后成功时间。
  • Nginx 5xx、上游 TLS 校验失败和 SSH 主机指纹变化。

常用命令:

sudo systemctl status Scert --no-pager -l
sudo journalctl -u Scert --since "1 hour ago" --no-pager
sudo ss -lntp | grep -E ':(443|9003|9004)\b'
sudo -u Scert /scert/scert --config /scert/conf/scert.json status

日志输出不得包含 DNS Token、SMTP 密码、HTTP 通知密钥、SSH 私钥、超级管理员密码或会话 Cookie。

11. 当前外部验收边界

以下项目必须有真实外部环境和合法凭据才能完成,不能由本地自动化测试替代:

  • 真实 DNS Provider API 的最小权限凭据与在线写入/清理验证。
  • 合法域名的 Let’s Encrypt Production 申请、续期和速率限制处理。
  • MySQL 5.7 与 8.0 的真实备份、恢复和失败回滚。
  • Windows Service 安装、升级、开机启动、停止和 ACL。
  • 公网生产 Nginx、真实证书链和最终业务访问。

这些外部项未完成时,可以批准 Linux + SQLite 的受控试运行,但不得把未验证能力写成已通过。