eBPF 与 Linux 事件采集:从 Audit 框架到 osquery 的bpf_process_events/bpf_socket_events实战解析
【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleet
本篇文章以 Fleet 联合创始人兼 CTO Zach Wasserman 在 osquery@scale 2021 上的演讲《eBPF & the future of osquery on Linux》为骨架,系统梳理 Linux 上 osquery 事件采集的两条技术路线:以 Linux Audit 框架为基础的经典方案,以及以 eBPF 为代表的新一代内核事件采集方案。读完本文,你将理解 Audit 框架的能力边界、eBPF 的核心原理,掌握bpf_process_events与bpf_socket_events两张事件表的表结构、实现机制与在 Fleet 中启用它们的完整配置方法,并了解 eBPF 采集技术未来的演进方向。
为什么讨论 Linux 上的事件采集
osquery 最基础的能力是把操作系统抽象成一张张可查询的关系表——进程、用户、网络连接、文件系统,都变成 SQL 可以检索的对象。这类查询属于"快照式"(snapshot)信息获取:在你执行查询的那一刻,表返回的是当时系统的状态。
但端点可见性(endpoint visibility)的需求远不止于此。安全团队真正需要的是事件流:进程什么时候被执行、由谁执行、带什么参数;网络连接什么时候建立、连向了哪里。这正是事件采集(event instrumentation)要解决的问题,也是威胁狩猎、EDR 类工作负载的基石。
在 Linux 上,osquery 长期以来依赖Audit 框架来承载这类事件采集需求;而 eBPF 的出现,为 osquery 在 Linux 上的事件采集打开了全新的可能性。本文讨论的正是这条演进路径:Audit 方案的能力与短板、eBPF 的核心原理,以及由此诞生的bpf_process_events、bpf_socket_events两张事件表。
Linux Audit 框架:经典的 osquery 事件方案
Linux Audit 是内核提供的一套审计子系统。审计守护进程auditd订阅内核审计事件,osquery 则通过内核的 audit netlink 接口接入同一事件流,把进程创建、用户登录、配置修改等事件转成process_events、user_events、auditd等事件表。
在 osquery 中,Audit 采集是通过一组command_line_flags精确控制的。当前仓库的 osquery 测试工具完整记录了这些开关,见 tools/osquery-testing/README.md 与 tools/osquery-testing/test-tables.sh:
sudo osqueryi \ --disable_events=false \ --disable_audit=false \ --audit_allow_user_events=true \ --audit_allow_process_events=true \ --audit_allow_config=true \ --enable_keyboard_events=true \ --enable_mouse_events=true \ --line "SELECT * FROM process_events LIMIT 3"各开关的含义:
| 开关 | 作用 |
|---|---|
disable_events | 是否禁用 osquery 的事件发布器(publisher)基础设施,设为false表示开启事件采集 |
disable_audit | 是否禁用 Audit 发布器,设为false表示启用基于 Linux Audit 的事件表 |
audit_allow_process_events | 允许采集进程事件,是process_events表可用的前提 |
audit_allow_user_events | 允许采集用户登录/登出事件,支撑user_events表 |
audit_allow_config | 允许采集审计配置变更事件 |
audit_allow_fork_process_events/audit_allow_kill_process_events | 进一步细分进程事件的子类:fork 派生与 kill 信号 |
后面两个细分开关在仓库的 osquery 选项清单中得到了确认:tools/osquery-agent-options/osquery_5.18.1_codeflags.txt 中列出了audit_allow_fork_process_events、audit_allow_kill_process_events与audit_allow_process_events,并且它们同样出现在 tools/gitops-auto-complete/generated-schema.json 的 agent options schema 中——这意味着在 Fleet 的 GitOps 配置里,这些开关是可以通过 YAML 合法声明并校验的。
Audit 方案的不足
Audit 方案虽然成熟可用,但在规模化采集场景下暴露了明显的短板:
- 事件采样与丢失:高事件量下,audit 事件流会触发采样(sampling)甚至丢失,威胁狩猎最忌讳的就是"漏事件";
- 内核事件覆盖有限:Audit 主要覆盖进程与系统调用层面的审计点,对网络连接等更细粒度的内核事件支持薄弱;
- 发布器模型的开销:事件从内核到 netlink、再到 osquery 发布器的整条链路,在高负载主机上会带来不可忽略的 CPU 与内存开销。
这些短板正是 eBPF 被引入的核心动因。
eBPF:内核事件采集的新一代基础
eBPF(extended Berkeley Packet Filter)允许用户态程序在内核中安全地运行受限的字节码,从而在内核事件发生的源头进行观测,而无需修改内核或加载内核模块。对 osquery 而言,eBPF 意味着:
- 更完整的事件流:直接挂载在
execve、fork、connect等系统调用(syscall)的 tracepoint 上,从内核侧拿到第一手事件; - 更低的漏报率:事件在源头捕获,绕开了 audit 链路中的采样与丢失问题;
- 更细的观测维度:可以同时追踪进程生命周期与网络连接生命周期,这是 Audit 方案难以覆盖的。
仓库中的技术分析文档 docs/Contributing/host-vitals/osquery-ebpfpub-replacement-analysis.md 对 osquery 的 eBPF 事件发布器(内部代号 ebpfpub)做了完整剖析,可以直接印证两张 eBPF 事件表的设计。
两张核心事件表:bpf_process_events与bpf_socket_events
演讲中重点介绍的两张新表,正是 eBPF 能力在 osquery 中的落地成果。
bpf_process_events:进程生命周期
该表通过挂载进程相关的系统调用 tracepoint 采集进程事件,覆盖事件类型包括:
- 进程执行:
execve、execveat - 进程创建:
fork、vfork、clone - 进程终止:
exit、exit_group
表的能力包括进程树追踪(通过记录父子进程关系还原调用链)和命令行参数捕获,查询方式与经典process_events类似,例如:
SELECT pid, ppid, path, cmdline, uid, time FROM bpf_process_events WHERE time > (SELECT MAX(time) - 300 FROM bpf_process_events);bpf_socket_events:网络连接生命周期
该表通过挂载网络相关的系统调用 tracepoint 采集连接事件,覆盖事件类型包括:
- 连接建立:
connect、accept、accept4 - 服务端监听:
bind、listen - 同时追踪 IPv4 与 IPv6,并维护 socket 状态与连接元数据(源/目的地址、端口、进程归属等)
典型查询示例:
SELECT pid, path, remote_address, remote_port, action FROM bpf_socket_events WHERE action = 'connect' ORDER BY time DESC LIMIT 100;两张表遵循"事件表 + 状态字段"的设计:每次系统调用产生一行事件,配合时间戳与动作类型(如 connect/accept/bind、exec/exit),就可以重建一段窗口内的主机行为序列,这正是威胁狩猎所需的"过程视角"。
在 Fleet 中启用 eBPF 事件表
在 Fleet 中,osquery 的全部行为由agent options(Agent 配置)下发到 fleetd,再由 fleetd 同步到各主机的 osquery 实例,具体机制见 docs/Configuration/agent-configuration.md。
command_line_flags是其中与事件采集直接相关的配置段。要启用 Audit 或 eBPF 事件表,可以在Settings > Organization settings > Agent options中,或通过fleetctl应用的 YAML 中声明如下配置:
command_line_flags: disable_events: false disable_audit: false audit_allow_config: true audit_allow_process_events: true audit_allow_fork_process_events: true audit_allow_kill_process_events: true audit_allow_user_events: true注意以下几点:
command_line_flags中的设置只在 fleetd 重启时生效(重启 osquery 时重新加载 flag 文件);而options中的设置(如distributed_interval)可以热更新,无需重启。两者更新时机的差异务必区分。- 如果完全省略
command_line_flags,Fleet 会保留主机本地已有的 osquery flags;如果显式设为{}或null,Fleet 会清空各主机的本地 flags 并重启 osquery——所以不要在未明确写出所需 flags 的情况下置空该段。 - 如需验证当前生效的 flags,可以在主机上通过
sudo orbit shell进入交互式 osquery shell,然后执行:
SELECT name, default_value, value, description FROM osquery_flags;eBPF 采集的未来:从 ebpfpub 到 libbpf 的演进
从源码结构看,仓库对 eBPF 事件采集的下一步演进已有清晰规划,见 docs/Contributing/host-vitals/osquery-ebpfpub-replacement-analysis.md。
当前实现(ebpfpub)在运行期依赖 LLVM 9 的 API 将 BPF C 代码编译成 BPF 字节码再加载进内核。这一设计带来三重约束:版本锁定在旧 LLVM 工具链、存在事件丢失与 CPU 开销偏高的性能问题、代码库长期缺乏维护。分析文档推荐的重构路线是以 libbpf + 预编译探针(precompiled probes)取代 ebpfpub:
- 构建期:用
clang -target bpf将.bpf.c编译为.bpf.o,并嵌入 BTF(BPF Type Format)信息; - 运行期:通过 libbpf 的 CO-RE(Compile Once, Run Everywhere)机制加载,实现"一次编译、跨内核版本运行";
- 事件传递:改用 ring buffer 高效传递内核事件;
- 迁移策略:先以
bpf_process_events_v2/bpf_socket_events_v2的并行表形式与旧表并存做 A/B 对比,验证稳定后再替换回正式表名。
这一路线的收益是显著的:运行时依赖从约 100MB 的 libclang 缩小到约 200KB 的 libbpf,启动无需运行期编译,性能与可维护性均有质的提升,同时保留bpf_process_events/bpf_socket_events的表结构兼容性——也就是说,围绕这两张表写好的查询与告警,在未来升级中无需改动。
结语
Linux 上 osquery 的事件采集正在经历一场底层切换:从 Audit 框架的 netlink 事件流,走向 eBPF 的内核 tracepoint 直采。前者解决了"有没有事件"的问题,后者解决的是"事件全不全、快不快、省不省"的问题。对使用 Fleet 管理 Linux 主机的团队而言,bpf_process_events与bpf_socket_events提供的是两条高质量的事件源——进程的每一次 exec/fork/exit、网络的每一次 connect/accept/bind 都在内核源头被捕获,再以标准 SQL 的形式交给分析师去查询、聚合与告警。随着 ebpfpub 向 libbpf/CO-RE 的演进落地,这套事件能力在性能与可维护性上还有进一步上升的空间,这也正是演讲标题中"未来"二字的含义所在。
如果你希望在本机复现这些能力,可以借助仓库自带的 osquery 测试脚本 tools/osquery-testing/test-tables.sh 与事件表清单(macOS.txt、queries.txt),在开启--disable_audit=false与--audit_allow_process_events=true等 flags 后逐表验证事件采集效果。
【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考