土法炼钢 · 系统与基础设施

【Tetragon / eBPF】运维与导出工程:metrics 更名、JSON 轮转与 SIEM 接线边界

文章导航

分类入口
kubernetessecurity
标签入口
#tetragon#ebpf#metrics#grpc#json-export#siem#v1.7.0

目录

第 11 篇 解释事件在节流与环缓冲上消失。本篇回答运维侧两个对称的问题:Prometheus 上的计数器能证明什么;日志管道接到文件之后仍看不见的原因是不是 SIEM 配错了。 v1.7.0 把一批指标改名,并把默认 gRPC 从 TCP 换成 Unix socket。把旧仪表盘和旧客户端原样接到新 agent,会同时出现「merge 指标消失」和「第三方采不到事件」。

本篇在系列中的位置

篇目 核心内容
第 11 篇 · 节流与观测税 丢事件的内核/队列层
第 12 篇 · 运维与导出工程 metrics、轮转、SIEM 与 gRPC 地址
第 13 篇 · 排障坐标系 按五轴归因
系列目录 全部篇目

版本锚定:Tetragon v1.7.0(2026-04-29)Upgrade notes + pkg/metrics/ + pkg/exporter/。JSON 默认路径以 tag events.md 为准:/var/run/cilium/tetragon/tetragon.log。无真实节点则不粘贴伪造 /metrics 或 dashboard 截图。不写 Splunk / Elasticsearch 产品步骤。


一、v1.7.0 metrics:merge 从两条计数器收成一条带 status 的计数器

Upgrade notes · Metrics:

源码 pkg/metrics/kprobemetrics/kprobemetrics.go 与 notes 一致:MergeTotal 的 Help 是 “The total number of attempts to merge a kprobe and kretprobe event.”;status 约束为 ok / errorMergeOkInc / MergeErrorsInc 都打到同一计数器。旁边仍有 tetragon_generic_kprobe_merge_pushed_total(推入待合并队列的次数),notes 没有删除它。

升版检查:Grafana / 告警若仍搜旧的 _errors_total / _ok_total,查询会空,不表示 merge 不再发生。应改为:

tetragon_generic_kprobe_merge_total{status="error"}
tetragon_generic_kprobe_merge_total{status="ok"}

该指标证明的是 kprobe 与 kretprobe 事件能否配对,不是「策略是否匹配」或「JSON 是否写出」。status="error" 升高时,用户态看到的可能是残缺的 enter 或 exit,而不是完整的一次调用。把它当成第 9 篇的 hook 选错,坐标系又偏了。curr_fn / prev_fn 用来区分是哪两个探测点在抢同一条合并槽;curr_type / prev_type 区分当前与前一条是 enter 还是 exit。告警若只看 status 总和,会把互不相关的函数搅在一起。

MergePushed 计数的是「先放下、稍后合并」的次数。它升高只说明合并队列在工作,不说明最终 ok。配对失败时,第 11 篇的环缓冲丢失与本节的 merge error 仍要分开看:前者是根本没进 agent,后者是进了但 enter/exit 对不上。

pkg/metrics/consts 把 Prometheus namespace 钉成 tetragon,因此上文计数器都以 tetragon_ 开头。eventmetrics.RegisterHealthMetrics 注册 flags / notify overflow / BPF collector / missing process info;InitEventsMetricsevents_totalpolicy_events_total 注册到另一条 registry。刮取时若只看见 health 组、看不见 events_total,先查该 scrape 对应的 registry 是否注册了 InitEventsMetrics 那一组,不要假设 merge 更名把它们删了。v1.7.0 Upgrade notes 没有删除 events_total

同一次发布还点名(Upgrade notes / changelog,本篇只列与导出运维直接相关的):

指标或行为 v1.7.0 口径
tetragon_process_cache_early_deletions_total 新增,观察 process cache GC 过早删除(第 13 篇血缘轴)
tetragon_overhead_program_seconds_total 修复为按秒报告,不再误把纳秒当秒(PR #4830)
tetragon_debug_events_total 把非致命问题从错误里分开(PR #4416)

pkg/exporter/metrics.go文件导出路径另备一套计数器,与 merge 无关:

指标 Help 口径
tetragon_events_exported_total 已导出事件总数
tetragon_events_exported_bytes_total 已导出字节
tetragon_events_last_exported_timestamp 最近一次导出的时间戳
tetragon_export_ratelimit_events_dropped_total 导出层限流丢掉的事件

最后一项与第 11 篇 Post.rateLimit 不是同一层:Exporter.Send() 在 JSON encode 之前看用户态 rateLimiter,拒绝则 rateLimitDropped.Inc() 并返回。SIEM 若只读文件,会同时少掉这些事件;gRPC 听众不受这个计数器约束。

第 11 篇已列的 tetragon_observer_ringbuf_* 在升版后名字不变,仍是管道丢失的第一选择。本篇不重复公式,只强调:merge_total 回答配对;ringbuf lost 回答没进 agent;events_exported_total 回答文件 sink 写出了多少。 三者不能互相替代。


二、JSON 轮转:SIEM 只能看见文件 sink

tag events.md:默认部署把 JSON 写到 /var/run/cilium/tetragon/tetragon.log,可供 fluentd、logstash 一类工具采集;文件会轮转并压缩。路径与 live 站点后版本的目录迁仓说明不是一回事,本系列按 tag 文档钉这一条。

实现上 pkg/exporter/exporter.gocilium/lumberjack/v2 写文件。NewExporteroption.Config.ExportFilenameExportFileRotationInterval:间隔为负则直接报错;大于 0 则 time.AfterFunclumberjack.Logger.Rotate()Send() 的顺序是:导出层 rateLimiter(失败则只加 export_ratelimit_events_dropped_total)→ encoder.Encodeevents_exported_total++ 并刷新 events_last_exported_timestampSetLogParams 允许在运行时改 MaxSizeMaxBackupsRotationInterval(经 event log gRPC 参数;本篇不展开该 API)。daemon-configuration 示例用 drop-in export-filename 把路径改成 /var/log/tetragon/tetragon.log——这是覆盖默认,不是第二条默认。

tag events.md 写默认部署会轮转并压缩。Helm chart 的具体 exportFileCompress 默认值以安装时的 chart 为准,本篇不把 live chart 表格写成 v1.7.0 事实。运维能核对的是:进程是否以 lumberjack 打开了 ExportFilename;采集器是否跟随 rotate 后的新文件。

events_last_exported_timestamp 适合做「文件 sink 是否还在写」的存活探针。它不证明 SIEM 已摄入:采集器可以停在旧 inode 上,而 Tetragon 已经 rotate 到新文件。这是日志管道的经典 inode 问题,不是 TracingPolicy 失败。

必须连同第 4 篇 Caution 再读一遍:allowlist / denylist 只作用于文件 sink。gRPC 与 tetra getevents 仍是未经过这层过滤的流。因此:

接线 看见的集合
采集 tetragon.log 的 SIEM 经过 export allow/deny、field filter、redaction、导出层 rate limit、轮转窗口里仍在磁盘上的文件
tetra getevents / 自写 gRPC 客户端 不受 JSON allow/deny 约束
agent 停机且未开 persistent 观测 两边都没有新事件;第 10 篇 --keep-sensors-on-exit 只留下强制执行

SIEM「少事件」时先问三句:文件路径是否仍是 tag 文档那条(或你显式改过的 export-filename);allow/deny 是否把该类事件裁掉;轮转后采集器是否还指着已压缩/已改名的 inode。不要先改 TracingPolicy。

events.md 里的 allowlist 形态(文档示例):每行一个 JSON 对象,行之间为 OR,对象内字段为 AND。denylist 优先于 allowlist。只配 allowlist 时导出是 default-deny。

{"event_set": ["PROCESS_EXEC", "PROCESS_EXIT"], "namespace": ["foo"]}
{"event_set": ["PROCESS_KPROBE"]}

上面配置在 JSON 文件里会留下:(EXEC 或 EXIT) 且 namespace=foo,或者任意 PROCESS_KPROBE。同一事件若仍出现在 tetra getevents 里,符合 Caution,不是采集器坏了。

同一份 events.md 还描述 field filter 与 redaction:按 protobuf field mask 做 INCLUDE / EXCLUDE;redaction 用 RE2 捕获组把参数/环境变量替换成 "*****"。这些同样 只改文件里的 JSON 形态,不改 gRPC 流上的对象(过滤分层仍以第 4 篇为准)。SIEM 侧若发现「有事件但字段空了」,先查 field filter,再查策略是否没取到该参数。文档 redaction 例子会把 "--password=foo" 写成 "--password=*****"——本篇不把它扩成密文处理教程。

本篇不写某个厂商的 source / sourcetype / ingest pipeline。工程边界是:日志产品只消费 Tetragon 愿意写进文件的那一子集。 若审计要求「与 tetra 所见一致」,文件 sink 满足不了,必须接 gRPC,并接受第 4 篇已经写出的过滤分层。

导出完备性仍是开放问题:JSON 与 gRPC 所见集合在配置 allow/deny 之后故意不对齐。升版改 socket 之后,第三方若静默失败,SIEM 会表现为「突然没日志」,而 tetra 在节点上仍然有事件——这是客户端连错地址,不是节流。


三、gRPC 默认地址:localhost:54321 不再是 v1.7.0 缺省

Upgrade notes · Helm Values:

把 agent 默认 server-addresslocalhost:54321 改为 /var/run/tetragon/tetragon.sock。该 socket 对节点上的 root 用户在同一路径可用。所有连接到 agent 的第三方程序都要更新这个地址。

events.md 把默认 helm 安装写成 unix:///var/run/tetragon/tetragon.sock,可用 --server-address 覆盖。daemon-configuration 给出两种写法:--server-address unix:///var/run/tetragon/tetragon.sock,或 drop-in 文件 /etc/tetragon/tetragon.conf.d/server-address 内容为同一 URI。tetra 未指定 --server-address 时会尝试探测本机 daemon 配置。文档 caution:Unix socket 仅限特权用户。

flowchart LR
  agent["Tetragon agent"]
  agent -->|"file sink allow deny redaction"| json["tetragon.log lumberjack"]
  json --> siem["Log pipeline SIEM"]
  agent -->|"gRPC unfiltered"| sock["unix:///var/run/tetragon/tetragon.sock"]
  sock --> tetra["tetra getevents"]
  sock --> third["Third-party gRPC client"]

破坏面(机制,非某 SDK 的 changelog):

  1. 仍拨 localhost:54321 的 sidecar、operator、自研 collector 会连接拒绝或连到空端口。
  2. 相对路径写错成 unix://var/run/...(少一杠)时,URI 解析与 Tetragon 期望的 unix:///var/run/... 不一致。
  3. 非 root 容器没有权限打开该 socket,表现为「gRPC 没事件」,JSON 文件可能仍在写。
  4. 把 socket 路径从宿主机 mount 进 sidecar 时,路径必须与 agent 实际 listen 的 path 一致;Upgrade notes 写该 socket「对节点上 root 在同一路径可用」,没有承诺任意容器命名空间都能看见它。

events.md 里仍出现 --set tetragon.grpc.address=localhost:54321 的 helm 示例:那是显式改回 TCP 的方法,不是 v1.7.0 的默认。第三方文档若还写死 54321,以 Upgrade notes 为准。需要 TCP 时必须显式配置,并接受「监听在 localhost 上的 gRPC 谁能连」与 Unix socket 特权模型不同——本篇不评价哪种更安全,只要求客户端与 agent 用同一地址族。

同一次 Events/gRPC 节还删除了 legacy stacktrace-tree:GetStackTraceTree gRPC、tetra stacktrace-tree、相关 protobuf。栈要改走 TracingPolicy PostkernelStackTrace / userStackTrace(见 examples/tracingpolicy/stack_traces.yaml)。已废弃的 EnableTracingPolicy / DisableTracingPolicy 现在会返回错误,除非打开 enable-deprecated-tracingpolicy-grpc。这些都会让「旧客户端」在升到 v1.7.0 后失败;本篇只点名,不重写第 5、6 篇的加载路径。


四、一张表:升版后运维信号怎么用

问题 优先看 不能证明
旧 Grafana 面板空了 merge 指标是否仍用已删除的两个名字 策略未加载
SIEM 比 tetra 事件少 第 4 篇 Caution;allow/deny;events_exported_total 内核选择器没匹配
tetra 与 SIEM 都少 第 11 篇 THROTTLE / ringbuf lost 单纯「导出路径写错」
第三方客户端全断 server-address 是否仍是 54321 JSON 轮转坏了
轮转后出现空洞 lumberjack 文件名与采集 inode;export_ratelimit_events_dropped_total Override 没生效
有事件但参数被星号替换 redaction filter hook 没取到参数

事故回顾时建议排成三列,缺哪列就进哪一层,不要从 YAML 改起:

证据
内核是否发生 策略加载成功、hook 符号存在、enforcement mode(第 10 篇)
agent 是否见到 tetragon_events_total、ringbuf received/lost、THROTTLE
文件是否写出 events_exported_total、allow/deny、轮转后的路径

不写具体 dashboard。可核对的工程动作是:把告警表达式迁到 tetragon_generic_kprobe_merge_total{status=...};把 gRPC 客户端改为 unix:///var/run/tetragon/tetragon.sock;把 SIEM 的输入钉在 tag 文档的文件路径,并承认它与 gRPC 不是同一集合。

tetragon_events_totalpkg/metrics/eventmetricsEventsProcessed)计数的是 agent 处理过的事件类型,带 process labels。它高于 events_exported_total 时,差额可能来自 JSON 过滤、导出限流、或根本没开文件导出。不要用 events_total 当 SIEM 摄入量的代理。

升版清单(只含本篇范围,不是完整 Upgrade notes):

  1. 改 scrape 与告警里的 merge 指标名。
  2. 改第三方 --server-address / 客户端 target。
  3. 删掉 tetra stacktrace-treeGetStackTraceTree 调用。
  4. 确认 EnableTracingPolicy / DisableTracingPolicy 客户端是否依赖已强制报错的 API。
  5. 核对 JSON 路径仍是 /var/run/cilium/tetragon/tetragon.log 或你显式设置的 export-filename

五、学术谱系、争论与开放问题

本篇偏运维,论文只收一条与「监视器看见的集合」有关的线。Garfinkel(NDSS 2003)整篇的前提是:安全工具声称观察到的系统调用集合,必须和内核实际发生的集合有可陈述的关系。Tetragon 把过滤拆到内核选择器、cgroup-rate、环缓冲、JSON allow/deny、导出限流多层之后,没有任何一层的计数器单独等于「真实发生」。merge_total 是配对尝试;exported_total 是文件写出;ringbuf lost 是没进用户态。导出完备性——能否对一次事故重建「内核发生 / agent 见到 / SIEM 见到」三列——仍开放。

争论:文件 sink 简便 vs gRPC 完整

主张 代价
只采 tetragon.log 适配现有日志管道;allow/deny 可降量 tetra 所见故意不一致;轮转与 inode 跟踪
只采 gRPC 看见未经 JSON 过滤的流 v1.7.0 默认 Unix socket 打断旧 TCP 客户端;权限模型更严

没有文献规定 SIEM 必须接哪一侧。可检验命题是:事故回顾时能否说明缺口落在哪一层(第 13 篇口诀:先点名轴)。

开放问题

  1. 三列对齐:内核发生、agent 见到、文件写出能否用同一套关联 id 对账。入口:第 4 篇 Caution;本篇 events_exported_total vs ringbuf_*
  2. 升版指标迁移:删除的 merge 计数器会让历史告警静默。入口:v1.7.0 Upgrade notes Metrics。
  3. 停机窗口:persistent enforcement 留下阻断、导出管道为空(第 10 篇限制)。SIEM 如何记录「强制执行仍在、事件没有」。

六、小结

  1. v1.7.0 删除 tetragon_generic_kprobe_merge_errors_total_ok_total,改用 tetragon_generic_kprobe_merge_totalstatus 标签。
  2. tetragon_events_exported_* 只描述文件导出;export_ratelimit_events_dropped_total 是文件路径上的又一次丢弃。
  3. SIEM 接到日志文件就只看见文件 sink;JSON denylist 挡不住 tetra
  4. 默认 gRPC 为 unix:///var/run/tetragon/tetragon.sock,原 localhost:54321 客户端会断。
  5. 本篇不提供 Splunk/ELK 配置;下一篇用五轴把「无事件 / 误阻断 / 导出缺口」收成排障口诀。

七、参考资料

规范 / 官方文档(A)

源码(A)

核心论文

站内对照

实验台账


上一篇:节流与观测税 · 系列目录 · 下一篇:排障坐标系

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .