Files
Rocky 034a3e8745
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled
Add complimentary OOBE polish and configurable admin mTLS
Allow one server-audited onboarding polish request without credits and make the certificate gate temporarily reversible while preserving application authentication.
2026-08-20 17:05:35 +08:00
..

管理端 mTLS 部署

account.osglab.com 在同一个 TLS server 中同时承载移动端 API 和管理端。 由于 TLS 握手发生在 HTTP 路径匹配之前,配置必须使用 server 级 ssl_verify_client optional:普通客户端不提供证书时仍可正常访问。OpenResty 会把实际 证书验证结果传给 Ktor;ADMIN_MTLS_REQUIRED=true(默认值)时,/admin/admin//v1/admin 和其子路径要求验证成功。

临时关闭

在 1Panel/Compose 环境中显式设置并重启应用:

ADMIN_MTLS_REQUIRED=false

关闭后,管理端无需客户端证书,但登录仍要求用户名、密码和 TOTP,其他会话、CSRF、RBAC、 失败锁定、限流与审计规则保持不变。恢复时将该值改回 true 并重启应用。不要为了临时关闭 而删除客户端 CA、证书或轮换记录。

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 覆盖并转发证书验证结果。有效证书对应:

X-OSG-mTLS-Verified: SUCCESS

无证书时该值为 NONE。客户端传入的同名头会被覆盖;其他路径会删除该头。Ktor 只能把 OpenResty 写入的这个头作为“边缘已验证”信号,不能信任客户端提供的证书相关头,也不能用 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 秘密。

验证

ADMIN_MTLS_REQUIRED=true 时,将测试域名解析到目标边缘后执行:

# 无证书:管理路径必须是 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_MTLS_REQUIRED=false 时,无证书访问 /admin/ 应返回管理页面, /v1/admin/auth/session 应返回匿名会话状态。伪造 X-OSG-mTLS-Verified: SUCCESS 不会 改变结果,因为 OpenResty 会将其覆盖为实际验证状态。

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

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 密钥。