安全与事件可观测性 Schema
本文定义 Kairo 事件总线 → OpenTelemetry 集成的字段命名约定与基数约束。
状态: v0.9 起 schema 覆盖所有 KairoEventBus 域,不再仅限 security。原有 security.* 键早于 bus(见 ADR-018),为与现存 LoggingSecurityEventSink 消费者兼容,在信封 body 内原样保留。当 KairoEventOTelExporter 把信封桥接到 OpenTelemetry 时,会在外层额外套一层 kairo.<domain>.* 命名空间前缀。
属性命名空间
KairoEventOTelExporter 默认发出的每条 log record 只带两个匿名信封级键。 kairo.event.id 仅在显式允许导出标识符时出现:
| 键 | 类型 | 示例 |
|---|---|---|
kairo.domain | String (enum) | security、execution、evolution、collaboration |
kairo.event.type | String | GUARDRAIL_DENY、MODEL_TURN、THREAD_STARTED |
kairo.event.id | String(UUID,需显式开启) | 9c1b…-…-… |
其余按域划分的属性只有在显式允许内容导出时,才会平展到 kairo.<domain>.<key> 下。取值统一转成 String;结构化 payload 必须由发布者在入 bus 前展平。tenant、principal 和 event id 由独立的标识符开关控制。
Severity 映射:
security→WARNexecution/evolution/collaboration→INFO
LogRecord.severityText 取域名;LogRecord.body 取 event type;LogRecord.observedTimestamp 使用 KairoEvent.timestamp()。
按域 Schema
kairo.security.*
用于 guardrail 生命周期事件。OTel exporter 始终开启(不被采样丢弃)。
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
kairo.security.event.type | SecurityEventType enum | 安全决策分类 | GUARDRAIL_DENY |
kairo.security.policy.name | String (有限集合) | 产出决策的策略 | content-filter |
kairo.security.decision.action | ALLOW / DENY / MODIFY / WARN | 策略输出 | DENY |
kairo.security.decision.reason | String (最多 256 字符) | 人类可读原因 | PII detected in output |
kairo.security.target.name | String (有限集合) | 被守护的工具或模型 | echo、claude-3 |
kairo.security.target.type | MODEL / TOOL / MCP_TOOL | 目标类型 | TOOL |
kairo.security.agent.name | String (有限集合) | 拥有该 pipeline 的 Agent | assistant |
kairo.security.guardrail.phase | GuardrailPhase enum | pipeline 切入点 | PRE_TOOL |
kairo.execution.*
用于执行日志生命周期(模型回合、工具调用、压缩、迭代)。通过 kairo.observability.event-otel.sampling-ratio 采样。
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
kairo.execution.model | String (有限集合) | 模型标识 | claude-opus-4-7 |
kairo.execution.tool | String (有限集合) | 适用时的工具名 | bash、read |
kairo.execution.phase | Enum | 生命周期阶段 | MODEL_TURN、TOOL_CALL、COMPACT |
kairo.execution.iteration | Integer | 单次运行内的迭代序号 | 3 |
kairo.execution.tokens.input | Integer | 输入 token 数 | 12540 |
kairo.execution.tokens.output | Integer | 输出 token 数 | 812 |
kairo.execution.duration_ms | Integer | span 耗时毫秒 | 1824 |
kairo.evolution.*
用于自进化技能治理生命周期(proposal → review → apply)。
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
kairo.evolution.skill.id | String (有限集合) | 技能标识 | summarize-diff |
kairo.evolution.phase | Enum | 治理阶段 | PROPOSED、REVIEWED、APPLIED、ROLLED_BACK |
kairo.evolution.reviewer | String (有限集合) | 审阅主体 | sre-ops |
kairo.evolution.outcome | Enum | 审阅结论 | ACCEPTED、REJECTED |
kairo.collaboration.*
用于 task-scoped Agent 协作生命周期。
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
kairo.collaboration.profile | String (有限集合) | 选中的无状态 Agent Profile | default、worker、explorer |
kairo.collaboration.phase | Enum | 子任务生命周期阶段 | QUEUED、WORKING、VERIFYING、TERMINAL |
kairo.collaboration.risk | Enum | Assignment 的有效风险 | D1、D2、D3 |
kairo.collaboration.acceptance | Enum | 宿主持有的验收状态 | PENDING、ACCEPTED、REJECTED、FAILED |
kairo.collaboration.outcome | Enum | 子任务终态 | COMPLETED、CANCELLED、FAILED |
低基数约束
上述每个域的属性值都保持在可枚举的有限集合内:
- 默认禁止导出 request id、trace id、UUID、tenant id 和 principal id。
- 禁止原始输入内容(prompt、工具参数、模型响应)——必须留在原始 bus
payload中,不导出。 - 禁止无界的用户自定义字符串。
若属性本身高基数,必须在发布前桶化(例如耗时 → OTel SDK 侧 histogram;用户 id → 角色)。
属性脱敏
kairo.observability.event-otel.redact-attribute-patterns 是一个 regex 列表,匹配平铺键(命名空间拼接后)。命中时,值会在挂到 log record 之前被字面量 <redacted> 替换。常用起步配置:
kairo:
observability:
event-otel:
redact-attribute-patterns:
- ".*password.*"
- ".*token.*"
- ".*secret.*"脱敏发生在 exporter 而非发布者。它是显式内容导出的纵深保护;在默认策略下,任意 事件属性根本不会抵达外部观测后端。
OTel 集成(v0.9)
kairo-spring-boot-starter-observability 会在以下条件满足时装配 KairoEventOTelExporter:
kairo.observability.event-otel.enabled=true(默认false,与 v0.9 其他 starter 一致)。- 存在
KairoEventBusbean(只要kairo-spring-boot-starter-core在 classpath 就总是成立)。 - 存在
LoggerProviderbean(应用自行接入 OTel SDK——可以用opentelemetry-spring-boot-starter或手写配置)。
默认 include-domains 为 [security]。execution / collaboration / evolution 域需要显式开启:
kairo:
observability:
event-otel:
enabled: true
include-domains: [security, execution, collaboration, evolution]
sampling-ratio: 0.2 # 非 security 域采样;security 总是全量
include-content: false # 默认值;prompt、工具载荷和路径只保留在本地
include-identifiers: false # 默认值;event/tenant/principal id 只保留在本地仅开启 exporter 不会开启任何敏感数据开关。内容和标识符必须分别明确授权,避免匿名 诊断在无意中变成可关联追踪。
原有 LoggingSecurityEventSink 继续并行工作——它用遗留 security.* 键(无 kairo. 前缀)写结构化 SLF4J 条目,现有 dashboard 在团队迁移到 OTel 路径期间仍可正常运行。域 / 信封契约见 ADR-018,exporter 行为保证见 ADR-022。