# AI 代理的 SaaS 管理访问：用受限操作替代广泛令牌

AI 代理可以处理 SaaS 管理工作，不必携带全能管理员令牌。安全的设计更窄，也更需要精心规划：把每项允许的变更描述成一个操作，将它绑定到一个租户和一小组输入，把凭据放在模型之外，并在后果值得由人判断时要求人工决策。

广泛令牌在设置阶段看起来很高效，因为它减少了阻力。但它也会把每条提示词、每份导入文档、每个连接器响应和每次模型错误，都变成潜在的管理员请求。我见过团队把这种访问称为“临时权限”，几个月后才发现，他们那段实用的小自动化已经通过一份被遗忘的凭据掌握了用户、发票、角色分配和工作区配置。

通常的最小权限建议没有错，但还不完整。仅靠 scope，很少能回答代理是否应该删除某个用户、修改某个群组或更改订阅。管理员需要与工作相匹配的边界，还需要足够的证据，以便事后重建每一次请求。

## 广泛的管理员令牌会把日常工作变成事故响应

一枚管理员令牌赋予代理的权限，几乎总是超过你交给它的任何一项任务。大多数 SaaS 管理工作可以分成四种不同的风险类别：管理个人账户、更改群组成员关系、读取或影响资金，以及修改整个工作区。把这些能力放进同一套权限，日常支持工作就可能找到通往所有权转移或账户删除的出口。

考虑这样一个请求：“移除本周结束合作的承包商。”代理需要一份可靠的已批准身份列表、一个目标工作区，以及暂停或取消配置这些身份的权限。它不需要创建新工作区、轮换域设置、修改发票，也不需要给自己授予管理员角色。然而，管理员 API 令牌通常会允许其中许多调用，甚至全部调用。

问题并不只在模型恶意或出错时才出现。当代理读到姓名含糊的支持工单、收到某个单元格里嵌有恶意指令的电子表格，或在出错后向错误租户重试请求时，问题就已经开始了。宽泛令牌让每一种失败都拥有超出任务实际需要的权限。

不要把令牌和操作混为一谈。令牌回答的是：“这个调用方可能访问哪些 API 路径？”操作回答的是：“这次运行究竟可以针对哪个对象、使用哪些输入，请求什么具体变更？”这个区别决定了你的控制平面能否在 SaaS 供应商看到请求之前拒绝不安全的操作。

常见的建议是创建一个拥有管理员角色的服务账户。这个建议很有吸引力，因为供应商的设置指南让它很容易，内部自动化也能快速取得成果。但对代理来说，它仍然是错误的做法。服务账户原本是为确定性程序设计的，管理员通常可以控制其源代码、输入和调用路径。代理的下一次请求却来自不断变化的上下文。应当缩小它可能造成的影响范围。

## 从真实的管理动词清单开始

访问清单应该列出操作，而不是产品或职位名称。“代理管理我们的协作套件”没有任何实际用处。“代理暂停已获批离职记录中列出的用户”则给出了工程师可以实现、管理员可以审查的内容。

收集近期工单、运行手册和审计记录，然后把每项重复任务还原成一个动词、一个对象和一个后果。不要按供应商菜单上的标签分组。SaaS 控制台常常把互不相关的能力放在同一个 Administrator 角色下，因为这适合人工操作员，不适合自动化调用方。

一个可行的初始清单可以包括：

- 根据不可变用户 ID 读取用户资料。
- 在存在指定审批记录后暂停用户。
- 将用户添加到一个已批准的群组。
- 导出指定会计期间的发票。
- 读取固定允许列表中的工作区设置。

也要写下人们悄悄假定以后会需要的操作。“更新任意工作区设置”不是一个操作。应当把它拆成会话时长、允许的域、外部共享或数据保留等具体设置。每项设置都有不同的失败模式，也有不同的审批人。

只要供应商提供不可变 ID，就在操作契约中使用它们。电子邮件地址会变化，显示名称可能重复。接受“Alex Kim”并选择第一个匹配项的请求，等于在等待一次薪资组织调整引发事故。如果有帮助，可以让代理搜索并展示候选对象，但在执行任何变更前必须要求唯一 ID。

这份清单会揭示一个令人不舒服的事实：有些自动化请求还没准备好交给代理。如果没人能说清谁可以被移除、哪些群组可以变更，或事实来源在哪里，问题就是治理，而不是技术。AI 代理不会修复治理缺口，只会以机器速度把缺失的决策暴露出来。

## 操作契约必须限制目标和载荷

操作目录不能只定义一个易懂的名称和一个 API 端点。它还必须限制目标、可接受字段、权威来源，以及返回给代理的响应。否则，一个看似范围很窄的包装器，实际上只是把任意 JSON 转发给强大的管理员 API。

下面的例子描述了一个暂停用户的操作。它有意保持精简。生产实现可以使用模式校验器，但这些约束必须存在于某个代理无法在运行过程中自行改写的位置。

```json
{
  "name": "suspend_user",
  "tenant": "acme-workspace",
  "method": "POST",
  "path_template": "/v1/users/{user_id}/suspend",
  "inputs": {
    "user_id": {"type": "string", "pattern": "^usr_[A-Za-z0-9]+$"},
    "approval_ref": {"type": "string", "pattern": "^OFF-[0-9]+$"},
    "reason": {"type": "string", "max_length": 240}
  },
  "forbidden_inputs": ["role", "owner", "tenant_id", "credential"],
  "requires_approval": true
}
```

`forbidden_inputs` 这一行可以阻止一种常见的包装器失效方式。有人先创建了一个安全端点，随后为了应对未来需求，又加入一个通用的 `options` 对象。这个对象很快就会变成 `is_admin`、`transfer_ownership` 或目标租户等字段的隧道。拒绝未知字段。未来的需求应当对应新的操作，并经过审查。

应当在操作定义中绑定租户，不要接受代理传入的租户。如果你运营多个工作区，就创建独立的操作条目，并让审批人选择目标。请求载荷中包含 `tenant_id` 很方便，但代理可能会把一个客户环境中的引用复制到另一个环境。

响应同样重要。返回用户 ID、变更前状态、变更后状态、时间戳，以及 API 提供的供应商请求标识符。不要因为供应商端点返回了完整账户对象，就把包含恢复数据、个人字段或令牌的无限制账户对象也返回给代理。控制输出内容，可以限制进入后续代理推理的信息。

如果供应商支持幂等性，就应当显式加入相应字段。网络故障后的重试应该得到已知结果，而不是再次发送邀请、重复扣款或重复修改群组。保存操作请求 ID，并让重试与它关联。不要让语言模型从含糊的错误信息中猜测之前的调用是否成功。

## OAuth scope 必要，但通常过于粗糙

OAuth scope 会限制凭据，而你应当使用供应商提供的最窄 scope。但它不会自动表达你的运营规则。像 `users.write` 这样的 scope，可能允许暂停、删除、编辑资料，以及修改租户中所有用户的角色。你的代理也许只需要其中一项。

RFC 6749 将 scope 定义为限制访问请求的字符串，同时把具体含义留给授权服务器。这种灵活性解释了为什么不同供应商的 scope 名称差异很大，也解释了为什么管理员不能只根据标签判断安全行为。应当阅读供应商 API 参考中批准 scope 下的每个写入方法。Scope 名称不是安全审查。

RFC 8707 为 OAuth 请求增加了资源指示器，使客户端可以申请面向特定受保护资源的令牌。如果 SaaS 供应商支持资源限制，应当使用它，尤其是在同一身份可以访问多个租户或 API 的情况下。资源指示器可以限制令牌预期的受众，但它仍然无法告诉供应商你的代理可以暂停用户，却不能删除用户。

在可能的情况下，按操作类别分离凭据。只读目录凭据不应因为都用于月度报告，就和账单变更凭据拥有相同权限。这样可以减少轮换带来的影响，也能在供应商令牌泄露或配置出错时限制损害。

尤其要警惕一种危险模式：客户端请求了一小组 scope，却通过一个接受任意下游路径的管理员服务交换它。清单里的 OAuth 授权看起来范围很窄，但它背后的服务账户却拥有不受限制的权限。检查完整的调用路径。真正有效的权限，是供应商实际处理请求时所在位置的权限。

不要把 bearer token 存进代理配置、提示词文件、shell 历史记录或工具输出。暴露后再做脱敏，并不能让令牌重新回到你的控制之下。代理应该请求一个命名操作并提供普通参数。另一个独立组件只在这次出站调用中注入凭据，然后返回受约束的结果。

## 用户和群组变更需要独立的升级路径

当用户生命周期自动化遵循声明式身份来源，而不是聊天指令时，它会更安全。SCIM 在 RFC 7644 中定义，是一种配置和管理身份资源的协议。它为创建、替换、补丁更新、查询和取消配置操作提供了标准形式，但它不会判断“把某人设为管理员”的请求是否合法。

如果有权威目录，应当在日常入职、转岗和离职流程中使用 SCIM 或供应商支持的生命周期 API。允许代理根据该来源准备拟议变更，并把请求绑定到支持该变更的身份记录。如果有人说“移除 Sam”，代理应该找到记录并展示匹配的身份，而不是在相似姓名之间猜测。

群组成员关系需要比许多团队想象中更严格的控制。名为 `Engineering` 的群组，在某个产品里可能无关紧要，在另一个产品里却可能授予源代码访问、部署权限或财务报告权限。应当根据群组授予的权限分类，而不是根据名称分类。特权群组应当放进单独的操作类别，由指定审批人处理，并使用更短的会话时长。

角色分配不是普通的资料维护。它会改变谁能进行后续变更，而且这些变更可能发生在代理的审计路径之外。角色提升、所有权转移、恢复方式变更和联邦配置，都应当放在每次调用都要求人工决策的操作之后。对许多组织来说，代理应当准备请求并收集证据，由人直接在供应商控制台执行最后一步。

一次失败的离职流程看起来往往很普通。代理收到针对 `jordan.lee@company.example` 的工单，按显示名称搜索，找到一名姓名相近的在职员工，然后把对方从高权限群组中移除。操作员修正工单后，代理又重试真正的承包商记录。两个操作在 API 看来都成功了。问题出在操作设计上：名称搜索和特权变更被允许在一次未经审查的动作中完成。

应当通过分离发现和变更来修复这个流程。让代理返回候选身份、不可变 ID 和当前群组成员关系。审批记录必须包含选定的 ID。之后的暂停或移除群组操作只能接受这个 ID。这次额外交接不是官僚流程，而是防止含糊查询变成权限变更的必要措施。

## 账单权限应在资金流动之前停止

账单数据往往需要自动化，但账单权限有一条明确边界：读取发票和改变付款对象是两回事。不要因为供应商把它们都称为 Billing Admin 功能，就让报表、付款更新、订阅变更、退款和税务设置共用一套凭据。

只读导出操作可以接受一个有合理上限的日期范围，返回发票标识符和总额，并记录请求。除非真实任务确实需要，否则不应把完整支付工具、税务文件或任意客户账单资料暴露给代理上下文。要同时减少访问范围和响应数据。

即使供应商 API 把以下操作做得很普通，也应当把它们视为高影响操作：

- 更改支付方式或账单联系人。
- 增加席位、订阅等级或用量上限。
- 取消订阅或发放抵扣。
- 修改税务、法律实体或采购订单信息。
- 创建可以管理账单的用户。

要求每次调用都经过审批，并展示确切的供应商租户、账户或订阅 ID、旧值、新值，以及 API 能提供的财务影响。“批准账单更新”这种审批提示，设计出来就是让人直接点击。审批人必须看到具体会发生什么变化。

预算护栏也应当放在模型之外。如果订阅操作可以提高上限，就在操作定义中设置固定上限，或者在人工选择批准值之前拒绝变更。不要让代理根据上下文窗口中的政策文件自行判断增加支出是否合理。

一些团队试图用每日操作摘要来解决账单风险。摘要有助于复核，但无法在扣款发生前阻止它。摘要适合读取操作和低影响对账。不可逆的财务调用前必须放置明确同意。

## 工作区设置需要变更窗口，而不是永久自由

工作区设置很容易被低估，因为它们在管理控制台里看起来只是几个开关。外部共享、域验证、会话时长或数据保留设置，可能会同时影响所有用户。因此，一次很小的 API 请求，后果可能比数百次普通账户编辑更严重。

应当为每项设置，或每个关系紧密的设置类别定义一个操作。每个定义都应包含允许的值、写入前所依赖的当前状态读取，以及回滚值。不要允许代理把任意配置对象提交给通用设置端点。通用端点很容易失控：供应商新增字段后，你原本受约束的自动化也可能继承从未审查过的权限。

要求操作在提出写入之前立即读取当前值。审批内容应同时显示旧值、新值和影响范围。这样可以避免另一个管理员已经修改设置后，操作员仍然批准过期方案。

对于可能中断登录、共享、配置或数据保留的设置，应使用变更窗口。代理可以收集当前配置、起草变更请求，并且只在规定窗口内执行操作。紧急修复应使用单独的紧急操作，要求填写明确原因，并配置即时通知路径。不要把紧急访问伪装成普通自动化例外。

如果供应商提供非生产租户，应在那里测试回滚。如果没有，就选择可逆设置，并在自动化前记录供应商的行为。依赖“代理会把它改回来”的回滚方案不算方案，因为原始请求可能超时，或者供应商可能在写入时规范化了值。

## 人工审批只有绑定到具体运行才有用

审批只有在审批人能看到谁在请求、将执行什么操作，以及权限会持续多久时才有用。对“AI 助手”的泛化审批，最终会变成措辞更好听的常驻权限。将会话审批绑定到单个代理进程，并在进程退出或用途改变时撤销它。

对于目标和载荷本身带来风险的变更，应使用逐次调用审批，包括特权群组成员关系、角色提升、账单变更、删除、所有权转移和全工作区设置。对于读取用户并准备离职候选名单等范围明确的低影响调用，可以使用会话审批。不要让每次目录查询都弹出审批。人们最终会停止阅读。

Sallyport 通过绝对保险库闸门、逐会话授权，以及可选的每次密钥使用审批来实现这种区分。面向代理的 MCP 路径可以执行 HTTP 或 SSH 操作，同时不会把存储的凭据暴露给代理。

如果操作系统能够确认调用进程的身份，审批记录就应包含它。单独记录进程名称的证据很弱，因为任何进程都可以使用一个熟悉的名称。代码签名权限、进程生命周期和操作请求，可以为审批人提供足够上下文，让其拒绝来自意外工具的请求。

审批不能弥补操作目录权限过大的问题。如果提示词说“更改工作区设置”，审批卡也重复这句话，那么人就必须在别处重新还原具体方案。应当让审批载荷足够具体，迫使审批人针对指定租户、对象、旧值、新值和原因作出决定。

## 证据必须在代理会话结束后仍然存在

SaaS 供应商自己的审计日志很有必要，但它可能无法说明代理为什么发出请求、哪个本地进程发起了请求，或是否有人批准了请求。应当保留独立的操作记录，把代理运行、审批事件、操作契约、出站请求、供应商响应和撤销事件串联起来。

要谨慎记录请求字段。你需要足够的细节来重建操作，但不应把审计系统变成另一堆秘密。保存标识符、状态转换、必要时的请求哈希、供应商请求 ID，以及敏感值的受保护表示。提前决定事故期间谁可以读取详细记录。

防篡改证据很重要，因为被攻陷的本地进程可能会在不安全调用后试图删除痕迹。哈希链日志可以帮助你验证条目是否被修改或删除，而不必重写后续记录。它不能证明每次操作都是明智的，但能证明记录是否仍然保持连续性。这是不同但很有用的结论。

例如，Sallyport 会从加密、哈希链保护的审计日志中生成会话和活动日志，`sp audit verify` 可以在离线状态下检查这条链，而且不需要保险库秘密。验证应该成为事故流程的一部分，而不是等到需要时才临时发现的命令。

应当围绕真实的权限路径进行撤销演练。终止代理运行，拒绝未来的操作请求，如果可能已经暴露则撤销或轮换受影响的 SaaS 凭据，核验审计记录，并将供应商侧的变更与操作日志进行比对。只能撤销聊天会话的团队，并没有撤销管理访问权限。

## 分阶段替换访问权限，拒绝那些诱人的捷径

迁移在这样的情况下才能成功：用受限的操作路径替代一条宽泛权限路径，在故障场景下验证它，然后移除旧权限。试图一次性重做所有 SaaS 集成，只会让旧管理员令牌继续存在，理由是“项目完成前还需要它”。之后它就会变成永久权限。

选择一个事实来源稳定、结果可回滚的任务。准备暂停账户通常比删除账户更合适。导出发票通常比修改付款更合适。先记录现有调用顺序，再找出任务实际使用的每个端点和字段。许多团队最终会发现，所谓必需的管理员凭据，只是因为某个没人重新检查过的特殊端点而存在。

在信任正常流程之前，先用刻意构造的错误输入测试新的操作路径。发送未知字段，发送来自另一个租户的用户 ID，模拟超时后重试，提交一个已过期审批引用的请求。正确结果应该是带有审计记录的拒绝，而不是尽力猜测。

然后从代理配置、构建日志、代理可以访问的秘密存储和备份脚本中移除旧令牌。仅仅轮换令牌还不够，如果下一个自动化仍能使用同一个宽泛角色。确认代理无法使用它能够读取的凭据直接调用供应商。

为仍然需要人工在控制台完成的任务保留例外登记。记录所需的供应商操作、受限 API 路径不存在的原因、获准操作人员和复查日期。保持可见的例外会被重新审视，藏在运行手册中的例外则会成为下一次使用广泛令牌的理由。

每项拟授予代理的权限都可以用一个简单标准检验：你能否说清确切目标、允许的变更、审批条件，以及操作留下的证据？如果不能，代理还没有真正的任务，只有一枚等待事故发生的管理员令牌。
