主题
11 - 管控收敛:实例内操作预置与屏蔽
一句话:原生 Console 的全开放被拆成四层,拉起时注入权威预置、密钥只走 Vault 到 secrets 卷、入口在网关按角色收口、员工只在语言主题与订阅内技能上自选;预置的权威靠定时巡检把员工改动覆盖回来实现,代价是“修改被静默还原”只能靠审计解释,而隐藏管理菜单只是体验优化,真正的底线是后端对管理端点的拒绝。
一、设计目标
QwenPaw 原生 Console 是"单机自用"形态——完整的设置页面、模型管理、密钥配置、Agent 配置、备份恢复等功能全部开放给用户。在企业数字分身场景下,这种"全开放"模式不可接受:
- 员工不应能修改模型配置(平台预置的才是正确的)
- 员工不应能看到任何密钥/凭证明文
- 管理端点不应被员工角色访问
- 但同时要保留员工的个人化空间(语言、主题、会话使用)
本章定义实例内操作的四层收敛模型:平台预置 → 敏感屏蔽 → 入口收口 → 员工自选。
二、四层收敛模型
三、平台预置详细说明
3.1 预置清单
| 预置项 | 注入时机 | 注入方式 | 员工可改 | 覆盖策略 |
|---|---|---|---|---|
| 模型 Provider / base_url | 实例创建(initContainer) | 写入 secrets 卷 active_model.json | 否 | 预置为权威,覆盖员工修改 |
| 默认模型 | 实例创建 | 写入 secrets 卷 | 否 | 同上 |
| 默认 Agent 角色 | 实例创建 | 写入 config.json agents 段 | 否 | 同上 |
| 默认技能包 | 实例创建(post-init) | 控制面调用 /api/skills/pool/import | 否(订阅范围内可选) | 预置为权威 |
| 通道配置 | 实例创建 | 环境变量 QWENPAW_ENABLED_CHANNELS=console | 否 | 镜像级固化 |
| 安全策略 | 实例创建 | 写入 config.json security 段 | 否 | 预置为权威 |
| ACP 执行体 | 镜像构建 | 镜像内置二进制 + config 默认启用 | 否 | 镜像级固化 |
3.2 预置覆盖机制
平台预置是权威配置。控制面在以下时机执行预置覆盖:
| 时机 | 操作 | 说明 |
|---|---|---|
| 实例创建 | 全量预置 | initContainer + post-init 写入所有预置项 |
| 实例恢复 | 全量预置 | 恢复后重新校验预置项(防止备份数据覆盖) |
| 定时巡检 | 增量校验 | 每日检查预置项是否被篡改,发现则修复 |
| 镜像升级 | 全量预置 | 升级后重新写入预置项 |
预置 vs 个人偏好的区分:
config.json 字段分为两类:
平台管控段(预置为权威,员工修改会被覆盖):
- channels
- security
- acp
- providers(在 secrets 卷)
员工可改段(保留员工个人偏好):
- settings.json(语言、主题)
- agents.{id}.preferences(对话偏好)
- skills.{id}.enabled(技能启用状态,受订阅约束)四、敏感屏蔽详细说明
4.1 屏蔽清单
| 敏感信息 | 存储位置 | 流动路径 | 员工可见 |
|---|---|---|---|
| 模型 API Key | Vault + K8s Secret | Vault → K8s Secret → secrets 卷 → 实例进程读取 | 否 |
| RT Token | Vault | Vault → Redis 缓存 → 网关注入 header → 实例校验 | 否 |
| 实例账密 | Vault | Vault → K8s Secret → 实例进程(仅内部校验用) | 否 |
| MCP 凭证 | Vault | Vault → 控制面 → 注入请求 header → 实例转发 | 否 |
| IM 凭证 | Vault | Vault → 渠道聚合器运行时 → IM API 调用 | 否 |
| 数据库密码 | K8s Secret | K8s Secret → 控制面/聚合器环境变量 | 否 |
| Fernet 加密密钥 | K8s Secret | K8s Secret → Vault 初始化 | 否 |
4.2 屏蔽实现
密钥零暴露原则:所有密钥/凭证只在"Vault/K8s Secret → 实例 secrets 卷/进程内存"之间流动,不经过浏览器、不经过员工、不进入日志、不进入备份。
具体实现:
| 措施 | 说明 |
|---|---|
| secrets 卷不挂载到日志路径 | qwenpaw.log 在 data 卷,secrets 卷独立 |
| 备份排除 secrets | include_secrets=false |
| 日志脱敏 | 控制面和实例的日志采集器自动过滤敏感字段 |
| API 响应脱敏 | 所有 API 响应中不返回密钥/凭证相关字段 |
| Console UI 隐藏 | 管理页面(模型/密钥/系统设置)不对员工角色展示 |
五、入口收口详细说明
5.1 网关角色拦截
网关(ext_authz 服务)按角色拦截请求:
| 角色 | 可达端点 | 不可达端点 |
|---|---|---|
employee | /api/console/chat、/api/healthz、/api/agents/*/memory、/api/skills/*/enable | /api/providers、/api/settings/*、/api/backup、/api/admin/*、/api/mcp、/api/skills/hub |
admin | 全部端点 | — |
system | 仅控制面 RT 可达 | — |
后端底线:前端 UI 隐藏管理菜单只是改善体验,真正的权限控制在网关。即使员工绕过 UI 直接调用管理 API,网关也会按角色拦截。
5.2 Console UI 定制
QwenPaw Console 前端通过插件机制定制菜单:
员工视角看到的菜单:
├── 对话(主界面)
├── 会话列表
├── 技能管理(启用/禁用已安装的 Skill)
├── 个人偏好(语言/主题)
└── 我的能力(查看订阅的技能/模型/配额)
管理员额外看到:
├── 模型管理
├── MCP 管理
├── 备份恢复
├── 系统设置
└── 审计日志5.3 管理端点保护
实例的管理端点(/api/providers、/api/settings/*、/api/backup 等)仅接受携带有效 RT 的请求。由于 RT 只由网关/控制面持有,员工无法直接调用管理端点。
六、员工自选空间
6.1 可选配置项
| 配置项 | 存储位置 | 说明 |
|---|---|---|
| 界面语言 | settings.json | 中文/英文/日文等 |
| 界面主题 | settings.json | 亮色/暗色 |
| 对话偏好 | agents.{id}.preferences | 回复风格、详细程度 |
| 技能启用 | skills.{id}.enabled | 在订阅范围内选择启用哪些 Skill |
| 会话管理 | 实例内部 | 创建/删除/归档会话 |
6.2 自选与预置的边界
员工修改了语言为英文 → settings.json 更新 → 保留(不覆盖)
员工修改了默认模型 → config.json providers 段更新
→ 下次巡检发现与预置不符 → 覆盖回预置值 → 记录审计
员工禁用了某个 Skill → skills.{id}.enabled = false → 保留(在订阅范围内)
员工尝试安装未订阅的 Skill → 控制面校验订阅权限 → 拒绝七、审计与合规
7.1 操作审计
| 操作类型 | 审计内容 | 保留时长 |
|---|---|---|
| 预置覆盖 | 谁触发、覆盖了什么、原值/新值 | 180 天 |
| 管理端点访问 | 谁、什么时间、什么端点、结果 | 180 天 |
| 员工自选修改 | 谁、修改了什么、原值/新值 | 90 天 |
| 密钥轮换 | 轮换时间、操作人、影响实例 | 永久 |
7.2 合规要求
| 要求 | 实现 |
|---|---|
| 数据最小化 | 只收集业务必需的审计数据 |
| 目的限制 | 审计数据仅用于安全合规,不用于员工绩效评估 |
| 透明性 | 员工可查看自己的审计记录(GET /my/audit) |
| 保留期限 | 审计数据按类型设定保留期限,到期自动清理 |
| 访问控制 | 审计数据仅安全管理员可查 |