Files
OSGAccountServer/deploy/mtls
Rocky 405a2cfc0f Harden admin deployment and local acceptance
Enforce mTLS and least-privilege runtime boundaries while adding repeatable MySQL 8.4 and Docker smoke checks that require no production secrets.
2026-08-17 15:20:46 +08:00
..

管理端 mTLS 部署

account.osglab.com 在同一个 TLS server 中同时承载移动端 API 和管理端。 由于 TLS 握手发生在 HTTP 路径匹配之前,配置必须使用 server 级 ssl_verify_client optional:普通客户端不提供证书时仍可正常访问,只有 /admin/admin//v1/admin 和其子路径要求验证成功。

CA 与证书

  1. 为管理客户端创建独立私有 CA,不要复用公网服务端证书 CA 或其他内部 CA。
  2. CA 私钥离线保存;不要放入仓库、OpenResty 主机或容器镜像。
  3. 管理客户端证书使用短有效期和唯一密钥,并限制为 TLS Client Authentication (clientAuth) 用途。
  4. 仅将 CA 证书链(不含任何私钥)部署到: /www/server/openresty/conf/mtls/admin-client-ca.pem
  5. CA 文件由 OpenResty 运行用户只读,目录不可由应用进程或非特权用户写入。
  6. 更新 CA 文件后先运行 openresty -t,成功后再平滑重载。若需要立即吊销证书, 应另外配置并维护 ssl_crl;当前配置只依据证书链和有效期验证。

不要把客户端证书、客户端私钥、CA 私钥或生产证书标识提交到仓库。 计划轮换与紧急处置步骤见 ROTATION.md

上游信任边界

OpenResty 仅在管理路径且 $ssl_client_verify = SUCCESS 时向 Ktor 设置固定头:

X-OSG-mTLS-Verified: SUCCESS

客户端传入的同名头会被覆盖;其他路径会删除该头。Ktor 只能把这个头作为“边缘已验证” 信号,不能信任客户端提供的证书相关头,也不能用 DN、CN 或证书正文做隐式授权。 后端端口必须继续只监听 127.0.0.1:18080,否则攻击者可绕过边缘伪造该头。 mTLS 只证明客户端持有受信证书,管理接口仍应执行应用层身份认证、授权和审计。

一次性管理员 Bootstrap

首次部署前运行 ./gradlew generateAdminCredentials,将生成的 runtime 文件仅临时写入 1Panel/Compose 环境,并同时设置:

ADMIN_ENABLED=true
ADMIN_BOOTSTRAP_ENABLED=true

确认初始管理员已创建且可以登录后,必须将 ADMIN_BOOTSTRAP_ENABLED 改回 false 并从 1Panel、Compose 环境和部署文件中永久删除 ADMIN_BOOTSTRAP_OPERATOR_IDADMIN_BOOTSTRAP_USERNAMEADMIN_BOOTSTRAP_PASSWORD_HASHADMIN_BOOTSTRAP_TOTP_SECRET_BASE32。 日常运行只保留 ADMIN_ENABLED=true。重启后再次验证登录,确保服务不再依赖 Bootstrap 秘密。

验证

将测试域名解析到目标边缘后执行:

# 无证书:管理路径必须是 404。
curl -i https://account.osglab.com/admin
curl -i https://account.osglab.com/v1/admin

# 有效管理证书:请求应到达 Ktor,状态码由管理接口决定。
curl -i --cert admin-client.pem --key admin-client-key.pem \
  https://account.osglab.com/v1/admin

# 无证书的普通移动端 API:响应应与变更前一致。
curl -i https://account.osglab.com/health

# 即使客户端伪造信任头,无证书访问管理路径仍必须是 404。
curl -i -H 'X-OSG-mTLS-Verified: SUCCESS' \
  https://account.osglab.com/v1/admin

还应使用由非管理 CA 签发或已过期的客户端证书确认返回 404,并在 Ktor 测试端点确认: 管理请求只收到固定值 SUCCESS,普通 API 不收到 X-OSG-mTLS-Verified

部署后可在受信设备运行不含登录凭据的自动验收:

ADMIN_CLIENT_CERT=/secure/path/admin-client.pem \
ADMIN_CLIENT_KEY=/secure/path/admin-client-key.pem \
bash deploy/verify-admin.sh

脚本验证公开健康检查、无证书隐藏、伪造边缘头拦截、有效证书访问,以及 HSTS/CSP 安全响应头;它不会读取或传输管理员密码和 TOTP 密钥。