AI 代理操作目录:找出不需要的访问权限
建立 AI 代理操作目录,通过记录每项操作、影响、负责人、身份和审批决定,找出过度权限。

AI 代理操作目录是找出那些没人真正有意选择的权限的最快方法。它列出代理在自身工作区之外可以执行的操作,然后要求逐项做出决定:谁负责这项操作,出错后会发生什么,以及是否必须由人审批。
大多数团队一开始就走错了方向。他们先盘点 API 密钥、集成或软件账户,然后以为自己已经了解访问权限。其实并没有。凭据只是一个容器。真正的安全决策发生在操作层面:“创建发票草稿”和“发起退款”有着截然不同的含义,即使两个调用使用的是同一个令牌。
我见过权限审查失败,因为团队问的是:“代理需要访问计费系统吗?”这个问题太宽泛,无法诚实回答。应该分别问它是否需要读取一张发票、创建草稿、提交退款、更新收款信息,或导出客户列表。答案通常各不相同。不必要的访问权限,就藏在这些差异中。
集成清单会掩盖真正重要的权限
系统清单告诉你代理连接到了哪里。操作目录告诉你它可能造成什么后果。两者都要保留,但不要把其中一个误当成另一个。
考虑一个连接到源代码管理服务的代理。“仓库访问”可能包括读取代码、创建拉取请求、修改分支保护、创建部署密钥、发布版本或删除仓库。把这些内容当作一个权限,会把一组独立的风险决策简化成敷衍的“是”或“否”。
SSH 也存在同样的问题。“代理可以通过 SSH 连接到 staging”几乎没有提供有用信息。只能获取服务状态的受限命令,与一个可以重启服务、读取部署密钥或修改防火墙规则的账户下的 shell 访问,后果完全不同。应记录命令类别或端点,而不是只记录传输方式。
这个区别很重要,因为团队经常把暴露的两个维度混在一起:
- 可达性是指代理能否联系某个系统。
- 权限是指系统在建立连接后允许它做什么。
- 后果是指代理发出错误或被操纵的请求后可能发生什么。
一个内部端点可能很难访问,却拥有极高权限。一个公开 API 可能很容易访问,但权限有限。只根据服务是否“内部”来设计审批,会同时漏掉这两种情况。
NIST Special Publication 800-53 的 AC-6 控制项将最小权限描述为:只授予完成指定任务所需的访问权限。这句话听起来显而易见,但应用到代理身上就不一样了。“指定任务”不能只是“协助工程工作”。它需要具体到一个具有目标、方法、边界和预期结果的操作。如果无法把这些写下来,就不能声称实现了最小权限。
从审查者无需打开代码仓库就能理解的操作名称开始。“POST /v1/issues”是有用的证据,但“在工程跟踪系统中创建问题”能让负责人明白自己正在审批什么。两者都保留在记录中。
一行记录一个外部可见操作
目录中的每一行,都应代表一个可以单独做出访问或审批决定的最小操作。如果两项操作合理地拥有不同负责人、不同影响或不同审批要求,就应该分成两行。
一行实用的记录需要足够详细,让工程师能够实现控制,也要足够通俗,让系统负责人能够拒绝它。可以使用以下字段:
| 字段 | 记录内容 | 存在的原因 |
|---|---|---|
| 操作 ID | 稳定标识符,例如 deploy.production.restart-service | 即使名称变化,也能保留原有决策 |
| 系统 | 目标系统和环境 | 区分生产环境与测试环境的访问 |
| 操作 | 人类可读的动词和对象 | 让权限可以被审查 |
| 技术路径 | API 方法和路径、命令模式或工具调用 | 让工程师能够执行边界控制 |
| 身份 | 凭据类型、账户、作用域和委派模型 | 暴露共享权限或过大的权限 |
| 处理的数据 | 发送的输入和返回的输出 | 暴露数据泄露风险 |
| 影响 | 后果类别和可逆性 | 为审批选择提供依据 |
| 负责人 | 明确的业务或技术决策人 | 让某个人对访问权限负责 |
| 审批 | 无、每次会话或每次调用 | 定义人的控制点 |
| 证据 | 测试、日志引用或实现位置 | 证明记录符合实际情况 |
| 审查日期 | 日期和审查人 | 防止旧例外变成永久权限 |
不要在操作字段中写“各种”“管理员任务”“完整 API”或“按需”。这些说法意味着目录在工作真正开始前就停止了。继续拆分,直到某个人无需猜测就能回答“是”或“否”。
下面是一个开发代理的简要示例:
action_id: issue-tracker.create-bug
system: issue tracker, production tenant
operation: Create a bug report in the Engineering project
technical_route: POST /api/projects/engineering/issues
identity: service account agent-issues, scope issues:write
inputs: title, body, labels, repository reference
outputs: issue ID and URL
impact: internal write, reversible by project members
owner: Engineering operations manager
approval: per-session
review_date: 2026-09-30
即使这项操作只创建工单,“production tenant”这个词也应该保留在这一行中。许多团队在同一个生产 SaaS 租户中存放真实客户、员工和事件信息。环境标签能告诉审查者,他们正在跨越哪一道边界。
避免虚假的精确。只要目标、负责人、身份、审批和后果确实相同,就不需要为每个无害的字段更新单独建立一行。但当某个特殊字段会改变结果时,就必须拆分。“更新事件状态”和“更换事件指挥官”可能经过同一个端点,但不应获得相同的审批决定。
沿着凭据和工作流发现操作
只阅读代理提示词,不可能找到完整的操作集合。提示词描述意图,代码、配置、凭据和实际流量才会显示代理真正能够请求什么。
先从人们希望代理执行的工作流开始。请工程师用动词描述他们最近交给代理,或希望交给代理的十项任务。“调查构建失败”可能会扩展为读取日志、查询部署服务、创建问题、重启测试环境和发送消息。记录每一个跨越的外部边界。
然后从每个凭据反向检查。查看 API 作用域、OAuth 授权、服务账户角色、SSH authorized keys、命令包装器、CI 变量和本地密钥存储。凭据经常会暴露工作流讨论中没人提到的操作。带有用户管理作用域的 API 令牌就是一个操作候选,即使团队坚持说代理只负责创建工单。
最后,将意图与证据进行比较。网络跟踪、API 网关日志、命令审计记录和代理工具定义,会显示工作流文档遗漏的调用。可以时,先在安全的测试环境中完成这一步。生产日志依然重要,因为在时间压力下,代理和人都倾向于寻找捷径。
使用以下五轮收集流程:
- 列出每个会超出本地任务范围的代理工作流。
- 从代理配置和代码中提取每个工具调用、端点和 shell 命令模式。
- 列出每个凭据允许的操作,包括继承的角色和通配符作用域。
- 审查近期操作日志,寻找清单中没有的目标或动词。
- 与目标系统负责人核对差异。
第四轮通常会出现令人不舒服的发现。你可能会找到一个拥有广泛仓库管理权限的旧令牌、一把被生产主机接受的 staging SSH 密钥,或一个可以触发发布的“内部” webhook。不要为了符合原计划而悄悄缩小记录。把实际有效的操作放入目录,并让某个人决定它是否应该保留。
一个有用的测试是把某一行记录交给没有参与构建该集成的同事。他们应该能够解释代理发送了什么、收到了什么,以及最严重的合理错误是什么。如果做不到,这一行只是技术残留,不是控制记录。
影响要描述后果,而不是一个笼统的风险分数
应根据错误操作会改变、暴露、花费或承诺什么来分类影响。单一的“高、中、低”评级会失败,因为它隐藏了操作为什么需要人的关注。
我在目录中使用五类后果:披露、完整性、可用性、外部承诺和权限变更。一行可以同时属于多个类别。读取客户导出文件会产生披露后果。删除部署会影响可用性。添加管理员会改变权限。发送合同会产生外部承诺,即使从技术上说该操作可以撤销。
再加入两个修饰因素:可逆性和影响范围。可逆性要问的是,是否能由有能力的人在不造成损失或混乱的情况下撤销操作。影响范围要问的是,错误会影响一份草稿、一个项目、许多用户,还是整个环境。
这样得出的决定才经得起解释。“删除临时测试分支”可能会改变完整性,但可以撤销,影响也有限。“轮换生产数据库凭据”可能提高安全性,却也可能影响许多服务的可用性。两者都是写操作,但应属于不同的审批类别。
不要让“API 支持撤销”决定可逆性。账本中的退款可以撤销,但客户可能已经收到令人困惑的邮件。已发布的软件包可以撤回,但下游系统可能已经获取它。已删除的账户可以恢复,但原所有者可能在事件处理期间失去访问权限。应考虑运营后果,而不只是数据库操作。
操作返回的数据同样需要关注。一个看似无害的状态查询,如果返回完整环境变量、支持记录或私钥,也属于披露操作。团队往往过度关注代理能否写入,因为写入看起来更主动。一个能够读取所有密钥、然后调用外部端点的代理,已经拥有制造严重事件的足够权限。
保持影响描述具体。不要写“高影响”,改为“可以修改工作区所有成员的生产授权”或“可以将客户标识符发送到第三方 API”。前一种描述能告诉负责人要决定什么,单独的标签做不到。
负责人必须是有权说“不”的人
每项操作都需要一名明确的负责人,这个人能够拒绝、缩小或移除该操作。负责人对权限决定负责,而不是对代理产生的每个运营结果负责。
最合适的负责人通常属于目标系统,或承担业务后果。工程负责人可以负责生产部署操作。财务团队负责提交退款。安全团队可以定义访问管理的条件,但不应因为自己是安全团队,就成为每一行记录的默认负责人。
共享负责人会让目录逐渐失效。“安全和工程”意味着双方都会以为对方会审查。应记录一名承担责任的负责人;如有需要,可以在备注中列出需要咨询的团队。如果负责人更换岗位或团队,应在交接中一并转移目录记录。
负责人需要一份一屏就能看完的决策材料。提供操作、系统、实际身份、涉及的数据、后果、建议的审批方式,以及代理需要该权限的简短原因。不要把一份原始 OAuth 作用域列表交给他们,然后称之为治理。
负责人应该回答四个问题:
- 代理确实需要这个结果,还是工作流只是觉得这样方便?
- 能否通过更窄的端点、角色、账户、目标或命令取得同样结果?
- 哪种错误会造成无法接受的后果?
- 谁应该批准使用,且这项决定什么时候到期?
通常最难回答的是第一个问题。团队经常授予宽泛操作,只因为这样可以避免未来再次讨论。但这不是需求,而是一次被推迟的访问审查,并且还附带了凭据。
让负责人在执行路径中清晰可见。如果发生事件时没人能找到负责人,目录就没有发挥作用。明确的负责人也让定期审查变得可行,因为审查可以直接问:“你是否仍然授权这个代理以这个身份执行操作 X?”
审批应该对应承诺发生的时刻
审批只有在代理造成后果之前出现,并且审查者能够理解自己允许的内容时才有用。如果代理已经把十项无关操作捆在一起,弹出一个写着“允许使用工具”的按钮,那只是安全表演。
在目录中使用三种审批状态。“无”表示代理获得会话权限后即可执行操作。“每次会话”表示人在特定代理进程开始调用任何获授权操作前,批准该进程。“每次调用”表示人需要审查该操作的每一次使用。
对于后果适中、范围狭窄且较为常规的操作,适合使用每次会话审批,例如读取构建状态或创建内部草稿问题。它能确认预期的代理进程正在运行,然后让代理完成普通工作,而不必让人反复点击。
对于会产生承诺或跨越难以恢复边界的操作,适合使用每次调用审批。应将其用于修改生产访问权限、删除重要记录、触发影响客户的部署、向公司外发送消息、处理资金和导出敏感数据。在这些情况下,让人检查每个请求是合理的摩擦。
审批记录必须包含上下文。至少要显示调用进程身份、操作、目标、目标环境和重要参数。“代理请求 POST”会迫使审查者在压力下重新推断操作。“在生产环境重启 payments 服务,由已签名进程 X 发起”才是可以做出决定的信息。
不要用审批提示来弥补一项本不应存在的权限。对“在生产环境执行任意 shell 命令”设置每次调用提示,仍然意味着审查者要一次次批准空白支票。应将宽泛的 shell 能力替换为受限命令或独立操作,然后在必要时审批这些具体操作。
操作网关在这里很重要,因为它可以让凭据远离代理,同时把人的决定放在接近执行的位置。Sallyport 使用固定的决策阶梯:锁定的保管库拒绝所有操作,新代理进程默认需要每次会话授权,选定的密钥则可以要求每次使用都审批。
这种结构能避免一个常见错误:在还没有很好地清点操作、无法安全编写规则之前,就先发明一套庞大的规则语言。复杂策略在设计文档中看起来很成熟,例外不断增加后却会变得无法审查。从清晰的操作、范围狭窄的身份,以及与影响相匹配的审批开始。
目录能在生产环境之前暴露失败路径
当目录捕捉到一连串单独看来都合理的选择时,它才真正有价值。考虑一个被要求调查订单工作流为何失败的编程代理。
工程师因为某个服务令牌可以读取日志,就把它交给代理。同一个令牌也有权查询订单 API。代理发现一份格式错误的订单,并被告知“清理测试数据”。由于集成没有清晰区分租户名称,它对生产租户调用了删除端点。端点接受了请求。之后人发现这份订单是真实订单,但恢复它需要在支付、库存和客户支持系统之间进行协调。
每句话单独看都无害:读取日志、查询订单、删除测试数据。操作目录会把这条链拆成几行:
| 操作 | 隐藏问题 | 更好的决定 |
|---|---|---|
| 读取订单工作流日志 | 日志包含客户标识符 | 限制返回字段,并记录披露影响 |
| 按 ID 查询订单 | 令牌拥有广泛订单访问权限 | 使用限定到所需租户的只读身份 |
| 删除测试订单 | 生产与测试共用一组端点 | 分离目标环境,并要求每次调用审批 |
| 修改客户订单 | 这不是清理工作 | 将负责人指定给运营人员,并从代理范围中移除 |
有用的发现不是“代理会犯错”。当访问边界含糊时,人也会犯同样的一连串错误。代理执行得更快,更容易重试,也可能遵循听起来在局部合理的指令,却没有注意到人类会结合上下文推断出的业务含义。
对于高后果记录,在备注中写出失败路径。使用简单格式:触发条件、错误目标或错误理解、采取的操作、即时影响、恢复负担。这样能让审批选择不再抽象,也能让审查者有理由拒绝宽泛访问。
目录还可以发现危险组合。读取事件记录可能是可以接受的。经过审查后向公共状态页面发布信息也可能可以接受。但如果同一个代理同时执行这两项操作,却没有内容边界,就可能暴露内部事件细节。应审查这样的组合:一个操作提供敏感输入,另一个操作把数据发送到组织外部。
让目录可执行,然后证明它符合实际
只存在于电子表格中的目录,最终会变成一份权限愿望清单。将每条获批记录连接到技术边界:独立凭据、受限 API 作用域、目标允许列表、受限 SSH 命令或审批配置。
在配置和日志中使用操作 ID。这样可以进行简单测试:每个观察到的外部操作都应映射到一个目录 ID,每个有效的目录 ID 都应对应当前的执行控制点。调查两种不匹配。没有记录的观察操作是影子访问。没有执行控制的记录可能是过时计划,也可能是未受控制的路径。
对于 HTTP 调用,验证方法、主机、路径模式、目标环境和凭据作用域。对于 SSH,验证账户、主机组、命令限制,以及辅助工具能否传递任意参数。“SSH 访问已获批”不是可执行的声明。
例如,这条目录记录声称代理只能获取部署状态:
Action ID: deploy.status.read
Host: deploy.internal.example
Command: deployment-status --service \u003capproved-service\u003e
Identity: agent-deploy-read
Approval: per-session
但下面的实现破坏了这一声明:
command=\"/usr/local/bin/deployment-status $SSH_ORIGINAL_COMMAND\" ssh-ed25519 AAAA... agent
这个包装器把任意原始命令作为参数传入。如果 deployment-status 会调用 shell,或接受未经检查的选项,那么目录边界就是虚构的。更安全的设计是把获批的服务名称映射到固定命令,并拒绝所有其他输入。要有意测试拒绝路径。
case \"$1\" in
checkout) exec /usr/local/bin/deployment-status --service checkout ;;
search) exec /usr/local/bin/deployment-status --service search ;;
*) echo \"service not permitted\" \u003e\u00262; exit 1 ;;
esac
不要把这段代码直接复制到 authorized-keys 配置中。它展示的是你需要的特性:代理只能从定义好的操作中选择,而不是使用任意命令语言。你的环境仍然需要输入验证、账户限制,以及由了解命令行为的人进行测试。
对于操作证据,应记录能够证明边界两侧的测试。正向测试证明获批调用可以正常工作。负向测试证明相邻的禁止调用会失败。团队经常只保留正向测试,因此宽泛凭据才会悄悄存活。
Sallyport 会从一个只能写入、无法读取的加密哈希链审计日志中,记录代理会话和单独调用。它的 sp audit verify 命令可以在离线状态下对密文验证哈希链,无需访问保管库密钥。这些证据有助于将目录与实际行为进行核对,但不能代替移除不必要操作的决定。
工作变化时审查访问,不要等到季度审查才发现问题
当你添加工具、修改代理工作流、签发或轮换凭据、更换系统负责人,或发现险些出错的事件时,都应审查目录。这些事件会改变实际有效的访问权限。等待日历上的审查,会让旧假设持续存在,同时集成不断增加。
无论如何,都要为每一行设置审查日期。高后果操作的间隔应短于无害的内部读取。审查不应只是确认电子表格还存在,而应确认代理是否仍需要这项确切操作、身份是否仍然足够狭窄、负责人是否仍然正确,以及实际使用情况是否支持保留它。
积极移除未使用的操作。团队不愿删除权限,是因为担心代理以后会需要它。如果真的需要,就按照同一个负责人和审批流程重新添加。重新授予一项已知操作,比清理一项本来不该留存的操作更省力。
第一份有用的目录不必覆盖一切。选择一个代理,列出它今天能够执行的每项外部操作,并要求负责人逐行做出决定。你会发现,有些访问之所以存在,只是因为此前没人需要给它命名。这正是应该在最糟糕的时刻到来之前移除的访问权限。
常见问题
什么是 AI 代理操作目录?
操作目录是代理可能请求或触发的所有外部操作清单。每条记录都会写明目标系统、确切操作、所使用的凭据或身份、影响、业务负责人以及所需审批。它不同于应用清单,因为它记录的是代理能做什么,而不只是系统中有哪些软件。
团队应该什么时候为 AI 代理建立操作目录?
应在代理能够自主执行操作之前开始建立。等到代理已经连接了广泛权限后再建目录,往往只是在记录既成事实,而不是做出决策。如果代理已经拥有访问权限,可以先把新增操作置于审批之后,同时完成清点。
代理的只读访问总是低风险吗?
如果读取权限可能暴露源代码、客户数据、凭据、安全发现或业务计划,就要把它视为潜在敏感权限。只读权限也可能成为破坏性写操作前的侦察手段。应根据返回的数据进行分类,而不只是看请求是否会修改记录。
哪些代理操作应该每次都要求审批?
对于不可逆、对外可见、成本高昂或涉及安全的操作,使用逐次调用审批。例如删除生产数据、发布版本、修改访问控制、发送批量消息和转移资金。审批内容应包括清晰的操作摘要、目标系统和相关参数。
谁应该负责代理访问清单中的一项操作?
负责人必须了解系统的业务目的,并愿意承担授予或移除该操作的责任。负责人不必每天运行集成,但必须能够决定代理是否应保留访问权限。“平台团队”不能算负责人,除非其中有明确的人可以做出这个决定。
如何清点使用共享服务账户的操作?
清点实际使用的身份,而不是账户的友好名称。记录操作使用的是服务账户、OAuth 授权、API 令牌、SSH 密钥还是委派的用户会话,同时记录作用域和目标环境。共享凭据会削弱问责,因此当操作集合不同时,应将它们拆分。
可以用电子表格维护代理权限清单吗?
最初可以使用电子表格,只要每项操作都有单独一行、稳定标识符、负责人、审查日期和决策。问题不在于使用电子表格,而在于只维护一份永远不会交到访问审批人手中的系统清单。
如何评估 AI 代理操作的影响?
不要把每项写操作都标记为高影响。应区分可逆的内部更新,例如创建草稿工单,与发布、删除或授予访问权限等不可逆或对外操作。目录应说明操作出错时会造成什么后果,而不是依赖含糊的严重性标签。
为什么审计日志不足以实现 AI 代理访问控制?
日志只能告诉你凭据或权限已经存在后发生了什么。操作目录要回答的是这项操作是否本来就应该存在、谁接受了它,以及执行前适用什么审批。两者都需要,因为完整的日志并不能减少过度权限。
AI 代理操作目录应该多久审查一次?
当代理接入新的集成、凭据发生变化、系统负责人更换,以及发生事故或险些出错的事件后,都应审查目录。同时为每条记录设置定期审查日期,强大操作的间隔应更短。未经审查的目录最终会变成一份没人愿意在今天授予的权限档案。