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.
This commit is contained in:
Rocky
2026-08-17 15:20:46 +08:00
parent 1a9c518f96
commit 405a2cfc0f
17 changed files with 1480 additions and 37 deletions
+86
View File
@@ -0,0 +1,86 @@
# 管理端 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](ROTATION.md)。
## 上游信任边界
OpenResty 仅在管理路径且 `$ssl_client_verify = SUCCESS` 时向 Ktor 设置固定头:
```text
X-OSG-mTLS-Verified: SUCCESS
```
客户端传入的同名头会被覆盖;其他路径会删除该头。Ktor 只能把这个头作为“边缘已验证”
信号,不能信任客户端提供的证书相关头,也不能用 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
秘密。
## 验证
将测试域名解析到目标边缘后执行:
```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`
部署后可在受信设备运行不含登录凭据的自动验收:
```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 密钥。