P1 AIP
安全治理:角色、权限、脱敏与审计
AIP 不是"能查就都能查"——管理后台提供用户、角色、权限、敏感列脱敏、AI 护栏与双层审计的治理闭环。IT 管理员建角色、分配权限、锁定账号、配置脱敏,追查"谁在何时查了什么、AI 怎么决策的"。看完这 4 个故事,你就能搭起最小可用的权限、脱敏与审计体系。
IT 管理员
数据工程师
RBAC
敏感列脱敏
AI 护栏
双层审计
共 4 个故事
能 / 不能速览
✅ 这个主题能做
- 管理后台(/admin/*,仅 admin 角色):用户创建、更新、删除、重置密码、锁定 / 解锁
- 角色管理:创建、改名、删除,给角色分配 / 更新权限集合(FEATURE_ACCESS / COLUMN_ACCESS 等)
- 敏感列脱敏:标记 customers.email 等为敏感列,查询结果按 5 种方式脱敏(NLQ / 工具 / 工作流三处一致)
- AI 护栏:提示注入关键词检测 + 输入长度限制,策略存系统设置可运行时改
- Prompt 级 PII 脱敏:发给 LLM 的文本(text2sql / 摘要)自动脱敏,手机号 / 身份证 / 邮箱不落到模型
- 双层审计:NLQ_QUERY(谁查了什么)+ AI_DECISION(retrieve→generate→execute 决策链,/admin/ai-audit 回放)
- 审计防篡改:SHA-256 哈希链,VerifyChain 可校验全链完整性
⛔ 这个主题做不了
- 数据源列表对全部已登录用户可见,数据源级隔离未做
- NLQ 主链路不自动应用 RLS 行级过滤(RLS/CLS 在工具 / 工作流查询路径应用)
- 审计导出 / 归档 / 摘要是平台能力(AuditAdminService),AIP 未提供 REST 入口,需分页拉取
- 护栏只管输入(注入 / 长度),不做 LLM 输出内容的安全复核
- admin 不能删除自己、不能移除自己的 admin 角色(自护规则)
适用角色
本主题面向两个角色:
- IT 管理员(赵工):核心使用者,负责账号、角色、权限、脱敏、护栏与合规,是治理闭环的操盘手。
- 数据工程师:配合提供数据源与元数据信息,在权限设计与敏感列识别上给出建议。
业务分析师是被治理的对象:他们登录后用 /chat 与 /datasources,但访问 /admin/* 会被拦截(403)。
能力速览(能做什么)
用户管理(/admin/users)
创建 / 查询 / 更新 / 删除用户;重置密码(≥6 位,同时清空锁定);锁定 / 解锁;密码连续错 5 次自动锁定。
角色与权限(/admin/roles)
角色 CRUD + 权限集合整体替换(FEATURE_ACCESS / COLUMN_ACCESS / ACTION_ACCESS + resource_name);用户-角色绑定。
敏感列脱敏(/admin/security)
标记敏感列(PII/财务/健康/凭证),5 种脱敏方式(full_mask / partial_mask / hash / tokenize / nullify),命中即脱敏并写入审计。
AI 护栏(/admin/security)
提示注入关键词检测 + 输入长度限制(默认 4000 字符),策略存系统设置,可运行时调整。
安全概览(/admin/security)
GET /security/overview:敏感列数 / RLS 数 / CLS 数 / 审计总数 / AI 护栏状态 / 脱敏记录数汇总 / 最近审计。
双层审计(/admin/audit + /admin/ai-audit)
事件级:按 user_id / event_type / 时间查询;决策级:/ai-audit 按 trace_id 回放一次查询的 retrieve→generate→execute 决策链。
调整指南(怎么调整)
- 改权限粒度:角色权限用 resource_name 收敛范围(如 FEATURE_ACCESS 配到具体资源),比一刀切更符合最小授权。
- 改脱敏策略:手机号 / 邮箱用 partial_mask(保留首 3 尾 4),姓名用 hash,不需要的值用 nullify / full_mask;同表同列唯一,重复创建会报错。
- 改护栏强度:AI_GUARDRAIL_MAX_INPUT_LEN 收紧输入长度;AI_GUARDRAIL_INJECTION_KEYWORDS 增删注入关键词(JSON 数组);测试可临时关总开关。
- 改账号状态:员工离职先锁定(PUT /users/:id/lock locked=true)再逐步回收角色,最后删除;重置密码可清空锁定状态。
- 改审计范围:追查某个人的全部动作按 user_id 过滤;只看查询类事件按 event_type=NLQ_QUERY;看 AI 决策过程用 /ai-audit 的 trace_id 精确过滤。
- 治理边界:数据源级隔离未做、审计导出无 REST 入口(需分页拉取)、NLQ 主链路不应用 RLS——向业务说明这些边界。
做得好的场景
安全治理在"账号生命周期 + 角色授权 + 敏感数据脱敏 + 双层审计"这条线上体验最顺:
- 账号生命周期管理:创建、锁定、重置密码、删除全在管理后台,登录连续失败自动锁定,离职交接不再靠手工改库。
- 管理面强隔离:adminMiddleware 保证 /admin/* 只有 admin 角色可访问,业务账号拿到 403。
- 敏感数据守得住:客户邮箱等敏感列配置一次,NLQ / 工具 / 工作流三条查询路径结果全部脱敏,脱敏状态写进审计。
- 双层审计可回放:NLQ_QUERY 回答"谁查了什么",AI_DECISION 回答"AI 这次怎么决策的",合规对答有据。
限制与不足
以下是明确的边界,使用前先知道:
- 数据源级隔离未做:当前所有已登录用户都能看到 /datasources 列表;细到"角色 A 看不到数据源 B"不在 MVP。
- NLQ 主链路不应用 RLS:查询执行不自动做行级过滤,RLS/CLS 在工具(query_data)与工作流 query_data 节点应用。
- 审计导出无 REST:导出 / 归档 / 摘要是平台能力(AuditAdminService),AIP 只提供查询与 /ai-audit,大范围取证需分页拉取。
- 护栏只护输入:不做 LLM 输出内容复核;PII 脱敏对中文姓名较激进,需按业务用 PII_PATTERNS 裁剪。
- 自护规则:admin 不能删除自己、不能移除自己的 admin 角色,批量治理时需注意。
场景故事
故事 1
IT 管理员建"销售分析员"角色并分配权限给新同事
场景:角色与权限
角色:IT 管理员
耗时:约 8 分钟
- 背景
- 销售部新来了分析员小周,赵工(IT 管理员)要给他开 AIP 账号,但只想让他用智能查询查数,不能进管理后台。赵工登录 admin / admin1,进入管理后台(/admin)。
- 传统做法对比
- 以前要么给新员工开"最大权限"账号(越权风险),要么让 DBA 手工改权限表(无审计);现在角色模板 + 用户绑定两步,权限可复用、可追溯。
- 角色
- IT 管理员(admin 角色,具备管理后台全部权限)。
- 操作步骤
-
- 在"角色与权限"页创建角色 sales_viewer(POST /api/v1/roles)
- 给角色更新权限集合(PUT /api/v1/roles/:id/permissions,配置 FEATURE_ACCESS 等权限点)
- 在"用户管理"页创建用户 xiaozhou(POST /api/v1/users)
- 给 xiaozhou 分配 sales_viewer 角色(POST /api/v1/users/:id/roles)
- 系统响应
- 创建角色返回:
{
"role": { "id": 3, "role_name": "sales_viewer", "permissions": [] }
}
分配角色返回 {"assigned": true, "role_id": 3};随后小周用 xiaozhou 登录 /chat 可正常查询。
- 结果洞察
- 小周登录后能进 /chat 查数,但访问 /admin 或 /api/v1/users 等管理接口时返回 403(admin role required)——管理面与非管理面被 adminMiddleware 严格隔开。赵工还注意到:小周执行 query_data 工具需要 tool:query_data:execute 权限点,未授予会收到 403 TOOL_PERMISSION_DENIED,最小授权落实到工具级。
- 调整建议
- 权限集合用 resource_name 收敛到具体资源,避免 role 权限过大;同一类岗位复用角色模板,新同事来了只做"建用户 + 绑角色"两步。
- 动手试一试
- 登录:admin / admin1。页面路径:/admin/roles → 新建角色;/admin/users → 新建用户并分配角色。输入内容:角色 sales_viewer;用户 xiaozhou。预期结果:xiaozhou 可登录 /chat,访问 /admin/* 返回 403。
- 限制提示
- 当前权限主要作用在"管理面 vs 非管理面"与工具执行权限点,数据源列表对所有已登录用户可见;若重复分配同一角色会返回 409。
故事 2
敏感列脱敏 + AI 护栏:客户邮箱查出来是"打码"的,注入指令被拦
场景:脱敏与护栏
角色:IT 管理员 + 数据工程师
耗时:约 10 分钟
- 背景
- 赵工和张工一起做数据安全加固:先把 customers.email 标记为敏感列,让查询结果脱敏;再检查 AI 护栏是否拦得住提示注入。赵工在 /admin/security 的"敏感列"Tab 新建一条记录。
- 传统做法对比
- 以前敏感字段靠 SQL 里手动拼脱敏函数,漏一个查询入口就泄一次;现在敏感列配置一处,NLQ / 工具 / 工作流三条查询路径全部生效,脱敏状态还自动写进审计。
- 角色
- IT 管理员(配置敏感列与护栏)+ 数据工程师(确认哪些列属于 PII)。
- 操作步骤
-
- 在 /admin/security 敏感列 Tab 新建:table_name=customers、column_name=email、sensitivity_type=PII、masking_method=partial_mask(POST /api/v1/security/sensitive-columns)
- 在"AI 护栏"Tab 确认 enabled=true、max_input_len=4000,注入关键词列表保留默认 19 个中英文词
- 用普通用户登录 /chat,输入"查询所有客户的邮箱"验证脱敏
- 再输入一句包含"忽略之前的指令"的查询验证护栏拦截
- 系统响应
- 创建敏感列返回:
{
"code": 0, "message": "ok",
"data": { "id": 1, "table_name": "customers", "column_name": "email",
"sensitivity_type": "PII", "masking_method": "partial_mask",
"description": "客户邮箱", "created_at": "...", "updated_at": "..." }
}
随后 /chat 查询命中 email 列,返回值为脱敏后的 zha****mple.com;审计中该条 NLQ_QUERY 带 "data_masked": true, "masked_records": 3, "risk_level": "medium"。含注入词的输入被护栏拦截:400 输入疑似包含提示注入内容,已拒绝该请求。
- 结果洞察
- 赵工确认:脱敏在结果返回前最后一公里生效,客户邮箱 3 行全部打码(保留首 3 尾 4);护栏在 chat 入口前置拦截注入指令,业务正常查询不受影响。PII 类型(PII/FINANCIAL/HEALTH/CREDENTIAL)与脱敏方式(full_mask/partial_mask/hash/tokenize/nullify)都有枚举校验,配错会报 400。
- 调整建议
- 姓名列用 hash(SHA-256 十六进制)、金额类敏感列用 nullify 或 full_mask;护栏关键词可按业务域增删(JSON 数组存 system_settings);验证脱敏是否全链路生效,可在 /admin/security 概览看 masked_records 累计值。
- 动手试一试
- 登录:admin / admin1。页面路径:/admin/security。输入内容:新建敏感列 customers.email(partial_mask);/chat 输入"查询所有客户的邮箱"。预期结果:返回 email 为打码值(zha****mple.com 样式),审计 data_masked=true。
- 限制提示
- 脱敏只针对登记过的敏感列,未登记的列原样返回;护栏只管输入不校验 LLM 输出;PII 正则对中文姓名较激进,如需发给 LLM 的文本脱敏请用 PII_PATTERNS 按业务裁剪。
故事 3
账号治理:锁定离职员工、重置弱口令、登录失败自动锁定
场景:账号治理
角色:IT 管理员
耗时:约 6 分钟
- 背景
- 月末信息安全巡检,赵工发现两件事:一位已离职同事的账号还在用;另一位同事的密码疑似弱口令,且曾出现连续输错密码的迹象。他要在管理后台完成"锁定 + 重置密码 + 回收权限"的组合操作。
- 传统做法对比
- 以前账号回收靠通知各系统管理员手工处理,漏一个系统就留个后门;现在锁定、重置密码、移除角色都在一个管理后台完成,且密码连续错 5 次会自动锁定账号并写 ACCOUNT_LOCKOUT 审计。
- 角色
- IT 管理员(admin 角色)。
- 操作步骤
-
- 对离职账号执行 PUT /users/:id/lock,body {"locked": true} 立即锁定
- 查看该用户角色列表(GET /users/:id/roles),逐个移除角色(DELETE /users/:id/roles/:roleId)
- 对弱口令账号执行 POST /users/:id/password 重置(密码至少 6 位)
- 确认无需保留后 DELETE /users/:id 删除账号
- 系统响应
- 锁定返回:
{ "user": { "id": "a1c2...", "username": "zhangwei", "locked": true } }
重置密码返回 {"reset": true};移除角色返回 {"removed": true};被锁定账号再登录返回 401。弱口令账号若连续输错 5 次,登录接口会自动锁定并审计 ACCOUNT_LOCKOUT。
- 结果洞察
- 赵工用离职账号试着登录,直接 401——锁定立即生效,不等密码过期。他还验证了重置密码会把锁定状态一并清空(resetPassword 会解锁),所以流程上"先锁定、再重置、最后删号"的顺序很关键;登录失败计数与锁定状态持久化在 users 表,重启不丢。
- 调整建议
- 按"锁定 → 移除角色 → 重置密码 → 删除"的顺序治理离职账号;给 admin 账号设强密码并定期轮换;locked 字段必填(缺字段返回 400),避免误把"解锁"当默认。
- 动手试一试
- 登录:admin / admin1。页面路径:/admin/users。输入内容:PUT /users/:id/lock body={"locked": true};POST /users/:id/password body={"password":"newpass99"}。预期结果:锁定后该账号登录 401;重置后新密码可登录、旧密码 401;连错 5 次自动锁定。
- 限制提示
- admin 角色有自护规则:不能删除自己、不能移除自己的 admin 角色;账号锁定不强制使已签发的 Token 立即失效,注意安全边界。
故事 4
合规审查准备:双层审计回放 + 安全概览取证
场景:合规审查
角色:IT 管理员 + 数据工程师
耗时:约 15 分钟
- 背景
- 下季度要做一次数据安全合规审查,赵工和张工需要自查:权限是否最小化、敏感列是否覆盖、查询行为是否可回溯、AI 决策过程是否可解释。赵工打开管理后台,张工对照数据源清单核对敏感字段。
- 传统做法对比
- 以前合规自查靠人肉盘点账号和权限,Excel 表格满天飞,AI 的"黑盒决策"更是无从解释;现在权限集中管理、敏感列统一脱敏、审计哈希链防篡改、决策链可回放,审查人看到的是硬证据。
- 角色
- IT 管理员(权限、脱敏、审计)+ 数据工程师(数据源与敏感字段视角)。
- 操作步骤
-
- 列出全部用户与角色(GET /api/v1/users、GET /api/v1/roles),逐一核对岗位必要性
- 检查敏感列清单(GET /api/v1/security/sensitive-columns)是否覆盖 PII / 财务字段
- 按事件类型与时间段拉审计日志(GET /audit/logs)作为"查询行为可回溯"证据
- 对重点查询按 trace_id 走 /admin/ai-audit(GET /ai-audit?trace_id=)回放决策链
- 打开 /admin/security 概览(GET /security/overview)汇总敏感列数 / RLS / CLS / 审计总数 / 护栏状态 / 脱敏记录数
- 系统响应
- 概览返回:
{
"sensitive_columns": 3, "rls_policies": 2, "cls_policies": 1,
"audit_logs_total": 1520, "ai_guardrail_enabled": true,
"masked_records": 42,
"recent_audit_events": [ ... ]
}
/ai-audit 按某次查询的 trace_id 返回三条 AI_DECISION 记录:retrieve(注入的上下文与通道)、generate(生成的 SQL 与方言)、execute(执行行数与脱敏标记),"AI 怎么决策的"一目了然。
- 结果洞察
- 审查结论:管理面由 admin 角色独占(adminMiddleware 强隔离);敏感列三条查询路径全部脱敏且带审计标记;NLQ_QUERY 全量落审计(含 data_masked / masked_records / risk_level);AI_DECISION 决策链可回放。赵工把按 user_id 与时间段的记录、脱敏累计数、决策链截图作为证据,比"Excel 截图"硬得多。
- 调整建议
- 把"新账号默认最小权限、季度复查角色清单、敏感列季度盘点、离职 24 小时内锁定"固化为流程;大范围取证用 /audit/logs 分页拉取(AIP 无导出 REST);关注后续版本补齐审计导出入口与数据源级隔离。
- 动手试一试
- 登录:admin / admin1。页面路径:/admin/audit、/admin/ai-audit、/admin/security。输入内容:GET /api/v1/security/overview;GET /api/v1/ai-audit?trace_id=<某次查询的决策链>。预期结果:概览计数正确;决策链返回 retrieve→generate→execute 三条 AI_DECISION。
- 限制提示
- 审计导出 / 归档 / 摘要是平台能力(AuditAdminService),AIP 未注册 REST 端点,大范围取证需分页拉取;NLQ 主链路不应用 RLS 行级过滤(RLS/CLS 在工具 / 工作流路径),向审查人如实说明这一边界。
常见问题
管理后台谁都能进吗?
不能。所有 /api/v1/users、roles、permissions、settings、audit/logs、ai-audit 都挂在 adminMiddleware 之下,只有 admin 角色可访问;普通业务账号访问返回 403(admin role required),未登录访问返回 401。
敏感列脱敏在哪配?脱敏方式有什么区别?
在 /admin/security 的"敏感列"Tab 配置(GET/POST /api/v1/security/sensitive-columns)。脱敏方式:full_mask 全打码为 ****、partial_mask 保留首 3 尾 4、hash 输出 SHA-256 十六进制、tokenize 替换为 ***、nullify 置 NULL。配置后 NLQ / 工具 / 工作流三条查询路径全部生效。
AI 护栏具体拦什么?
拦两件事:输入长度超限(默认 4000 字符)与提示注入关键词命中(默认 19 个中英文词,如"忽略之前的指令")。命中返回 400。策略在 /admin/security 可改,存 system_settings。
NLQ_QUERY 和 AI_DECISION 有什么区别?
NLQ_QUERY 是事件级审计(谁在何时查了什么、SQL 是什么、返回几行、有没有脱敏);AI_DECISION 是决策级审计(这次查询的 retrieve→generate→execute 三步决策链,按 trace_id 关联),在 /admin/ai-audit 可回放。两者是补充关系,都写入 AIP 独立审计表 aip_audit_log(按产品拆表,AIP 独立 SHA-256 哈希链)。
审计日志能导出吗?
导出 / 归档 / 摘要是平台能力(AuditAdminService 提供 CSV/JSON 导出与归档),但 AIP 当前未注册对应 REST 端点,需要留档请用 /audit/logs 分页拉取自行归档。审计日志带 SHA-256 哈希链,可校验防篡改。
主题小结
一句话:安全治理 = 账号生命周期(建 / 锁 / 重置 / 删)+ 角色授权(最小化)+ 敏感列脱敏 + AI 护栏 + 双层审计(NLQ_QUERY + AI_DECISION)。管理面与业务面被 admin 强隔离,敏感数据三处查询路径一致脱敏,AI 决策链可回放。记住边界:数据源级隔离与审计导出 REST 不在 MVP,NLQ 主链路不应用 RLS。