[English](../en/identity-and-security.md) | 简体中文 # 身份、权限与安全 这篇讲登录方式、角色和权限、遮罩对谁是边界、代码沙箱的隔离程度,以及其他安全边界。给管理员和运维看。 ## 登录方式 有三种登录方式。环境变量 `AGENTLAB_AUTH_MODE`(`off` / `local` / `oidc`)优先于「设置 → 身份」。 - **off**(默认):`X-Actor` 自报署名,所有人等同管理员,应用首页上写明这一点。同一网络里打得开页面的人都能用全部功能:跑工作流、花你配的模型额度、读数据源、执行沙箱代码;审批和发起记的是各自填的署名,未经核实。只在信得过的网络里这样用;`dev.sh --host`、`prod.sh --host` 会监听所有网卡。 - **local**:用户名 + 密码(`hashlib.scrypt`)。从未开启过登录、在设置里切过来时,必须在同一次保存里建出第一个管理员。环境变量直接指定 `local` 的新部署,在登录页建第一个管理员(只在还没有管理员时可用)。 - **oidc**:通用 OIDC,授权码 + PKCE。飞书、企业微信这类非标准协议暂不支持。要配身份提供方地址、客户端标识和密钥,并至少配一个管理员映射(管理员用户名或管理员组)。每次登录按映射重算角色,`groups` 声明同步成只读的组。回调地址是 `<对外地址>/api/auth/oidc/callback`;在反向代理后面时设 `AGENTLAB_PUBLIC_URL`(见[配置](configuration.md#对外访问地址))。 ### 会话 - 会话放在 HttpOnly、SameSite=Lax 的 cookie 里,库里只存 token 的哈希。 - 闲置 12 小时、最长 7 天过期(`AGENTLAB_AUTH_SESSION_IDLE_HOURS`、`AGENTLAB_AUTH_SESSION_MAX_DAYS`)。 - cookie 是否带 Secure,按请求是不是 https 决定;`AGENTLAB_AUTH_COOKIE_SECURE` 可以强制。 - 开了登录后,非 GET 请求必须带 `X-AgentLab-Request` 头;带了 `Origin` 的,必须是本站或 `AGENTLAB_CORS_ORIGINS` 里的地址。 - 登录连续失败后,等待时间逐次增加。 ### 忘了密码 忘了密码、单点登录配错时,在服务器上执行: ```bash cd backend && python -m app.auth reset-admin --username admin # 不给 --password 时随机生成并打印一次 ``` ## 角色与授权 角色:管理员 ⊇ 搭建者 ⊇ 使用者。 - 应用另有三档授权:使用、查看全部实例、管理。授给使用者的「管理」按「查看全部实例」算。 - 搭建者绑定岗位、授权时,从只读的人员名录里选(`GET /api/directory`:用户名、显示名、是否停用、组名)。名录里没有的、已停用的名字不让添加。 - 单点登录的人和组,第一次登录后才进名录;没进名录的,要确认后才添加。 - 开了登录后,发布、发起、数据导入的确认一律记登录的人,界面上不再有署名框。 ## 权限表 | 能做的事 | 管理员 | 搭建者 | 使用者 | |---|---|---|---| | 问数据、助手 | ✓ | ✓ | 默认不能,管理员可在「设置 → 身份」开启 | | 编排、探索运行、以已发布级发布、数据源、数据目录、定时任务、知识库、自定义工具 | ✓ | ✓ | ✗ | | 以受管级发布、把受管工作流降为已发布、版本退役 | ✓ | ✗ | ✗ | | 记录页、运行的实时推送 | ✓(别人的个人应用除外) | ✓(别人的个人应用除外) | 只限自己的问数据运行 | | MCP 的 stdio、端点和凭据、能力治理、模型接入 | ✓ | 只读 | ✗ | | 应用:使用 / 查看全部实例 / 搭建发布 | ✓ | 能用能看;管理要创建者或有管理授权 | 按授权使用、查看 | | 共享蓝图:读、改、试运行、出发布单 | ✓ | 自己建的、自己管理的应用出自的 | ✗ | | 建个人应用、刷新、提交审核 | ✓ | ✓ | 默认不能,管理员可在「设置 → 偏好设置」的「应用」一节开启 | | 别人的个人应用:名称、拥有者、创建和更新时间,归档 | ✓ | ✗ | ✗ | | 别人的个人应用:页面、刷新和试运行的运行、证据、附件、蓝图 | ✗ | ✗ | ✗ | | 处理派给自己的待办、核实动作 | ✓ | ✓ | ✓ | | 用户、组、登录方式、审计 | ✓ | ✗ | ✗ | ## 使用者的问数据 管理员开启后,使用者的问数据只能发起探索运行: - 图里只许这些节点:输入、模型调用、Agent、报告撰写、成果、知识检索、数据整形、条件分支、口径卡、合并查询、调用工具。 - Agent 和调用工具节点都只能用数据源查询和只读的内置工具。 - 查询结果在工具边界先遮罩;数据源一律只读(调用工具节点和 Agent 走同一道);能力治理里改成写入的工具也不执行。 - 记忆范围固定为自己的。 - 对话按建立人隔离。 个人应用的图用同一份白名单(见[个人应用](apps.md#个人应用))。 ## 哪些角色看得到原值 数据源设置的遮罩列: - **对开了登录的使用者是边界**:查询快照按派生遮罩处理后才给;工具快照的原文、运行事件里的结果预览一律不给;工件按白名单给。 - **对搭建者、管理员,以及未开启登录时的所有人,遮罩只减少暴露**:完整快照仍能按工件 id 取到。 开了登录时,使用者能读原始运行记录、事件和实时流的,只有自己的问数据运行。别的运行(包括替他发起的口径对账)经应用页和证据接口读,展示的 SQL 里写着的遮罩值换成「已遮罩」。 ## 审计 写进审计的: - 管理类操作:登录方式、用户和角色、组、端点、能力治理、应用发布、版本退役。 - 访问密钥的建、撤销、轮换、开关;每次用密钥的请求记一条,保留 90 天(见[访问密钥](apps.md#访问密钥))。 - 分享链接的建和撤销(打开只计次数)。 - 报告导出和可验证报告下载(`report.exported`)。 ## 代码沙箱 代码节点和工具里的 Python 在沙箱里执行。沙箱分两档: - **轻量档**:操作系统自带的访问控制。macOS 用 Seatbelt(`sandbox-exec`),Linux 用 bubblewrap。冷启动约 25ms,不用额外安装。 - **重量档**:microVM(libkrun + Hypervisor.framework),启动带独立内核的虚拟机。 两档共同保证三项约束:**默认断网**、**家目录不可读**、**只有工作区可写**。 - Seatbelt 的策略由内核强制,对子进程也生效:沙箱里用 `subprocess` 启动的 `cat` 读家目录,同样返回 `Operation not permitted`。 - 解释器刻意用 `sys.base_prefix` 下的干净 Python,不用项目环境,所以沙箱代码 import 不了 FastAPI、SQLAlchemy 和任何处理凭据的模块。 - bubblewrap 沙箱不继承后端的环境变量。 **Seatbelt 的局限**:它提供访问控制,不是虚拟化。 - 进程表共享,看得到宿主机的进程列表。 - 代码以当前用户身份运行,不像容器那样降权到 nobody。 - **macOS 不强制 `RLIMIT_AS`,内存用量限不住**:实测设了 256MB,仍能分配 900MB。CPU 时间、单文件大小、墙钟超时三项有效。 **microVM 补齐的正是内存这一项**。本机实测:宿主是 Darwin 27.0.0,VM 里是 Linux 6.12.99(libkrunfw 编译),PID 1 是 `init.krun`,VM 里没有 `/Users`,`free` 只显示 512MB。申请 900MB 会被内核的 OOM killer 终止,VM 本身存活——`RLIMIT_AS` 在 macOS 上形同虚设的问题,在这里不是被修好了,而是结构上不存在。两台 VM 之间也互相看不见。 microVM 的代价:运行时约 50MB;OCI 镜像**第一次拉取实测 54.5 秒**;缓存后热启动 0.19 秒,VM 里执行 7–30ms。成本集中在第一次,所以 auto 模式在镜像没缓存时优先用 Seatbelt,免得等一分钟(显式指定 strict 不受此限)。 都不可用时降级到 `local`,**不含任何访问控制**,界面标红。Docker 部署在没有 KVM 的机器上,隔离边界只有容器本身(见[部署](deployment.md#离线包里的代码沙箱))。怎么选后端、启用 microVM,见[配置](configuration.md#沙箱后端)。 ### 网络隔离不完整 > **这一项必须放在前面说清楚。** > `network=false` 时,HTTP/HTTPS 和域名解析都被切断,但 **UDP/53 拦不住**:实测手写的 DNS 包仍能拿到真实响应。`default_egress=DENY`、`Rule.deny_dns()`、显式 deny UDP、`max_connections=0` 都试过,UDP 通道始终堵不上(`deny_dns` 生成的规则只作用于宿主,DNS 出口在 microsandbox 的网络栈里硬编码放行)。 > 也就是说,**DNS 隧道这条外泄通道始终开着**。这层隔离足以防「代码意外联网装依赖」,不足以防「恶意代码窃取数据」。所以设置页把网络这一项标成黄色的「部分生效」,不标绿色——拦了一半却显示全绿,比显示全红更危险。真正的外泄防护要在网络层做。 ## 安全边界 - **表达式**:分支条件等表达式用 AST 白名单求值器,不用 `eval`。 - **工具网络**:HTTP 工具逐 IP 检查、拦内网和元数据地址、不跟随重定向;内网只对登记了「允许访问内网」的端点开放;文件工具不出工作区(见[工具](tools.md#网络和凭据))。 - **数据库**:SQL 守卫、连接层只读、Oracle 要配只读账号(见[数据源](data-sources.md#只读保证))。 - **人工审批**:只认明确的批准(`true` / 同意 / approve),看不懂的回复一律按拒绝处理。MCP 与自定义工具默认每次调用都等审批(见[工具](tools.md#审批档位))。 - **密钥**:模型的 API Key 经 Fernet 加密落库,只向前端返回掩码;端点的认证头、自定义工具的请求头、MCP 的环境变量与请求头同样加密,只回掩码。 - **开了登录**:会话 cookie 在库里只存 token 的哈希;非 GET 请求核对来源标记头和 Origin;使用者只能读有授权的运行,看到的查询结果一律遮罩。 - **写外部系统**:必须经「调用工具」节点;先留生效记录再发送;确认卡上的内容哈希在发送前重算比对;结果未知永不自动重发(见[应用](apps.md#写外部系统))。 - **安全响应头**:`nosniff`、`Referrer-Policy`,以及 `frame-ancestors`(缺省 `'self'`;`AGENTLAB_FRAME_ANCESTORS` 列出允许嵌整站的同站门户;只有 `'self'` 时另加 `X-Frame-Options: SAMEORIGIN`)。严格的 `script-src` 目前只发 `Content-Security-Policy-Report-Only`,观察一个版本没有误报再强制。HSTS 交给反向代理。 - **系统代为发起的运行**:评测、口径对账、口径召回的证据照常可查,但不进使用统计,记录页默认不列。