跳至正文

机器翻译。英文版本为权威来源,母语审校尚未完成。

least-privilege

许可与观察:漂移作为一等发现

作者 Olivares AI 6 分钟阅读

一篇配套文章介绍了最小权限偏移,这是指AI代理被允许执行的操作与实际观察到的操作之间的gap。那篇文章涵盖了这一概念:为什么会形成gap、先读观察如何产生允许与实际的差异、以及策略即代码如何在访问时消除这种差异。本文将进一步深入——探讨偏移如何成为安全模块内部的结构化、分类、可分级处理的发现,以及它一旦存在会发生什么。

简短版:偏移不是仪表板指标或日志行。它是一个持久化的实体,具有分类、严重性、置信度等级和分级处理生命周期。它用于异常队列,丰富取证时间线,并且诚实地反映它能和不能证明的内容。

三个信号来源

访问地图中的每一条边都记录了一个起点(代理、身份、会话)与一个资源之间的访问关系。每条边都有两个布尔标志:允许已观察。有趣的边是那些这两个标志不一致的边。

但这些标志并非凭空出现。它们来自不同的信号源,每个信号源都有不同的信任属性:

策略(允许)。 带有 signal_source=policysignal_source=scoped_grant 的边表示一个已声明的授权:即某个凭证、IAM 角色或平台自身的源范围平面表示此代理被允许执行的操作。在遥测证实之前,这些边是 permitted=true, observed=false。它们是上限。身份连接器(WIF 颁发者、API 密钥名册、工作区角色)提供这一端。一旦在工作区中获准其规则的 OAuth 范围的联合服务账户,就是这样一条边。

遥测(已观察)。 来自 OpenTelemetry 追踪、pgAudit 日志、CloudTrail 记录、MCP 注释、A2A 协议观测以及 GitHub/GitLab Webhook 的协作信号。这些会产生 observed=true 的边。其可信度取决于来源:pgAudit READ 分类是 attributed(数据库知道谁查询了以及是读取还是写入);MCP readOnlyHint 按规范是 approximate —— MCP 规范本身就说工具注释是不可信的。

内核(实际情况)。 eBPF 后备(signal_source=ebpf)在系统调用级别进行观察。它是代理无法绕过的信号。当 eBPF 层看到 connect()write(),而合作遥测没有报告时,这并不是日志记录 gap——它是反规避信号。安全模块将内核端和合作端的观察结果整合为关联异常,因此一个静默自己遥测的代理会成为一个发现,而不是一个盲点。

访问映射是对这些边的查询,而不是一个单独的模式。最小权限漂移是两个标志不一致的子集。

漂移如何成为一个发现

PermittedObserved之间的分歧是原始信号。引擎在其进入异常队列之前将其分类为两种漂移类型之一:

// DriftKind 分类允许与观察到的最小权限漂移。
type DriftKind string

const (
    // DriftUnusedGrant 是允许的访问但从未被观察到(权限过度配置)。
    DriftUnusedGrant DriftKind = "unused_grant"
    // DriftViolation 是观察到的未被允许的访问。
    DriftViolation DriftKind = "violation"
)

unused_grant 意味着策略允许代理执行其从未被观察到的操作。这是无效权限——承担风险而无益处。它是定期访问审查的清理信号:撤销那些未被使用的权限。

violation 意味着观察到代理正在做某些政策或授权不允许的事情。这是主动发现。它是差异表中显示为“未审核写入”的行——关键的边缘,异常队列优先处理的那个。

分类不是“正常”和“有问题”之间的二元方式。PrivilegeDrift 结构将违规边缘与其类型配对:

// PrivilegeDrift 是最小权限偏差:其 Permitted 标志
// 与 Observed 标志不一致的边。
type PrivilegeDrift struct {
    Edge AccessEdge
    Kind DriftKind
}

边缘本身携带完整的来源信息:来源(哪个代理)、资源、read/write 模式、产生该信号的信号源、归属的置信度,以及观察窗口(FirstSeenLastSeenOccurrenceCount)。漂移发现从不只是“某处出了问题”。它指向特定的代理、特定的资源、特定的访问模式,由特定的收集器观测,并具有时间范围。

异常队列:不仅是“不同”,而是经过分类的

当安全模块构建异常视图(GET /v1/m/security/anomalies 端点)时,它从访问边缘存储中提取漂移,并将每个 violation 分类为优先级异常。分类为原始边缘所不具备的提供了上下文信息:

访问漂移。 基线:已观察但未被允许的访问。该异常被命名为“意外访问:已观察但未被允许”,严重性为中等,并以 confidence=approximate 标记,因为商店级的漂移是原始信号——尚未与完整的代理到身份图进行对账。对账后的视图存在于访问地图自身的 /drift 端点;异常队列消耗原始信号并如实标记它。

怀疑 Egress/exfiltration。 当漂移边缘上的资源是指向外部非私有目标的网络端点时(eBPF 连接器将这些作为 tcp://host:port URI 发出),异常将被重新分类为 egress_exfil_suspected 并提升至高严重性。写入从未被授权访问的外部端点的代理,与读取其未被授权的数据库表的代理,是不同类型的发现。

敏感性升级。 当资源带有敏感性标签(highsecret)时,无论访问是否是出口访问,严重性都会提高。针对高敏感性资源的 violation 即使目标是内部的,也需要更快的分类。

每个异常都带有一个 evidence 映射,其中包含原始详细信息:

ev := map[string]any{
    "origin_kind":      edge.OriginKind,
    "origin_id":        edge.OriginID.String(),
    "resource_id":      edge.ResourceID.String(),
    "mode":             string(edge.Mode),
    "signal_source":    string(edge.SignalSource),
    "occurrence_count": edge.OccurrenceCount,
    "reconciled":       false,
}

reconciled: false是故意的。它告诉消费者这是原始的商店级别信号,而不是访问地图的调和后、代理到身份的视图。异常队列不会等待调和来显示violation——但它也不会在归因不确定时假装其是确定的。

置信水平:可证明的内容

访问地图中的每个边都有一个置信水平。产品使用两种:

  • 归因confidence=attributed):访问被收集器自身的证据牢固地绑定到来源。一个pgAudit记录标明代理的数据库角色、一个与代理IAM凭证相关的CloudTrail事件、一个与运行时解析到代理的进程ID相关的eBPF观察。归因链是端到端的。

  • 近似 (confidence=approximate):归因是推断的,可能存在信息丢失。信号来自共享服务账户,多个代理使用相同的凭证,来自有损存储(如不记录每个连接身份的 Redis 实例),或者来自规范中标记为不可信的 MCP 注释。该边仍然是一个信号——但操作员知道证据较弱。

置信度水平会影响异常的优先级分数。优先级函数 (priorityFor) 将每个异常的分数定为 0 到 100,近似置信度漂移会被折扣:

if confidence == string(sdkmodel.ConfidenceApproximate) {
    // 折扣:未消解的漂移存在噪声
}

这可以防止嘈杂的、共享身份的信号排挤一个明确的 attributed violation。两者都会出现在队列中;approximate 排名较低。这与法医强化应用的原理相同:当发现共享身份(SharedIdentity: true, AgentCount > 1)时,时间线会注明“每个代理的归属可能不明确”,而不是假装归属是精确的。

产品从不伪造确定性。仅标注的 MCP 边不具有与 eBPF 证实的边相同的权重。来自共享服务账户的漂移发现不具有来自单个代理身份的发现的相同权重。操作员能看到差异,并据此进行分类处理。

法医时间线中的漂移

漂移发现不仅存在于异常队列中。当开启一个法医案件并从哈希链审计账本重建其时间线时,安全模块会用主体的漂移信息丰富重建内容:

out.Drift = subjectDrift(r.Context(), sc, c.SubjectRef)

subjectDrift 函数会查询访问边缘存储中以主体为源的违规类型漂移,并返回 driftRefDTO 条目列表——每条记录包含源、资源、访问模式、信号来源、发生次数及最后一次观察时间。这些都是从存储自身的漂移计算中读取的,而不是由安全模块重新计算的。

时间线还承载着主体的身份归属和数据来源信息,因此调查人员在审查案件时可以看到完整的情况:代理行为以何种身份出现(以及该身份是否被共享)、它访问了哪些不该访问的数据,以及它从哪些数据中得出答案。每一项这些增强信息都可以容忍缺失的邻居——如果知识模块未安装,则来源信息会被省略而不是伪造;如果身份没有解析到具体代理,则归属显示为“尚未绑定”,而不是凭空创建一个。

分流生命周期

一个源自漂移的发现以状态 open 进入系统。此后,它遵循标准的发现分流生命周期:

  • 打开:发现已存在,但尚无人处理。
  • 已分级处理:操作员已确认,并分配给审查。
  • 已解决:根本原因已修复(授权被撤销,策略被收紧,代理范围被重新定义)。
  • 已驳回:操作员已审查并确定这不是实际风险(已知行为,来自approximate归因的误报)。

每一次分级状态的更改都会被自动审计到真实主体。驳回发现的行为本身也会被记录在防篡改账本中,因此审计员不仅可以看到发生了什么偏差,还可以看到谁进行了审查以及他们做出的决定。发现的证据(其类型、严重性和详细哈希)在创建后是不可变的;分级处理的更改仅影响工作流程状态。

这在实际操作中的意义

一个代理获得了一个针对 Claude 工作区的 API 密钥。身份连接器读取工作区的成员名单并发出策略边:此密钥被允许在该工作区调用 API。代理运行了三周。遥测显示它在该工作区调用 API —— 没有偏差。然后一次部署更改使代理获得了对第二个工作区密钥的访问权限。遥测观察到代理调用两个工作区。第二个工作区没有策略边。生成了一条类型为 violation 的偏差发现:已观察到但不允许。它以 access_drift 进入异常队列,严重性为中等,置信度为 approximate(该边尚未与身份图进行对账)。如果第二个工作区的资源带有 high 敏感性标签,严重性将提升。该发现将停留在操作员的队列中,直到有人进行分类处理。

这就是日志记录和结构化漂移之间的区别:该发现被分类,attributed(带有诚实的信心),被优先处理,并可进行分诊。它会持续存在,直到有人解决或驳回它。如果代理稍后成为事件案件的对象,它会出现在取证时间线中。而对其采取的每一个动作都会记录在一个产品可以证明其完整性的链条中。


漂移不是一个需要最小化的度量。它是一个需要分诊的发现。代理被允许做的事情与其被观察到的行为之间的gap,是最小权限执行的高信号表面——但仅当gap被结构化、分类并诚实地说明其可以证明的内容时。

要查看一个运行地产的通行地图和漂移表面,请访问通行地图产品页面产品概览

相关文章

常见问题

unused_grant 漂移与 violation 漂移有什么区别?

unused_grant 是从未被观察到的被允许访问——代理拥有但未使用的死权限。violation 则相反:被观察到的访问没有任何策略或授权允许。两者都是漂移,但它们带有不同的风险特征和不同的响应期望。unused_grant 是清理目标;violation 是可能需要立即分类处理的主动发现。

为什么异常队列折扣会近似置信度漂移?

当一个漂移边被标记为 approximate 时,其归因是推测的而非确定的。它可能来源于一个共享服务账户,在该账户中每个代理的归因会崩溃,或者来自一个有损信号源。在优先级评分中折扣它可以防止未调和的、潜在噪声的漂移挤掉更高置信度的发现。漂移仍会出现在队列中;其排名较低,直到归因确定或操作员进行分拣。

查看您的智能体能触及哪些资源

Olivares AI 是面向您 AI 资产体系的开放式自托管平台。将其部署在您自己的基础设施上,即可获得安全与平台团队一直期待的访问关系图。