Files
OSGAccountServer/deploy/mtls/README.md
T
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

105 lines
4.6 KiB
Markdown
Raw 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.
# 管理端 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 环境中显式设置并重启应用:
```text
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](ROTATION.md)。
## 上游信任边界
OpenResty 在管理路径用 `$ssl_client_verify` 覆盖并转发证书验证结果。有效证书对应:
```text
X-OSG-mTLS-Verified: SUCCESS
```
无证书时该值为 `NONE`。客户端传入的同名头会被覆盖;其他路径会删除该头。Ktor 只能把
OpenResty 写入的这个头作为“边缘已验证”信号,不能信任客户端提供的证书相关头,也不能用
DN、CN 或证书正文做隐式授权。
后端端口必须继续只监听 `127.0.0.1:18080`,否则攻击者可绕过边缘伪造该头。
mTLS 只证明客户端持有受信证书,管理接口仍应执行应用层身份认证、授权和审计。
## 一次性管理员 Bootstrap
首次部署前运行 `./gradlew generateAdminCredentials`,将生成的 runtime 文件仅临时写入
1Panel/Compose 环境,并同时设置:
```text
ADMIN_ENABLED=true
ADMIN_BOOTSTRAP_ENABLED=true
```
确认初始管理员已创建且可以登录后,必须将 `ADMIN_BOOTSTRAP_ENABLED` 改回 `false`
并从 1Panel、Compose 环境和部署文件中永久删除
`ADMIN_BOOTSTRAP_OPERATOR_ID``ADMIN_BOOTSTRAP_USERNAME`
`ADMIN_BOOTSTRAP_PASSWORD_HASH``ADMIN_BOOTSTRAP_TOTP_SECRET_BASE32`
日常运行只保留 `ADMIN_ENABLED=true`。重启后再次验证登录,确保服务不再依赖 Bootstrap
秘密。
## 验证
`ADMIN_MTLS_REQUIRED=true` 时,将测试域名解析到目标边缘后执行:
```sh
# 无证书:管理路径必须是 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 会将其覆盖为实际验证状态。
部署后可在受信设备运行不含登录凭据的自动验收:
```sh
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 密钥。