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

【Tetragon / eBPF】运行时安全全景:缺口、五轴坐标系与 16 篇路线

文章导航

分类入口
kubernetessecurity
标签入口
#tetragon#ebpf#runtime-security#tracingpolicy#process-exec#falco#v1.7.0

目录

Cilium / eBPF 数据面内核 已把东西向包路径钉到 identity 与 map;可观测性 · 网络观测linux/ebpf-security 对照过 Tetragon 与 Falco。Cilium 选型收束 把 Tetragon 标为运行时安全续作,但停在排除树叶。中间仍缺一层:一次安全事件如何经进程血缘与 hook、TracingPolicy 选择器如何在内核过滤、Override 与 SIGKILL 各自停在哪一步、导出过滤为何与 tetra 所见不一致,以及相对 Falco / auditd / 仅 NetworkPolicy+Hubble 何时不该上 Tetragon。

本文只做三件事:钉缺口、定义后续 15 篇共用的五条坐标系,并给出阅读路线。难点不在「会不会 Helm 装 Tetragon」,而在控制面意图与内核路径交界上的可核对字段——exec_id、hook 类型、加载集合键、JSON allow/deny 与 gRPC 的分流、Override 相对 Signal 的保证。

本篇在系列中的位置

篇目 核心内容
第 1 篇 · 运行时安全全景 缺口、五轴坐标系、16 篇路线
第 2 篇 · 进程模型 exec_id、血缘、in_init_tree、procfs 回填
系列目录 关键问题、阅读路径、全部价值点

版本锚定:Tetragon v1.7.0(源码 tag v1.7.0,发布 2026-04-29)。机制叙述对齐该 tag 下的 docs/content/en/docs/bpf/pkg/api/v1/tetragon/tetragon.io/docs/ 是滚动站点,不以 live 文档冒充本版本。无真实 Tetragon 节点则不粘贴伪造 tetra getevents / JSON 输出。 spec.nodeSelector 与 domain sharding 晚于该 tag,不作为本系列能力。


一、相对站内已有内容,缺口在哪

下表列出各已有系列的视角,以及本系列补的格子。规则是:不重写已有内容,只填真正空着的格子。

已有内容 视角 本系列补什么
cilium/ 01–16 东西向 identity / map / kube-proxy 替代 / Hubble 进程与 syscall 安全事件面;不重写 CNI
cilium/16 点名 Tetragon,停损线 成系列展开策略 → hook → 强制执行
observability/15linux/ebpf-security 工具对照、快速启用清单 机制路径、失败模式、排障坐标系
ebpf/ 01–21 verifier、JIT、BTF、Map 不重写 VM;只写 Tetragon 如何用这些原语
Falco / auditd 站内提及 对照口号 机制差:过滤位置、阻断语义、TOCTOU

结论:读者知道「Tetragon 用 eBPF 做运行时安全」、会贴一条 TracingPolicy YAML,但不知道事件卡在选择器还是导出过滤、为何 tetra getevents 仍看到 denylist「已滤掉」的事件、Override 与 SIGKILL 各自停在哪一步、三条加载路径(kubectl CR / tetra gRPC / --tracing-policy 文件)撞名时为何「改了 CR 不生效」。本系列补「eBPF 运行时安全内核」那一格。

与通识教程的差别也在这里:多数「在 K8s 上装 Tetragon」文章停在 process_exec 示例与一条文件打开策略;本系列追问 策略 apply 成功之后丢失/误阻断仍落在哪一层,以及 血缘空洞、hook 未挂上、加载路径撞名、JSON 与 gRPC 集合不一致、Override 不可用各自如何表现。深度来自可证伪的阶段划分,而不是更长的功能清单。

本系列刻意不写 Helm values 百科、每个发行版 CIS benchmark 逐条映射、verifier 形式化算法全书、完整 MITRE 规则库、未实测跨方案 CPU 排行。站内 linux/ebpf-security 对照表里的资源占用数字本系列不引用——那些数字未经本仓库实测,也不能从 v1.7.0 官方文档核出。官方已经钉死、本系列会反复回指的机制差只有这一条:JSON export allow/deny 不影响 gRPC / tetra(v1.7.0 events.md Caution)。若目标只是「把 DaemonSet 跑起来」,官方 Quickstart 与 observability/15 已够;若目标是「失败落在哪张 map / 哪个 hook、导出为何对不齐」,则必须沿五轴下钻。


二、五条坐标系(后续章节回指)

后面每一篇都落到下面某一条轴上。本篇钉名字、关键锚点与失败表象;具体生命周期、源码与事件停顿点在对应篇展开。排障口诀:先点名轴,再下钻模块——不要一上来改 TracingPolicy YAML 或重装 DaemonSet。

flowchart LR
  proc["execve_map plus process cache"] --> hook["Hook Sensor"]
  hook --> sel["In-kernel selector"]
  load["Load paths kubectl gRPC file"] --> sel
  sel --> act["Action Override Signal Post"]
  act --> ring["Ring to agent"]
  ring --> split{"Sink"}
  split -->|"JSON allow deny"| json["tetragon.log"]
  split -->|"gRPC unfiltered"| grpc["tetra getevents"]

图:一次运行时安全事件沿五轴从进程状态走到 sink 分流。节点为英文,避免窄框折行;正文用中文解释每条轴。

可核对锚点 失败表象 主篇
进程血缘 exec_id / parent_exec_idGetProcessID:base64(node:ktime:pid))、execve_map、用户态 process cache、in_init_treeflags(含 procFS 短命进程无父、kubectl exec 不像 init 子孙、进程不在 map 02、13
Sensor/Hook 内置 process sensor(__base__);kprobe / tracepoint / uprobe / USDT / LSM / fentry(v1.7.0) 策略已 apply 无事件、无 BTF、hook 名写错 03、05
策略加载 三条路径:kubectl CR、tetra gRPC add、--tracing-policy 文件;集合键 name+namespace 改了 CR 不生效(实际是文件/gRPC 侧同名集合)、Namespaced vs cluster 撞名 05–06
过滤分层 内核 selector vs JSON export allow/deny vs field/redaction tetra 仍看见 denylist「已滤」事件 04、07
强制执行 Override(需 CONFIG_BPF_KPROBE_OVERRIDE)vs Sigkill/Signal;monitor vs enforce;TOCTOU SIGKILL 后 syscall 副作用已发生;Override 不可用却当阻断 10、13

进程血缘轴

定义:Tetragon 如何给一次执行分配跨节点、跨 PID 复用仍可核对的身份,以及父子关系在内核 map 与用户态 cache 之间如何衔接。

PID 会被内核复用。v1.7.0 的回答是 exec_id:用户态 GetProcessID 把导出用节点名、内核 ktime 与 PID 拼成 node:ktime:pid,再做标准 Base64(见 第 2 篇)。内核侧权威状态在 execve_map(按 TGID 索引);JSON 里的 process / parent 来自用户态 LRU cache 的富化。agent 启动时还会从 procfs 回填已存在进程,事件 flagsprocFS

「短命进程看不到父」或「kubectl exec 进来的 shell 被当成容器业务进程」优先落本轴,而不是先怀疑 TracingPolicy YAML。本轴不承诺零缺口血缘:fork 时若父不在 execve_map,子进程根本不会入图——这是失败路径,不是实现细节。

Sensor/Hook 轴

定义:哪些 BPF 程序在哪些内核/用户态点上挂着,以及 TracingPolicy 动态 hook 相对内置进程传感器覆盖什么。

可核对锚点 含义
__base__ sensor 进程生命周期:execve tracepoint、wake_up_new_task fork、exit kprobe、execve_map
spec.kprobes / tracepoints / uprobes / usdts / lsmhooks / fentries TracingPolicy 动态 hook(CRD @ v1.7.0)
BTF / CO-RE 加载失败时事件为零,表象像「策略没匹配」

「策略已 apply 但没有任何 kprobe 事件」优先查本轴的符号名、syscall ABI 前缀、LSM 是否启用、fentry 是否被内核接受,而不是先改选择器。Verifier / JIT 算法外链 ebpf/,本系列只写 Tetragon 选用的 hook 角色与内核依赖

策略加载轴

定义:一条 TracingPolicy 从哪条路径进入同一 collection map,以及同名集合如何互相覆盖或静默失败。

v1.7.0 文档列出三条路径:Kubernetes kubectl 施加 CR、tetra 经 gRPC add/delete、daemon 启动时的 --tracing-policy / --tracing-policy-dir 文件。集合键是 name + namespace(cluster-scoped 策略的 namespace 为空)。domain sharding(k8s / grpc / static)不是 v1.7.0 机制,不要用后版本 CLI 去解释本版本撞名。

「改了 CR 不生效」优先怀疑另一条路径已经占用同名集合,而不是先怀疑 YAML 缩进。展开见第 5–6 篇。

过滤分层轴

定义:内核选择器丢掉的事件,与 JSON 导出 allow/deny 丢掉的事件,不是同一集合。

内核 selector 在 hook 内决定 Post / NoPost / Override / Signal(第 7 篇)。JSON 文件 sink 另有 allowlist / denylist。v1.7.0 events.md 的 Caution 写死:这两类导出过滤作用于 gRPC,因此默认的 tetra getevents 仍能看见 denylist「已滤」事件。Field filter 与 redaction 又是另外两层,且 redaction 发生在进程对象构造时,会进入所有 sink。

「SIEM 里没有、tetra 里还有」优先落本轴,而不是先认定策略没挂上。展开见 第 4 篇

强制执行轴

定义:匹配之后 Tetragon 保证什么、明确不保证什么。

Override 让被 hook 的函数不执行并返回指定错误,依赖 CONFIG_BPF_KPROBE_OVERRIDESigkill / Signal 终止进程,官方文档写明不保证当前 syscall 不做完(典型是 write() 已把字节送进内核)。monitor / enforce mode 改变动作是否真正发出。TOCTOU 是系统调用拦截类工具的经典失败模式,不是 Tetragon 独有的实现 bug。

「策略匹配了但文件已经被写出去」优先落本轴的保证边界,而不是先加大选择器范围。展开见第 10、13 篇。


三、坐标系背后的三个不变量

相对「用户态规则引擎读 /proc 或 ptrace」与「只在 CNI 上做 NetworkPolicy」,Tetragon 运行时安全同时钉住三条不变量:

  1. 进程身份以 exec_id 为键,不以瞬时 PID 为键:PID 复用由 ktime 与节点名拆开;代价是必须解释 map 未命中、procfs 回填与 fork 失败路径。
  2. 能在 hook 完成的过滤尽量留在 BPF 里:选择器在内核丢事件,导出过滤在用户态再丢一次。代价是两层过滤的可见集合可以不一致——这是设计,不是 CLI 故障。
  3. 强制执行发生在具体 hook 的语义里,而不是「安全产品已阻断」的口号里:Override 与 Signal 的保证不同;syscall 入口拦截继承 Garfinkel 指出的 TOCTOU。代价是排障必须问「拦在函数入口还是进程退出」,不能问「Tetragon 开了没有」。

排障时先问「哪条不变量被触碰」,再落到对应轴。例如:kubectl exec 注入的进程看起来像业务子孙 → 不变量 1;denylist 之后 tetra 仍刷屏 → 不变量 2;SIGKILL 后副作用已落盘 → 不变量 3。

这三条不变量也解释了系列边界:本系列不重写 verifier 证明义务(那是 eBPF VM 层),也不写 Cilium 东西向 policy map(那是 CNI 数据面层)。我们只在 Tetragon 运行时安全里追问:给定这三条约束,v1.7.0 如何实现、何处失败、与系统调用拦截的经典假设差在哪。


四、设计谱系:过滤虚拟机 → 系统调用拦截 → 生产分叉

McCanne & Jacobson, USENIX Winter 1993(经典 BPF:内核过滤虚拟机)
  → 扩展 BPF(通用内核可编程;站内 ebpf/ 展开 verifier/JIT)
  → Garfinkel, NDSS 2003(系统调用拦截的陷阱:TOCTOU、/proc 窗口、覆盖不全)
  → Tetragon:eBPF hook + 进程 map + TracingPolicy(工程系统)
  → 仍争:内核过滤完整性 vs 用户态规则可移植性;导出完备性 vs 观测税

Höiland-Jørgensen et al.(The eXpress Data Path, CoNEXT 2018)把可编程点推到网卡驱动最早路径,是 Cilium 东西向数据面的学术对照,不是本系列主线。本系列的执行面是 kprobe / tracepoint / LSM / fentry 这类安全与追踪 hook,不是 XDP。不要把「eBPF 很快」从数据包路径直接搬到 syscall 拦截路径上——工作负载、缓存效应与失败模式都不同。

  1. 经典 BPF(McCanne & Jacobson, USENIX Winter 1993)定义「在内核里用受限虚拟机过滤」的范式;今天的 eBPF 是能力与安全模型都大幅扩展后的后代,细节见 ebpf/
  2. 系统调用拦截的陷阱(Garfinkel, NDSS 2003)列出 TOCTOU、通过 /proc 重建进程树的竞态、以及「以为拦了入口其实副作用已发生」。Tetragon 用内核 map 跟踪执行,消除的是「每次事件再扫一遍 /proc」这条路径,不消除 Garfinkel 的全部陷阱。
  3. 生产分叉(v1.7.0):内置 __base__ 进程传感器维持 execve_map;TracingPolicy 把策略写成可加载的 hook 集合;JSON 与 gRPC 分成两套可见集合。fentry、hostSelectormatchParentBinaries 已在该 tag;spec.nodeSelector 与 domain sharding 尚未进入。
维度 经典 / 早期 Tetragon v1.7.0 默认叙事 开放分叉
进程身份 PID、/proc 快照 exec_id + execve_map 启动窗口与 fork 未命中时血缘残缺
过滤位置 用户态规则 / 审计日志 hook 内 selector + 用户态导出过滤 两层集合能否对齐
阻断 杀进程、seccomp 否决 Override vs Signal TOCTOU 可接受边界
对照工具 auditd、Falco 用户态规则 同一节点上的 eBPF 运行时安全 规则库生态 vs 内核路径税

五、开放争论(先立靶,后各章拆)

争论 A 侧 B 侧 本系列落点
内核过滤完整性 vs 用户态规则可移植性 hook 内丢事件,攻击窗口短 Falco 规则库与用户态表达更易搬迁 第 4、7、14 篇
内核进程树 vs procfs 快照 短命进程在 exit 前可被 map 看见 启动前回填仍走 /proc,有窗口 第 2、13 篇
Override 正确性 vs SIGKILL 简便 函数不执行 不依赖 CONFIG_BPF_KPROBE_OVERRIDE 第 10 篇
「必须 Tetragon」营销 vs Falco / 仅 CNP 统一进程+syscall 面 规则库或网络策略在部分威胁模型下够用 第 14–16 篇

不在第 1 篇宣布胜负;每组争论要求后续篇给出可核对机制或选型边界,而不是「看业务场景」空话。

对「内核路径 vs 用户态规则」额外钉一句:本系列不比较未实测的 CPU 排行榜,只比较失败模式是否可归因到五轴中的某一层。若安全产品把过滤与阻断藏在黑盒里,工程师就失去了 exec_id / hook / sink 分流这类抓手——这是架构选择,不是性能排名。


六、16 篇路线与阅读建议

flowchart TD
  overview["01 Overview"] --> proc["02 Process Model"]
  proc --> hooks["03 Sensors Hooks"]
  hooks --> export["04 Event Export"]
  export --> agent["05 Agent Lifecycle"]
  agent --> tp["06 TracingPolicy"]
  tp --> sel["07 Selectors"]
  sel --> k8s["08 K8s Identity"]
  k8s --> faces["09 File Net Cap"]
  faces --> enf["10 Enforcement"]
  enf --> thr["11 Throttling"]
  thr --> ops["12 Ops SIEM"]
  ops --> trouble["13 Troubleshoot"]
  trouble --> vs["14 vs Alternatives"]
  vs --> rth["15 Runtime Hooks"]
  rth --> select["16 Selection"]
  overview --> select
路径 篇目 适合
必读核心 1 → 2 → 6 → 7 → 10 → 13 快速建立坐标系
事件与导出 3 → 4 → 11 → 12 管道与丢失归因
对照选型 1 → 14 → 16 路径选型
完整通读 1 → … → 16 系统掌握

先修:熟悉 Pod / 系统调用直觉;可选 cilium/01ebpf/01;对照 observability/15linux/ebpf-security

阅读时建议随身带一张「轴 → 锚点」卡片:短命进程无父先问血缘;策略已 apply 无事件先问 hook / 加载;tetra 与 JSON 对不上先问过滤分层;杀了进程仍落盘先问强制执行。把现象翻译成轴,比翻译成「重启 tetragon DaemonSet」更接近本系列目标。

五个关键问题到第 1 篇结尾仍然够用:后续每一篇应能把问题收束到某一轴上的可核对锚点。若一篇写完仍只能回答「看场景」,说明证据或机制还不够。本系列对跨方案 CPU 排名正是如此处理的。

本系列明确不写:Helm values 百科;把 live 文档的后版本能力写成 v1.7.0;伪造命令输出;把 Cilium NetworkPolicy / Hubble 数据面再讲一遍。


七、小结

  1. 定位:补 cilium/、observability/15 与 ebpf/ 之间的 Tetragon 运行时安全内核层,不重写产品百科或 verifier 全书。
  2. 五轴:进程血缘 / Sensor·Hook / 策略加载 / 过滤分层 / 强制执行;每轴有可核对锚点。
  3. 三不变量exec_id 为键、尽量在 hook 过滤、阻断语义绑定具体 hook。
  4. 谱系:经典 BPF → 系统调用拦截陷阱 → Tetragon v1.7.0 生产分叉。XDP 论文只作数据面对照。
  5. 路线:核心「1→2→6→7→10→13」;导出「3→4」;选型「1→14→16」。

下一篇进入血缘轴:没有 exec_idexecve_map 的语言,后面的选择器、导出分流和「偶发无父」都无处锚定。


八、参考资料

规范 / 官方文档(A)

源码(A)

核心论文

实验 / 工具

站内对照


系列目录 · 下一篇:进程模型

读完这篇,下一步读什么

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

2026-08-17 · kubernetes / security

Tetragon / eBPF 运行时安全:从进程血缘到 TracingPolicy

补齐站内 Cilium 数据面与可观测对照之上的运行时安全内核层:进程模型、Sensor/Hook、TracingPolicy 与内核过滤、强制执行、事件导出与节流,并以排障与相对 Falco/CNP 的选型收束。


By .