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

【Falco】规则语言与引擎:条件、优先级与异常

文章导航

分类入口
kubernetessecurity
标签入口
#falco#rules#rule-engine#libsinsp#exceptions#priority#v0.44.1

目录

第 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.yamlrules_filesrule_matching 注释。引擎求值在 libsinsp(falcosecurity/libs)。无真实节点则不粘贴伪造规则命中日志。


一、规则结构

官方规则文件是 YAML 列表,元素主要三类:RulesMacrosLists。规则条目必填键包括 rule(唯一短名)、condition(布尔过滤表达式)、descoutput(告警正文模板)、priority(严重级别)。可选键含 exceptionstagsappend 等。缺任一必填键时,加载阶段就会失败——这与「加载成功但永不命中」是两类事故,前者在第 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.nameproc.*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 风格级别:emergencyalertcriticalerrorwarningnoticeinformationaldebug(大小写不敏感)。它标定告警严重程度,供下游路由与 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)

站内对照(A/B)

学术谱系(A)


上一篇丢事件与缓冲

下一篇规则加载与 falcoctl

读完这篇,下一步读什么

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

2026-08-21 · kubernetes / security

Falco / 运行时检测:从双引擎驱动到规则引擎

补齐站内 Tetragon 排除树与产品对照之上的 Falco 检测内核:modern_ebpf 与 kmod 双引擎、libscap/libsinsp、规则引擎与输出,并以排障与相对 Tetragon/auditd/seccomp 的选型收束。

2026-08-21 · kubernetes / security

【Falco】libsinsp:状态富化与用户态进程树

钉清 libsinsp 如何用机器状态、线程/FD 表与用户态进程树富化 scap 事件;对照 Tetragon exec_id 的内核血缘差,并列出富化失败时规则条件「永远假」的表象。


By .