Files
sub2api-cn-relay-manager/docs/TRUSTED_SUBJECT_DEPLOY_GUIDE.md
phamnazage-jpg 4e2ee087fd feat(vNext.4): implement trusted-subject security chain for portal user key self-service
- Add portal_auth.go: Portal user session auth with HMAC-signed cookies
- Add /api/portal/session/{login,logout,state} endpoints
- Update nginx config template: cookie-to-header trusted proxy pattern
- Update frontend: sync CRM session on login/logout
- Add TRUSTED_SUBJECT_DEPLOY_GUIDE.md with remote43 deployment steps
- Update EXECUTION_BOARD.md: mark trusted-subject blocking issue as resolved

This implements the secure chain:
  Browser → Portal → nginx (cookie→header) → CRM (verify proxy secret)

Required remote43 actions:
1. Generate 64-char hex secret
2. Update .env.crm with TRUSTED_* config
3. Update nginx with cookie map and header injection
4. Restart services

Fixes EXECUTION_BOARD.md 2026-06-08 blocking issue
2026-06-09 07:48:03 +08:00

195 lines
5.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.
# vNext.4 Trusted-Subject 安全链部署指南
> 解决 2026-06-08 EXECUTION_BOARD.md 中记录的线上阻塞问题
## 问题描述
remote43 当前 nginx `/portal-admin-api/` 未注入 `X-CRM-Authenticated-Subject` / `X-CRM-Trusted-Proxy`,导致无法在现网安全完成新的 user-key 真验闭环。
## 解决方案
实施受信代理安全链:
```
用户浏览器 ← → Portal 前端 ← → nginx (cookie→header 转换) ← → CRM
↑ ↓
设置 httpOnly cookie 验证并注入受信 header
```
## 所需变更
### 1. CRM 二进制更新 (已完成)
新增文件:
- `internal/app/portal_auth.go` - Portal user session 认证模块
- `internal/app/portal_auth_test.go` - 测试用例
变更文件:
- `internal/app/http_api.go` - 添加 `/api/portal/session/*` 路由
- `internal/app/bootstrap.go` - 传递 trusted proxy secret
- `deploy/tksea-portal/index.html` - 添加 CRM session 登录/登出
- `deploy/tksea-portal/nginx.sub.tksea.top.conf.example` - nginx 配置模板
- `.env.example` - 环境变量模板
### 2. remote43 部署步骤
#### 步骤 1: 生成共享密钥
在 remote43 上执行:
```bash
TRUSTED_PROXY_SECRET=$(openssl rand -hex 32)
echo "Generated secret: $TRUSTED_PROXY_SECRET"
# 保存此密钥,需要同时配置到 nginx 和 CRM
```
#### 步骤 2: 更新 CRM 配置
编辑 `/home/ubuntu/.env.crm`(或实际运行目录):
```bash
# 在文件末尾添加:
# Trusted Subject Proxy Configuration
SUB2API_CRM_TRUSTED_SUBJECT_HEADER=X-CRM-Authenticated-Subject
SUB2API_CRM_TRUSTED_PROXY_SECRET_HEADER=X-CRM-Trusted-Proxy
SUB2API_CRM_TRUSTED_PROXY_SECRET=<步骤1生成的64字符密钥>
```
#### 步骤 3: 更新 nginx 配置
编辑 `/etc/nginx/sites-enabled/sub.tksea.top.conf`
`server` 块内添加:
```nginx
# 从 httpOnly cookie 提取 portal subject放在 server 块内)
map $http_cookie $portal_subject {
default "";
~*crm_session=([^;]+) $1;
}
```
修改 `/portal-admin-api/` location
```nginx
location /portal-admin-api/ {
proxy_pass http://127.0.0.1:18190/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 关键:从验证过的 cookie 提取并注入 subject
proxy_set_header X-CRM-Authenticated-Subject $portal_subject;
# 受信代理密钥(必须与 CRM 配置一致)
proxy_set_header X-CRM-Trusted-Proxy "<步骤1生成的64字符密钥>";
proxy_http_version 1.1;
}
```
**注意**
- 删除原来的 `proxy_set_header X-Portal-Subject "";`
- 确保密钥替换为实际生成的 64 字符 hex 字符串
#### 步骤 4: 重启服务
```bash
# 测试 nginx 配置
sudo nginx -t
# 重载 nginx
sudo systemctl reload nginx
# 重启 CRM
sudo systemctl restart crm
# 或使用:
# pkill -f "crm" && cd /home/ubuntu && ./server &
```
#### 步骤 5: 验证
浏览器测试:
1. 访问 `https://sub.tksea.top/portal/`
2. 登录(会同时设置 CRM session cookie
3. 打开浏览器 DevTools → Application → Cookies
4. 确认看到 `crm_session` cookiehttpOnly`crm_subject` cookie
5. 尝试创建/管理用户 Key应该可以正常工作
API 测试:
```bash
# 1. 登录获取 session cookie
curl -c cookies.txt -X POST https://sub.tksea.top/portal-admin-api/api/portal/session/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com"}'
# 2. 使用 cookie 访问 user-key API
curl -b cookies.txt https://sub.tksea.top/portal-admin-api/api/keys
# 3. 创建新 key
curl -b cookies.txt -X POST https://sub.tksea.top/portal-admin-api/api/keys \
-H "Content-Type: application/json" \
-d '{"key_name":"test-key","logical_group_id":"gpt-shared"}'
```
### 3. 故障排除
#### CRM 返回 `unauthorized` / `trusted proxy authentication required`
- 检查 `.env.crm` 中的 `SUB2API_CRM_TRUSTED_PROXY_SECRET` 是否正确设置
- 检查 nginx 中的 `X-CRM-Trusted-Proxy` header 值是否一致
- 检查两个密钥是否完全匹配(无多余空格)
#### CRM 返回 `trusted subject header required`
- 检查 nginx 是否正确添加了 `map $http_cookie $portal_subject`
- 检查浏览器是否有 `crm_session` cookie登录后应该自动设置
- 检查 cookie 是否被浏览器阻止SameSite/Secure 设置)
#### Portal 前端无法登录 CRM session
- 检查浏览器 console 是否有 CORS 错误
- 检查 `/portal-admin-api/` location 是否正确配置
- 确认 CRM 服务正在监听 `127.0.0.1:18190`
## 安全配置建议
1. **密钥管理**
- 使用 `openssl rand -hex 32` 生成强密钥
- 不要在任何地方记录或提交密钥
- 考虑使用 HashiCorp Vault 或 AWS Secrets Manager
2. **HTTPS**
- 生产环境必须启用 HTTPS
- 设置 `Secure` flag 在 cookies 上
3. **Cookie 设置**
- `crm_session`: httpOnly, SameSite=Lax, Secure (HTTPS only)
- `crm_subject`: SameSite=Lax, Secure (HTTPS only)
## 回滚计划
如果需要回滚:
1. 还原 nginx 配置(删除 map 和 header 设置)
2. 还原 `.env.crm`(移除 TRUSTED\_\* 配置)
3. 重载 nginx / 重启 CRM
portal 会回退到之前的 bearer token 认证模式。
## 验证清单
- [ ] 生成并记录了 64 字符 hex secret
- [ ] 更新了 `.env.crm` 配置
- [ ] 更新了 nginx 配置
- [ ] 重载了 nginx 配置
- [ ] 重启了 CRM 服务
- [ ] 浏览器测试通过(可以看到 crm_session cookie
- [ ] API 测试通过(可以创建 user-key
- [ ] 完整链路测试通过create → chat → pause → resume → delete