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
This commit is contained in:
@@ -7,8 +7,10 @@ ARTIFACT_DIR="${ARTIFACT_DIR:-$ROOT_DIR/artifacts/user-key-self-service/${TS}}"
|
||||
CRM_BASE="${CRM_BASE:-https://sub.tksea.top/portal-admin-api}"
|
||||
USER_CHAT_BASE="${USER_CHAT_BASE:-}"
|
||||
CHAT_MODEL="${CHAT_MODEL:-gpt-5.4}"
|
||||
USER_SUBJECT_ID="${USER_SUBJECT_ID:-}"
|
||||
USER_AUTH_TOKEN="${USER_AUTH_TOKEN:-}"
|
||||
USER_TRUSTED_SUBJECT_ID="${USER_TRUSTED_SUBJECT_ID:-}"
|
||||
USER_TRUSTED_SUBJECT_HEADER="${USER_TRUSTED_SUBJECT_HEADER:-X-CRM-Authenticated-Subject}"
|
||||
USER_TRUSTED_PROXY_SECRET_HEADER="${USER_TRUSTED_PROXY_SECRET_HEADER:-X-CRM-Trusted-Proxy}"
|
||||
USER_TRUSTED_PROXY_SECRET="${USER_TRUSTED_PROXY_SECRET:-}"
|
||||
|
||||
mkdir -p "$ARTIFACT_DIR"
|
||||
|
||||
@@ -31,9 +33,11 @@ Required env for --run:
|
||||
USER_CHAT_BASE 最终 user-key 调用入口 base, e.g. https://sub.tksea.top
|
||||
CHAT_MODEL chat 模型名,default: gpt-5.4
|
||||
|
||||
Authentication for /api/keys endpoints (choose one):
|
||||
USER_SUBJECT_ID 通过 X-Portal-Subject 头注入 subject(联合部署/受信入口)
|
||||
USER_AUTH_TOKEN 通过 Authorization: Bearer <token> 走用户链路
|
||||
Authentication for /api/keys endpoints:
|
||||
USER_TRUSTED_SUBJECT_ID 受信代理注入的 subject 值
|
||||
USER_TRUSTED_SUBJECT_HEADER subject 头名,default: X-CRM-Authenticated-Subject
|
||||
USER_TRUSTED_PROXY_SECRET_HEADER 代理密钥头名,default: X-CRM-Trusted-Proxy
|
||||
USER_TRUSTED_PROXY_SECRET 代理与 CRM 共享的密钥
|
||||
|
||||
Artifacts:
|
||||
artifacts/user-key-self-service/<timestamp>/
|
||||
@@ -48,12 +52,10 @@ EOF
|
||||
}
|
||||
|
||||
build_auth_args() {
|
||||
if [[ -n "$USER_AUTH_TOKEN" ]]; then
|
||||
printf '%s\n' "-H" "Authorization: Bearer $USER_AUTH_TOKEN"
|
||||
return 0
|
||||
fi
|
||||
if [[ -n "$USER_SUBJECT_ID" ]]; then
|
||||
printf '%s\n' "-H" "X-Portal-Subject: $USER_SUBJECT_ID"
|
||||
if [[ -n "$USER_TRUSTED_SUBJECT_ID" && -n "$USER_TRUSTED_PROXY_SECRET" ]]; then
|
||||
printf '%s\n' \
|
||||
"-H" "${USER_TRUSTED_SUBJECT_HEADER}: ${USER_TRUSTED_SUBJECT_ID}" \
|
||||
"-H" "${USER_TRUSTED_PROXY_SECRET_HEADER}: ${USER_TRUSTED_PROXY_SECRET}"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
@@ -133,8 +135,8 @@ cmd_env_check() {
|
||||
CRM_HEALTH="$crm_health" \
|
||||
USER_CHAT_BASE_PY="$USER_CHAT_BASE" \
|
||||
CHAT_HEALTH="$chat_health" \
|
||||
HAS_SUBJECT_ID="$USER_SUBJECT_ID" \
|
||||
HAS_AUTH_TOKEN="$USER_AUTH_TOKEN" \
|
||||
HAS_TRUSTED_SUBJECT_ID="$USER_TRUSTED_SUBJECT_ID" \
|
||||
HAS_TRUSTED_PROXY_SECRET="$USER_TRUSTED_PROXY_SECRET" \
|
||||
python3 - <<'PY'
|
||||
import json, os
|
||||
out = {
|
||||
@@ -142,8 +144,8 @@ out = {
|
||||
"crm_health": os.environ["CRM_HEALTH"],
|
||||
"user_chat_base": os.environ["USER_CHAT_BASE_PY"],
|
||||
"user_chat_health": os.environ["CHAT_HEALTH"],
|
||||
"has_user_subject_id": bool(os.environ["HAS_SUBJECT_ID"]),
|
||||
"has_user_auth_token": bool(os.environ["HAS_AUTH_TOKEN"]),
|
||||
"has_trusted_subject_id": bool(os.environ["HAS_TRUSTED_SUBJECT_ID"]),
|
||||
"has_trusted_proxy_secret": bool(os.environ["HAS_TRUSTED_PROXY_SECRET"]),
|
||||
}
|
||||
with open(os.environ["OUT_PATH"], "w", encoding="utf-8") as fh:
|
||||
json.dump(out, fh, ensure_ascii=False, indent=2)
|
||||
@@ -157,7 +159,7 @@ cmd_run() {
|
||||
cmd_env_check
|
||||
[[ -n "$USER_CHAT_BASE" ]] || die "USER_CHAT_BASE is required for --run"
|
||||
if ! build_auth_args >/dev/null; then
|
||||
die "set USER_SUBJECT_ID or USER_AUTH_TOKEN for /api/keys authentication"
|
||||
die "set USER_TRUSTED_SUBJECT_ID and USER_TRUSTED_PROXY_SECRET for /api/keys authentication"
|
||||
fi
|
||||
|
||||
local create_payload create_code key_id plaintext_key masked_preview create_body
|
||||
|
||||
Reference in New Issue
Block a user