Falco 以 Kubernetes 工具的身份为人所知,几乎每一份关于它的指南都是为集群写的。但它并不与集群绑定:它盯的是系统调用,而在一台带站点的普通服务器上它工作得一模一样。只不过几乎没人写这种情形。

而它有用之处恰恰在别的工具沉默的地方。站点上的一个 web shell 不违反任何权限、不产生失败登录,而如果是手写的,也不匹配任何特征。但它有一个对 Web 服务器来说不寻常的行为:PHP-FPM 进程启动了一个 shell。而这正是 Falco 看得见的。

它能感知什么

普通服务器上有代表性的事件:

  • 由 Web 服务器或 PHP 进程派生出的 shell——实际上就是 web shell 的明确信号;
  • /tmp/dev/shm/var/tmp 启动的程序;
  • 与之毫无关系的进程去读敏感文件(/etc/shadow、私钥);
  • 系统二进制文件的变化;
  • 本不该使用网络的进程发起的外发连接。

安装

关键的选择在安装时就要做:Falco 用什么方式获取系统调用。现代路线基于 eBPF,既不需要构建内核模块,也不需要内核头文件:

sudo falcoctl driver config --type modern_ebpf
sudo systemctl restart falco

经典的内核模块需要头文件,而且每次内核更新之后都要重新构建——而在一台更新自动安装的服务器上,这是服务反复死掉的原因。如果内核够新(5.8 及以上),就选 eBPF,然后把这个问题忘掉。

为了确认事件确实在来:

sudo systemctl status falco
sudo journalctl -u falco -n 50

噪声,以及怎样把它清掉

而这才是主要的工作。标准规则集偏向容器环境,而在一台普通服务器上它相当可观的一部分要么根本不适用,要么就在不停地触发。

随附的规则(/etc/falco/falco_rules.yaml)不去改动——更新时那个文件会被替换。你的改动放进 /etc/falco/falco_rules.local.yaml,不需要的规则也在那里关掉:

- rule: Terminal shell in container
  enabled: false

在没有容器的服务器上,通常需要调整的是:

  • 所有关于容器的规则——没有容器时它们只是在报告里占地方;
  • 「Write below etc」——每次安装软件包、以及你每次编辑配置文件时都会触发。它需要为 aptdpkgunattended-upgrades 加例外,否则事件会像洪水一样涌来;
  • 「Read sensitive file untrusted」——会在监控代理、备份工具以及 Lynis 之类的审计工具上触发;
  • 从临时目录启动——存在合理的例外:构建某个应用,或者某个自动化浏览器把驱动放在临时目录里打开。这类事件看着让人不安但能解释,而与其每次都从头想一遍,不如立刻为那个具体路径加上例外。

合理的顺序和任何别的检测工具一样:第一周只观察并添加例外,之后才把冒出来的事件当作信号。而规则很简单——如果报告里定期出现你不读的事件,那它就没为你做任何事。

事件该往哪里发

输出在 /etc/falco/falco.yaml 里配置:一个文件、系统日志,或者送往某个外部程序的数据流。而对一台服务器来说,一个文件加上随后的轮转就够了——别忘了轮转,事件文件也和其他日志一样会长大,而默认情况下没人看着它。

另外值得用优先级来做区分:严重的事件送到你会立刻看到的地方,其余的进通用日志留待日后再看。

Falco 和 auditd 不是一回事

两者都盯着系统调用,但目的不同。auditd 记录正在发生的事情,以便日后能把画面复原:它不评判任何东西、也不报告任何东西,它只是保存一份日志。而 Falco 在事件发生的那一刻套用规则并说「这看起来可疑」——也就是说,它给的是信号,而不是记录。

两个都留着是合理的:日志用来复原,信号用来反应。如果只能选一个,那么在事故之后最重要的是复原事件顺序的服务器上,auditd 更有用;而在需要关于正在运行的挖矿程序或 web shell 的早期信号的地方,则是 Falco。

它在小服务器上值不值得占位

诚实的答案是:并非总是。Falco 要处理系统调用,而在一台繁忙的机器上它对处理器的影响是感觉得到的。而如果服务器上只有一个站点,你既没有完整性监控也没有像样的自动更新,那就别从它开始。

它的时机来得晚一些——当基础工作都做完了,只剩下「服务器上到底在发生什么、而日志又没显示出来」这个问题的时候。而有一类事件它覆盖得比其余所有工具加起来还好:由 Web 服务器进程启动的那个 shell。按优先级和规则分开的事件是什么样子,见下面的演示页面。