Files
opsx-vpn/docs/specs/SDD-003-domain-tls.md
T

7.5 KiB
Raw Blame History

SDD-003:域名与 HTTPS 证书管理

字段 内容
版本 / 变更级别 0.1 / S3(证书私钥、网络入口及生产代理配置)
设计状态 Draft
实现状态 应用内 ACME、域名设置与管理员状态页已实现,本地构建/单测通过;生产端口/证书待部署验证
负责人 / 日期 待指定 / 2026-10-21
关联需求 test-link.appx365.com 使用 HTTP-01 自动签发和续期;管理后台提供域名及证书页面;桌面客户端可使用 HTTP 或 HTTPS,并在设置中填写地址
批准状态 用户要求开发与评估;生产入口切换以部署核验为准

1. 背景、目标与范围

  • 当前行为:后端路由在 :18080 提供管理站点和 API;部署文档仅描述外置 Nginx/Let's Encrypt 方案,没有集成证书状态页面。桌面 URL 校验拒绝远端 HTTP,地址位于概览页。
  • 2026-10-21 只读核对:test-link.appx365.com 解析到 121.4.111.208;服务器没有发现 Nginx、Certbot,80/443 未被监听。
  • 本次目标:使用项目已有的 Go autocert 依赖,在现有 Gin 进程中提供公网 80/443、HTTP-01 自动签发/续签;管理 API 和页面展示域名及缓存证书状态;桌面将地址放在设置中,接受 HTTP(提示明文风险)。单域名场景无需 Nginx、Certbot 或额外的 gin-gonic/autotls 封装。
  • 非目标:将证书私钥存到 SQLite/浏览器;允许任意命令、代理任意上游、公开认证服务内部端口;向桌面发放管理员 token;把 WireGuard 51820/UDP 交给 Nginx 代理。
  • 保留行为:旧 :18080 管理界面与现有 VPN 专线不受证书签发流程影响;证书失败保持现有 HTTP 服务可用。

2. 需求与约束

  • FR-01:管理员能查看当前域名、DNS、监听地址、证书颁发者/到期日;接口不返回私钥、登录凭据或证书正文。
  • FR-02:服务端仅为管理员保存的域名或 VPN_TLS_DOMAIN 指定的单一有效域名签发(环境变量优先),ACME 使用该域名 HostWhitelist;首次 HTTPS 握手签发,证书与账号密钥持久缓存于 data/acme,禁止任意域名签发。
  • FR-03:续签由 autocert.Manager 自动管理;重启后缓存证书由首次握手加载并继续续签,到期日由管理页显示;签发或续签失败保留已有 18080 HTTP 入口。
  • FR-04:HTTP 80 通过 autocert.Manager.HTTPHandler 放行 HTTP-01,其他当前域名请求重定向 HTTPS;443 用同一 Gin handler 提供管理站点与 API。OIDC 认证入口若另设域名需另行设计其路由,不从后台域名假设回调。
  • FR-05:桌面客户端服务端地址移到“设置”,支持完整 HTTP/HTTPS 根地址并允许保存;HTTP 展示风险提示,但健康检查可以执行。不保存账号和令牌。
  • NFR-01:管理 API 仅 admin,域名符合严格 FQDN 白名单;私钥缓存目录权限 0700,不暴露证书缓存内容或触发任意命令。
  • NFR-02:部署前核对 DNS、云安全组 TCP 80/443、端口占用、现有入口与回退;续签有可观测到期信息。浏览器页面与 Tauri 环境的 URL 校验一致。

3. 架构与方案

Internet TCP 80 → autocert HTTPHandler(HTTP-01;其余跳转 HTTPS)
Internet TCP 443 → autocert TLSConfig → 同一 Gin 管理站点 / API
ACME 密钥与证书 → data/acme(重启保留)
管理页面 → admin API → 仅读 DNS、域名及证书缓存元数据
旧 TCP 18080 → 同一 Gin handler(保留兼容;后续限制公网访问)

使用项目已存在的 golang.org/x/crypto/acme/autocert,无需额外 Gin 插件或依赖:管理员将域名保存到 data/tls-domain,重启后生效;VPN_TLS_DOMAIN 优先于文件配置,VPN_TLS_HTTP_ADDR / VPN_TLS_HTTPS_ADDR 可覆盖监听地址;未配置域名时完全保留旧启动行为。证书管理不写入业务数据库。首次公网 HTTPS 请求后才有真实缓存证书,管理页未签发前必须显示“等待首次访问”,不能声称证书已签发。HTTP 客户端输入只是用户选择;登录与设备令牌将来仍应推荐 HTTPS。

4. 接口、数据与配置契约

  • GET /api/system/tls 与 PUT /api/system/tls/domain 仅管理员可用,分别读取状态与保存单域名;状态返回当前/待启用域名、是否需重启、DNS、监听地址及 autocert 缓存证书的颁发者/到期日。没有手动签发按钮,首次 TLS 握手会触发签发。证书缓存位于 data/acme,不接收请求任意域名作为签发目标。
  • 云安全组 TCP 80/443 与 DNS A 解析须对应当前服务器;VPN_TLS_DOMAIN=test-link.appx365.com 生效时若端口占用,应用拒绝启动并保持旧进程可回滚。
  • 桌面仅在本机保存不含凭据的服务端地址;只允许 http / https 和根地址,拒绝 URL 账号、查询、片段、非根路径;实际健康检查继续调用 /api/health。

5. 风险与验收

风险或失败场景 防护 / 恢复 可观察信号
域名指向错误或 80 不可达 不启用证书前先核对 DNS 和公网入站;失败保留旧 18080 ACME 错误日志、证书未缓存
80/443 端口占用 启动时先绑定两个端口,失败则终止新版进程并回退旧版 启动日志与端口监听
续签失败与证书过期 autocert 自动续签、到期日提示、缓存保留 证书到期信息与 ACME 日志
公网 HTTP 管理凭据泄漏 HTTPS 默认推荐;明示 HTTP 风险;服务端切换后限制 18080 公网 HTTPS 可达、18080 仅可信入口
AC 对应需求 前置与操作 预期结果 验证方式 状态
AC-01 FR-01, NFR-01 管理员/非管理员请求状态 仅管理员可查看,证书私钥不回传 路由权限检查;线上请求待验证 部分验证
AC-02 FR-02, NFR-01 设置非法域名或端口占用 启动前拒绝,不向任意域名申请 域名/端口失败分支单测 已通过(本地)
AC-03 FR-03, FR-04, NFR-02 首次 HTTPS 请求与后续续签 HTTP-01 可达、443 站点正确、缓存保留与自动续签 DNS、ACME、TLS 实机验证 Not Run
AC-04 FR-05 桌面保存远端 HTTP/HTTPS 并检测 地址保存在设置;HTTP 提示且能检测,其他协议拒绝 Rust 单测、UI 构建;桌面实机待验证 部分验证

6. 发布与恢复

  • 先完成本地构建和测试,备份现有二进制、确认公网 80/443 无占用及云安全组策略,再配置 VPN_TLS_DOMAIN 并切换新二进制。以 https://test-link.appx365.com/api/health 触发首次签发;确认 TLS 域名、证书到期和管理站点之后收敛 18080 公网权限。
  • 若端口监听、HTTP-01 或首次握手失败,恢复原二进制/启动参数并重启旧 :18080 入口;data/acme 保留避免重复申请。不修改现有 VPN 网关或删除证书缓存。
  • 私钥文件和用户数据不删除;证书吊销、DNS 变更及防火墙收敛分别决策。

7. 待决问题

问题 是否阻塞 推荐方案
云安全组 TCP 80/443 是否放行 阻塞线上 HTTP-01 先核实公网访问再签发
test-link.appx365.com 是否同时承载 OIDC 认证服务 不阻塞管理站点 初版仅反代管理站点;OIDC 独立域名或另行设计路径路由
证书到期告警 不阻塞本地实现 当前页面展示到期时间;后续可补主动告警