第 5 篇 把「无告警」从驱动缓冲与 drop 指标里拆开;本篇落到规则引擎轴:事件已经进了 libsinsp,为何仍不告警?难点不在背默认规则名,而在分清条件求值、优先级(严重级别)、异常白名单各自做了什么,以及字段空时条件如何静默为假。
值班里最常见的混因果是:看见 YAML
已挂载,就断定「规则层没问题」,然后在驱动或 SIEM
之间来回重启。五轴要求反过来——若 -L
能列出规则名,下一步应证明条件左侧字段非空且未被
exceptions 吞掉,而不是先怀疑
modern_ebpf。另一类混因果是把 priority
当成求值顺序旋钮:把级别调到 CRITICAL
并不能让后加载的细规则压过先加载的宽规则。
本文只写求值机制与失败模式,不写 MITRE 映射、不逐条翻译默认规则集。加载路径留给第 7 篇。读完应能回答:一次告警(或一次该有却没有的告警)在条件、优先级、异常三条语义上分别卡在哪。
本篇在系列中的位置
篇目 核心内容 第 5 篇 · 丢事件与缓冲 buf / drop / BPF iterators 第 6 篇 · 规则语言与引擎 条件、优先级、异常、失败表象 第 7 篇 · 规则加载与 falcoctl 默认集、远程、热加载边界 系列目录 关键问题、阅读路径、全部价值点
版本锚定:Falco 0.44.1(源码 tag 0.44.1)。规则语言叙述对齐官方 Rules / Condition Syntax / Rule Exceptions 与 tag
falco.yaml中rules_files、rule_matching注释。引擎求值在 libsinsp(falcosecurity/libs)。无真实节点则不粘贴伪造规则命中日志。
一、规则结构
官方规则文件是 YAML
列表,元素主要三类:Rules、Macros、Lists。规则条目必填键包括
rule(唯一短名)、condition(布尔过滤表达式)、desc、output(告警正文模板)、priority(严重级别)。可选键含
exceptions、tags、append
等。缺任一必填键时,加载阶段就会失败——这与「加载成功但永不命中」是两类事故,前者在第
7 篇的加载失败表里,后者留在本篇第五节。
Macros 把可复用的条件片段命名出来,避免把同一段
evt.type in (...) 复制进几十条规则。Lists
是值集合(进程名、路径前缀等),不能单独当作过滤表达式解析;它们必须被宏或条件引用。三者分工决定了「改一条规则」时该动条件、宏,还是环境白名单:改威胁语义动
condition;抽公共模式动
macro;只排除某镜像/某用户动 exceptions 或
list。
append: true
用于在已有规则或宏上追加条件/异常,而不是整条覆盖——这是运维层调参常用路径,但追加顺序仍受
rules_files 加载顺序约束(见第 7 篇)。后加载的
append
若写得过宽,等价于在引擎里静默扩白名单,值班时却仍以为「只是加了一条例外」。
- rule: Example Open Sensitive File
desc: Detect open of a sensitive path (illustrative only)
condition: evt.type in (open, openat) and fd.name startswith /etc/
output: "Sensitive path open (user=%user.name file=%fd.name)"
priority: WARNING
tags: [filesystem]上例只说明键位形状;生产规则必须经加载与字段可用性验证,不能凭片段宣称「已覆盖某 ATT&CK 技术」。本系列刻意不把默认规则集翻译成 MITRE 百科——规则名与 tag 字符串不是机制证明。
二、条件求值与字段
条件是对已富化事件的布尔表达式:比较用字段在左、值在右,用
and / or / not
与括号组合。官方 Condition Syntax
把条件写成「比较序列 + 逻辑连接」;括号决定优先级。syscall
规则通常以
evt.type(或宏)起头,再叠进程、FD、容器等字段类——先收窄事件类型,再谈上下文,既是可读性习惯,也减少对无关
syscall 做无效字段提取。
字段不是「写了就能比」。fd.name、proc.*、container.*
依赖 libsinsp
状态轴 与(可选)plugin。富化失败时,比较常表现为条件整体为假,表象是「规则
YAML 在、falco -L
能列名、生产无告警」——这与「规则文件没加载」同属规则轴症状,根因却在轴
3。排障时若只反复改 condition
里的字符串字面量,却从不核对字段表是否为空,会在错误层空转。
默认 rule_matching: first(tag
falco.yaml,Incubating):规则按文件定义顺序求值,第一条命中即停。可选
all
继续匹配同事件的其余规则,文档写明可能有性能代价,须实测后再上生产。注意:这里的「第一条」由加载顺序决定,不是由
priority 数值决定。first
适合「一条事件一条处置」的运维习惯;all
适合需要多标签并行告警的场景,但会放大输出面压力(见第 8
篇背压)。
flowchart TD
event["enriched event"] --> order["rules in load order"]
order --> cond["evaluate condition"]
cond -->|"false"| next["next rule or done"]
cond -->|"true"| exc["check exceptions"]
exc -->|"exception matches"| suppress["no alert"]
exc -->|"no exception"| alert["emit alert with priority"]
next --> cond
alert -->|"rule_matching first"| stop["stop further rules"]
alert -->|"rule_matching all"| next
图:一次事件在规则引擎内的求值顺序(英文节点)。priority
进入告警元数据;exceptions
在条件为真之后仍可吞掉告警。
三、优先级与异常
priority 取 Syslog
风格级别:emergency、alert、critical、error、warning、notice、informational、debug(大小写不敏感)。它标定告警严重程度,供下游路由与
syslog
优先级使用;不决定哪条规则先求值,也不覆盖其他规则。把
priority 从 WARNING 改成 CRITICAL,改变的是
SIEM 里的颜色与分页策略,不改变引擎里谁先匹配。
exceptions(自
0.28.0)是规则作者声明的白名单形状:fields /
comps / values
元组从事件取值,命中则不告警。官方 Rule
Exceptions
强调:例外的合法形状应由规则作者限定(例如允许「进程 +
目录」元组,不允许「仅进程名」),避免运维用过宽维度把检测掏空。官方还建议尽量同时约束
actor、action、target(例如进程 + 路径),避免只写
proc.name 或只写镜像名导致过宽。
常见误区:
| 误解 | 0.44.1 事实 |
|---|---|
priority: CRITICAL 的规则会压过
WARNING |
否;顺序由加载与 rule_matching 决定 |
用 and not 堆在 condition 里等于
exceptions |
语义可近似,但官方推荐用 exceptions
保持可读与可追加 |
| 异常只影响输出文案 | 否;命中异常则不生成告警 |
「优先级阴影」在本系列指:first
模式下更前的宽规则先命中,后面更具体的规则永不触发——调的是顺序与匹配模式,不是把
priority 调高。若两条规则都能匹配同一
execve,只看见第一条的名字,应先打印
rules_files 顺序与
rule_matching,而不是怀疑输出 sink。
四、引擎在 libsinsp 中的位置
五轴里,驱动与 libscap 只保证事件到达用户态;规则求值在 libsinsp。libs 分工:libscap 读驱动;libsinsp 维护机器状态、做过滤与输出衔接。Falco 守护进程加载 YAML 后,把编译后的条件交给该引擎,对每条富化事件求值。引擎不负责打开 modern_ebpf 会话,也不负责 HTTP sink 是否可达——那些失败域分别在轴 1–2 与轴 5。
这与 Tetragon 在内核 selector 内丢事件的路径不同:Falco 主路径是用户态可移植规则,代价是必须能区分「无原始事件」(轴 1–2)、「字段空导致条件假」(轴 3)与「异常吞掉」(本轴)。同一句「规则写了没告警」,在五轴上可能落在四个完全不同的格子;本篇只负责条件、优先级、异常这一格的可证伪说法。
学术谱系上,这仍落在 Garfinkel(NDSS 2003)讨论的用户态检查窗口一侧——规则再精,也改变不了「判定点在用户态」这一不变量(详见第 1 篇)。工业反例 CVE-2022-26316 证明过 argv 竞态窗口,展开对照在第 14 篇;这里只需记住:规则语言表达力 ≠ 内核 inline 阻断。
开写时若需钉源码符号,以 falcosecurity/libs 与 Falco 0.44.1 配套 tag 中规则引擎入口为准;本篇不伪造行号。
五、失败表象:条件永远假、异常过宽
| 表象 | 优先核对 | 勿先做 |
|---|---|---|
falco -L 有规则,生产无告警 |
条件字段是否被富化;evt.type 是否覆盖实际
syscall |
立刻重装 DaemonSet |
| 测试机命中、集群不命中 | container / k8s 字段是否空(轴 3、第 9 篇) | 只改 priority |
| 宽规则偶发命中、细规则永不触发 | rules_files 顺序与
rule_matching |
认定「引擎坏了」 |
| 已知恶意模式仍静默 | exceptions / append
是否过宽 |
先改 sink(那是轴 5) |
条件永远假:表达式语法合法,但左侧字段为空或类型不符,布尔结果恒假。证据在富化与
plugin,不在「规则文件丢失」。典型链路是:测试机无容器字段依赖
→ 条件为真;集群规则带 container.* →
插件未加载或套接字不可达 →
条件假。看起来像「环境差异导致规则失效」,机制上是轴 3
空洞。
异常过宽:主条件为真,但
exceptions
用镜像名或进程名单独放行,生产噪声被压掉的同时把真实行为一并吞掉。调参时应收紧元组维度,而不是关掉整条规则后宣称「环境干净」。append
叠加多份本地例外时,更要用「例外元组是否仍含
target」做代码评审,而不是只看 diff 行数。
开放争论(本篇不宣判胜负):用户态规则表达力与可移植性,对内核 selector 的检查窗口与过滤完整性——选型落到第 14–16 篇。本篇可交付的工程结论只有一句:先证明事件进了引擎且字段非空,再争论规则库够不够。
本篇也不写:默认规则集逐条翻译与 MITRE
全书、未跑过的命中样例、把 priority
当成求值顺序、规则仓库订阅菜谱。那些分别越界到百科、实验台账或第
7 / 14 / 16 篇。
参考资料
规范 / 官方文档 / 源码(A)
- Falco Rules;Condition Syntax;Rule Exceptions;Rule fields(与 0.44 文档树对齐的概念)
- Falco 0.44.1
falco.yaml:rules_files、rule_matching、watch_config_files注释 - falcosecurity/libs:libsinsp 规则求值与状态富化分工(Kernel Events Architecture)
站内对照(A/B)
- 第 1 篇 · 五轴;第 4 篇 · libsinsp;第 5 篇 · 丢事件
- PLAN.md §八、§九 · 06
学术谱系(A)
- Garfinkel, Traps and Pitfalls: Practical Problems in System Call Interposition Based Security Tools, NDSS 2003(用户态检查窗口;对照展开在第 14 篇)
上一篇:丢事件与缓冲
下一篇:规则加载与 falcoctl
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
Falco / 运行时检测:从双引擎驱动到规则引擎
补齐站内 Tetragon 排除树与产品对照之上的 Falco 检测内核:modern_ebpf 与 kmod 双引擎、libscap/libsinsp、规则引擎与输出,并以排障与相对 Tetragon/auditd/seccomp 的选型收束。
【Falco】运行时检测全景:缺口、五轴坐标系与 16 篇路线
相对 Tetragon 排除树、可观测对照与 linux/ebpf-security 快速启用清单,钉清 Falco 0.44.1 检测内核缺口;定义 Driver、libscap、libsinsp、规则引擎、输出与丢事件五条轴,并强调 modern_ebpf 与 kmod 分列证据包。
【Falco】libsinsp:状态富化与用户态进程树
钉清 libsinsp 如何用机器状态、线程/FD 表与用户态进程树富化 scap 事件;对照 Tetragon exec_id 的内核血缘差,并列出富化失败时规则条件「永远假」的表象。
【Falco】Plugin 框架:container / k8smeta 与 syscall 主路径
说明 Falco 0.44.1 plugin 框架如何扩展事件源与字段;钉 container / k8smeta 与 syscall 主路径的分工、字段合流,以及元数据空时规则静默不命中;不写第三方 plugin 百科。