传统的 Linux 安全方案面临一个根本矛盾:AppArmor/SELinux 策略强大但配置复杂,Seccomp 简单但只能过滤系统调用,Audit 可以审计但无法阻止。eBPF 提供了一种新的安全范式——LSM BPF 允许在内核安全检查点挂载 eBPF 程序,既能审计又能阻止,策略可编程且低开销。
与此同时,Tetragon 等基于 eBPF 的运行时安全工具,实现了零侵入的进程监控——无需修改应用代码,即可实时检测异常行为。
一、Linux 安全机制演进
1.1 安全机制对比
| 机制 | 能力 | 限制 | 性能开销 |
|---|---|---|---|
| DAC(自主访问控制) | 基于文件权限 | 粗粒度 | 极低 |
| ACL | 细粒度文件权限 | 仅文件系统 | 低 |
| SELinux | 强制访问控制 | 策略复杂 | 中 |
| AppArmor | 路径级访问控制 | 仅路径匹配 | 中 |
| Seccomp | 系统调用过滤 | 仅系统调用,无法审计 | 低 |
| Audit | 审计日志 | 无法阻止,仅审计 | 中-高 |
| LSM BPF | 可编程安全策略 | 需要 5.7+ 内核 | 低 |
1.2 LSM BPF 的定位
二、LSM BPF 详解
2.1 LSM(Linux Security Module)框架
LSM 是 Linux 内核的安全钩子框架,在关键操作点插入安全检查:
2.2 LSM BPF 的工作原理
LSM BPF 程序挂载在 LSM 钩子上,在安全检查时被调用:
- 内核执行安全敏感操作(如文件打开、进程创建)
- LSM 框架调用注册的钩子函数
- LSM BPF 程序被触发,检查操作是否允许
- 返回 0(允许)或 -EPERM(拒绝)
2.3 LSM 堆叠与共存
Linux 5.1 引入了 LSM 堆叠(LSM Stacking),允许多个 LSM 模块同时生效。LSM BPF 作为”次要”LSM,可以与 SELinux/AppArmor 等”主要”LSM 共存——所有注册的 LSM 钩子依次执行,任一返回拒绝则操作被阻止:
启用 LSM BPF 需要在内核启动参数中添加 bpf 到 LSM 列表:
# 查看当前启用的 LSMcat /sys/kernel/security/lsm# lockdown,yama,integrity,apparmor
# 添加 bpf(需要重启)# GRUB_CMDLINE_LINUX="lsm=lockdown,yama,integrity,apparmor,bpf"LSM BPF 的部署应遵循渐进式策略:先以审计模式运行(仅记录,不拒绝),确认策略无误后再切换为阻断模式。生产环境中错误的 LSM BPF 策略可能导致服务不可用——例如误阻 socket_connect 会让所有网络请求失败。
2.4 LSM 钩子列表
| 钩子 | 触发时机 | 参数 |
|---|---|---|
| inode_permission | 文件访问权限检查 | inode, mask |
| inode_create | 创建文件 | dir, dentry, mode |
| inode_unlink | 删除文件 | dir, dentry |
| inode_rename | 重命名文件 | old_dir, old_dentry, new_dir, new_dentry |
| file_open | 打开文件 | file |
| task_kill | 发送信号 | task, signal |
| task_setuid | 设置 UID | uid |
| bpf | BPF 操作 | cmd, attr |
| socket_connect | Socket 连接 | sock, address |
| socket_bind | Socket 绑定 | sock, address |
| socket_listen | Socket 监听 | sock |
| socket_accept | Socket 接受 | sock |
| ptrace_access_check | Ptrace 访问检查 | task, mode |
| capget | 能力获取 | target, cap |
2.5 LSM BPF 程序示例:文件访问控制
#include "vmlinux.h"#include <bpf/bpf_helpers.h>#include <bpf/bpf_tracing.h>
// 受保护文件列表struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, u64); // inode 号 __type(value, u32); // 允许的 UID} protected_files SEC(".maps");
SEC("lsm/inode_permission")int BPF_PROG(restrict_file_access, struct inode *inode, int mask){ u64 ino = BPF_CORE_READ(inode, i_ino); u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
// 检查是否为受保护文件 u32 *allowed_uid = bpf_map_lookup_elem(&protected_files, &ino); if (!allowed_uid) return 0; // 非受保护文件,允许
// 检查当前用户是否有权限 if (uid != *allowed_uid) { // 记录非法访问 bpf_trace_printk("Access denied: uid=%d ino=%lu\n", uid, ino); return -EPERM; // 拒绝 }
return 0; // 允许}
char LICENSE[] SEC("license") = "GPL";2.6 LSM BPF 程序示例:网络连接控制
#include "vmlinux.h"#include <bpf/bpf_helpers.h>#include <bpf/bpf_tracing.h>
// 允许连接的 IP 列表struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, u32); // 目标 IP __type(value, u32); // 允许的 UID} allowed_ips SEC(".maps");
SEC("lsm/socket_connect")int BPF_PROG(restrict_connect, struct socket *sock, struct sockaddr *address){ struct sockaddr_in *addr = (struct sockaddr_in *)address; u32 dst_ip = BPF_CORE_READ(addr, sin_addr.s_addr); u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
u32 *allowed = bpf_map_lookup_elem(&allowed_ips, &dst_ip); if (allowed && uid != *allowed) return -EPERM;
return 0;}
char LICENSE[] SEC("license") = "GPL";2.7 Seccomp-BPF:系统调用过滤
Seccomp-BPF 是 eBPF 在安全领域的早期应用——在系统调用入口处过滤,限制进程可调用的系统调用集合。Docker/Kubernetes 的安全上下文正是基于 Seccomp-BPF:
// Seccomp-BPF 程序:只允许基本系统调用// 通过 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) 安装SEC("socket")int seccomp_filter(struct seccomp_data *ctx){ // ctx->nr 是系统调用号 // ctx->arch 是架构标识 // ctx->args[0..5] 是系统调用参数
switch (ctx->nr) { case __NR_read: case __NR_write: case __NR_openat: case __NR_close: case __NR_fstat: case __NR_mmap: case __NR_munmap: case __NR_brk: case __NR_exit_group: case __NR_clock_gettime: return SECCOMP_RET_ALLOW; // 允许
case __NR_socket: // 只允许 AF_INET 和 AF_INET6 if (ctx->args[0] == AF_INET || ctx->args[0] == AF_INET6) return SECCOMP_RET_ALLOW; return SECCOMP_RET_ERRNO | EAFNOSUPPORT;
default: // 其他系统调用:记录并拒绝 return SECCOMP_RET_ERRNO | ENOSYS; }}Seccomp-BPF 的局限在于只能过滤系统调用号和参数,无法跟踪调用序列或访问进程上下文。LSM BPF 弥补了这一缺口——它可以在安全检查点访问完整的内核对象(inode、socket、task),实现更细粒度的策略。
2.8 LSM BPF 审计模式
LSM BPF 程序可以工作在两种模式:审计模式(仅记录,返回 0 允许)和阻断模式(返回 -EPERM 拒绝)。审计模式是安全策略上线的必经阶段:
// 审计模式:记录但不阻止SEC("lsm/socket_connect")int BPF_PROG(audit_connect, struct socket *sock, struct sockaddr *address){ u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF; struct sockaddr_in *addr = (struct sockaddr_in *)address; u32 dst_ip = BPF_CORE_READ(addr, sin_addr.s_addr);
u32 *blocked = bpf_map_lookup_elem(&blocked_ips, &dst_ip); if (blocked && uid != *blocked) { // 审计模式:仅记录事件到 Ring Buffer struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0); if (e) { e->type = EVENT_BLOCKED_CONNECT; e->uid = uid; e->dst_ip = dst_ip; bpf_ringbuf_submit(e, 0); } // 审计模式:仍然允许 return 0; // 阻断模式:取消上面 return 0,改为: // return -EPERM; } return 0;}从审计模式切换到阻断模式,只需修改 eBPF 程序的返回值——无需修改策略逻辑或重新部署。建议审计模式至少运行 1-2 周,收集足够的事件样本后再切换。
三、Tetragon:eBPF 运行时安全
3.1 Tetragon 架构
Tetragon 是 Isovalent(Cilium 公司)开源的 eBPF 运行时安全监控工具:
3.2 Tetragon 的核心能力
| 能力 | 说明 |
|---|---|
| 进程执行监控 | 追踪 execve/fork/exit |
| 文件访问监控 | 追踪 open/read/write/close |
| 网络连接监控 | 追踪 connect/accept/bind |
| 系统调用过滤 | 基于 Seccomp-BPF |
| 内核模块监控 | 追踪模块加载/卸载 |
| 特权提升检测 | 追踪 capabilities 变化 |
| 容器安全 | 关联 K8s 元数据 |
| 实时响应 | 通过 LSM BPF 阻止恶意行为 |
3.3 Tetragon TracingPolicy
# Tetragon TracingPolicy 示例:监控所有进程执行apiVersion: cilium.io/v1alpha1kind: TracingPolicymetadata: name: monitor-process-execspec: kprobes: - call: "sys_execve" syscall: true args: - index: 0 type: "string" selectors: - matchNames: - namespace: "default" return: true returnArg: index: 0 type: "int"3.4 Tetragon 部署
# 使用 Helm 部署 Tetragonhelm repo add cilium https://helm.cilium.iohelm install tetragon cilium/tetragon -n kube-system
# 查看 Tetragon 日志kubectl logs -n kube-system -l app.kubernetes.io/name=tetragon
# 使用 tetragon CLI 查看事件kubectl exec -n kube-system tetragon-xxx -- tetra getevents3.5 Tetragon 实战:检测特权容器
apiVersion: cilium.io/v1alpha1kind: TracingPolicymetadata: name: detect-privileged-execspec: kprobes: - call: "cap_capable" args: - index: 1 type: "int" - index: 2 type: "int" - index: 3 type: "int" selectors: - matchArgs: - index: 2 operator: "Equal" values: - "21" # CAP_SYS_ADMIN四、eBPF 进程监控
4.1 进程生命周期追踪
#include "vmlinux.h"#include <bpf/bpf_helpers.h>
struct event { u32 pid; u32 ppid; char comm[16]; char filename[256]; u8 type; // 0=exec, 1=fork, 2=exit};
struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024);} events SEC(".maps");
// 追踪进程执行SEC("tracepoint/sched/sched_process_exec")int trace_exec(struct trace_event_raw_sched_process_template *ctx){ struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0); if (!e) return 0;
e->type = 0; e->pid = bpf_get_current_pid_tgid() >> 32; bpf_get_current_comm(&e->comm, sizeof(e->comm));
struct task_struct *task = (struct task_struct *)bpf_get_current_task(); e->ppid = BPF_CORE_READ(task, real_parent, pid);
bpf_ringbuf_submit(e, 0); return 0;}
// 追踪进程退出SEC("tracepoint/sched/sched_process_exit")int trace_exit(struct trace_event_raw_sched_process_template *ctx){ struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0); if (!e) return 0;
e->type = 2; e->pid = bpf_get_current_pid_tgid() >> 32; bpf_get_current_comm(&e->comm, sizeof(e->comm));
bpf_ringbuf_submit(e, 0); return 0;}
char LICENSE[] SEC("license") = "GPL";4.2 异常行为检测
| 检测场景 | eBPF Hook | 检测逻辑 |
|---|---|---|
| 反弹 Shell | tracepoint/sys_enter_execve | bash/nc 执行后发起网络连接 |
| 特权提升 | kprobe/cap_capable | CAP_SYS_ADMIN 获取 |
| 文件篡改 | tracepoint/sys_enter_openat | 敏感文件以写模式打开 |
| 异常网络 | tracepoint/sys_enter_connect | 未知目标 IP 连接 |
| 内核模块加载 | tracepoint/module_load | 非预期模块加载 |
| 容器逃逸 | LSM/bpf | 容器内使用 bpf() 系统调用 |
五、eBPF 安全最佳实践
5.1 纵深防御
5.2 安全原则
eBPF 安全不是银弹。它不能替代 SELinux/AppArmor,而是作为补充。正确的做法是纵深防御——多层安全机制协同工作,eBPF 提供实时的行为监控和快速响应能力。
- 最小权限:eBPF 程序本身也需要 CAP_BPF 权限,限制谁能加载 eBPF 程序
- 策略即代码:安全策略通过 TracingPolicy/YAML 管理,版本控制
- 渐进式部署:先审计模式(仅记录),再阻断模式(拒绝)
- 关联上下文:将 eBPF 事件与 K8s 元数据关联,精确定位问题 Pod
六、动手实践
6.1 使用 bpftrace 监控进程行为
# 追踪所有进程执行sudo bpftrace -e 'tracepoint:sched:sched_process_exec { printf("EXEC: pid=%d comm=%s\n", pid, comm);}'
# 追踪特权操作sudo bpftrace -e 'kprobe:cap_capable { if (arg2 == 21) // CAP_SYS_ADMIN printf("CAP_SYS_ADMIN: pid=%d comm=%s\n", pid, comm);}'
# 追踪网络连接sudo bpftrace -e 'tracepoint:syscalls:sys_enter_connect { printf("CONNECT: pid=%d comm=%s\n", pid, comm);}'6.2 编写 LSM BPF 程序
# 检查内核是否支持 LSM BPFcat /sys/kernel/security/lsm# 输出应包含 "bpf"
# 如果不包含,需要添加内核参数# GRUB_CMDLINE_LINUX="lsm=lockdown,yama,integrity,apparmor,bpf"6.3 部署 Tetragon
# 快速部署kubectl apply -f https://raw.githubusercontent.com/cilium/tetragon/main/install/kubernetes/tetragon.yaml
# 查看实时事件kubectl exec -n kube-system ds/tetragon -- tetra getevents -o compact七、本章小结
上一章理解了eBPF 网络全景。 本章详解了 eBPF 在安全领域的应用:
| 主题 | 核心要点 | 关键词 |
|---|---|---|
| LSM BPF | 在内核安全检查点挂载 eBPF 程序,实现可编程的安全策略 | LSM BPF |
| Tetragon | 基于 eBPF 的运行时安全监控,零侵入、实时检测 | Tetragon |
| 进程监控 | 追踪进程生命周期、检测异常行为 | 进程监控 |
| 纵深防御 | eBPF 安全与传统安全机制互补,而非替代 | 纵深防御 |
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时






