从最高层来看,Falco的架构非常直接:通过在分布式基础设施上安装多个传感器来完成部署。每个传感器负责(从本地机器或者通过一些API)收集数据,然后运行一组规则,并在有问题发生时发出通知。图1-1简单展示了它的工作原理。
图1-1:Falco的高层架构
你可以将Falco想象成基础设施的安全摄像头网络:你将传感器放置在关键位置并观察正在发生的情况,如果检测到有害行为,它们会通知你。在Falco中,这些不好的行为由社区创建和维护的一组规则来定义,你可以根据需要定制或扩展这些规则。Falco传感器产生的警报理论上可以保留在本地机器中,但在具体实践中,它们通常被导出到集中式收集器。对于集中式警报收集,你可以使用通用的安全信息和事件管理(Security Information and Event Management,SIEM)工具,也可以使用像Falcosidekick这样的专用工具。我们将在第12章中详细介绍警报收集。
现在,让我们更深入地研究Falco的架构并探索它的核心组件,先从传感器开始吧。
图1-2展示了Falco传感器的工作模式。
图1-2:Falco传感器架构
传感器引擎接收两种输入:数据源和规则。传感器将规则应用于来自数据源的每个事件。当规则匹配事件时,将产生一条输出消息。
每个传感器能够从多个来源收集数据。最初,Falco专门设计用于收集系统调用,到目前为止,系统调用仍然是其最重要的数据源之一。我们会在第3章和第4章详细介绍系统调用,现在你可以把系统调用理解为正在运行的程序用来与外部世界交互的接口。打开或关闭文件、建立或接收网络连接、从磁盘或网络读写数据、执行命令、使用管道或其他类型的进程间通信与其他进程通信,这些都是使用系统调用的例子。
Falco通过测量Linux操作系统的内核来收集系统调用。它可以通过两种不同的方式实现这一点:部署内核模块(即可以安装在操作系统内核中以扩展内核功能的一段可执行代码)或使用eBPF技术(该技术可以在操作系统内部安全地运行脚本执行操作)。我们将在第4章详细讨论内核模块和eBPF。
利用这些数据,Falco可以发挥令人难以置信的作用:掌握基础设施中发生的一切。以下是Falco可以检测的一些示例:
· 权限升级。
· 访问敏感数据。
· 所有权更改和模式更改。
· 意外的网络连接或套接字突变。
· 异常的程序执行。
· 数据泄漏。
· 违反合规要求。
除了系统调用之外,Falco还扩展了其他数据源,本书后面的章节会给出一些示例。例如,Falco可以实时监控云上的日志,并在云基础设施中发生异常情况时发出通知。以下是一些示例:
· 用户登录时没有进行多重身份验证。
· 云服务的配置更改。
· 有人访问Amazon Web Services(AWS)S3存储桶中的敏感文件。
Falco会经常添加新的数据源,因此我们建议你访问官方网站( https://falco.org )和Slack频道( https://oreil.ly/Y4bUt )以了解最新内容。
规则会告诉Falco引擎如何处理来自数据源的数据。它们允许用户以紧凑和可读的格式定义策略。Falco预置了一套相对全面的规则,覆盖了主机、容器、Kubernetes和云安全,你也可以轻松创建自定义的规则。我们将会花大量篇幅来讨论规则,尤其是在第7章和第13章,相信读完本书后,你将成为这方面的大师。我们先看看下面这个示例:
上述规则会检测在容器内启动bash shell的情况,这个操作在基于容器的不可变基础设施中通常是不建议的。规则中的核心条目是条件(condition)和输出(output),前者告诉Falco要查看什么,后者是条件触发时Falco将告诉你的内容。可以看到,条件和输出都作用于某些字段(field),这是Falco的核心概念之一。条件是一个布尔表达式,结合了对字段和值的检查(本质上就是一个过滤器)。输出则是文本和字段名称的组合,它们的值将在通知中打印出来,语法类似于编程语言中的print语句。
你是否想到了tcpdump或Wireshark这样的网络工具?赞!它们就是Falco的一大灵感来源。
丰富的数据源和灵活的规则引擎帮助Falco成为强大的运行时安全工具。在这些基础之上,来自不同提供商的元数据丰富了它的检测。
当Falco告诉你发生了什么事情时(例如,系统文件被修改),你通常需要更多信息来了解问题的原因和范围。这是哪个进程造成的?是在容器里发生的吗?如果是,容器和镜像的名称是什么?发生这种情况的服务/命名空间是什么?是生产环境还是开发环境?是root用户做出的更改吗?
Falco的数据扩充引擎通过构建环境状态来解决这个问题,包括运行的进程和线程、它们打开的文件、它们运行的容器和Kubernetes对象等。Falco的规则和输出可以访问所有状态。例如,你可以轻松地确定规则的范围,使其仅在生产环境或特定服务中触发。
每次规则被触发时,相应的引擎都会发出输出通知。一个最简单的配置就是引擎将通知写入标准输出(通常没有实际作用)。幸运的是,Falco提供了丰富的方式将通知路由到指定位置,包括日志收集工具、云存储服务(例如,S3)以及像Slack和电子邮件这样的通信工具。这里先提一下整个生态体系中非常重要的Falcosidekick项目,它被专门设计用于连接Falco与外部世界,让输出变得更加轻松(更多信息请参见第12章)。
Falco是为现代云原生应用程序设计的,因此它对容器、Kubernetes和云环境有着出色的、开箱即用的支持。由于本书是关于云原生安全的,因此我们将重点关注这部分内容。但需要注意的是,Falco并不局限于运行在云端的容器和Kubernetes,你完全可以使用它作为主机安全工具,许多预置规则都可以帮助保护你的Linux服务器。Falco对网络检测也有很好的支持,可以检查连接、IP地址、端口、客户端和服务器的活动,并在它们显示有问题或发生意外/异常行为时发出警报。
现在你已经看到Falco可以做什么,接下来让我们来谈谈为什么它是这样设计的。当你开发一个非常复杂的软件时,关注正确的应用场景并优先考虑核心目标是极其重要的。有时这意味着你要接受取舍。Falco也不例外,它的发展遵循一套核心原则。在本节中,我们将探讨为什么是这些原则以及它们各自如何影响Falco的架构和特性。理解这些原则可以帮助你判断Falco是否适合你的应用场景,并帮助你更加充分地使用它。
Falco引擎旨在为运行中的服务和应用程序检测威胁。当它检测到异常行为时,Falco应该立即提醒你(最多在几秒内),这样你就能立即得到通知并做出响应,而不是在几分钟或几小时后才意识到问题。
这个设计原则体现在三个重要的架构选择上。第一,Falco被设计为一个流处理引擎,能够在数据到达时快速处理数据,而不是先存储数据然后再处理。第二,它被设计为独立评估每个事件,而不是根据事件序列生成警报,这意味着将不同的事件关联起来(即使是可行的)不是Falco的主要目标(也不鼓励这么做)。第三,Falco评估规则时尽可能贴近数据源。如果可能的话,它会避免在处理信息之前传输信息,而是倾向于在端点处部署更丰富的引擎。
你可以在任何环境中部署Falco,包括需要稳定性和低额外开销的生产环境。不能因为它使得应用程序崩溃,而是应该尽最大可能减小对应用程序的影响。
这种设计原则会影响数据收集架构,特别是当Falco运行在具有许多进程或容器的端点上时。Falco的驱动程序(内核模块和eBPF探针)经历了多轮迭代和多年测试,以保证其性能和稳定性。通过操作系统的内核来收集数据,而不是监控进程/容器,可以确保你的应用程序不会因为Falco中的Bug而崩溃。
Falco引擎是用C++编写的,并采用了许多方法来减少资源消耗。例如,它会避免处理像读写磁盘或网络数据这样的系统调用。在某种程度上,这其实是一种限制,因为它阻止用户创建检查负载内容的规则,但它也确保了CPU和内存消耗保持在较低水平,这是更为重要的。
Falco旨在观察应用程序的行为,而不需要用户重新编译应用程序、安装库或者重新构建带有监控钩子(hook)的容器。这在现代容器化环境中非常重要,因为在这些环境中,对每个组件进行更改将需要大量不切实际的工作。它也保证了Falco可以看到每个进程和容器,无论它们来自哪里、谁运行或者运行了多长时间。
与其他策略引擎(例如,OPA)相比,Falco在设计时明确考虑了分布式、多传感器架构。它的传感器被设计为轻量、高效和便携,可以在不同的环境中运行。它可以部署在物理机、虚拟机或容器中。Falco二进制文件可用于多种平台,包括ARM。
目前市面上大多数威胁检测产品都是基于将大量事件发送到一个集中式SIEM工具,然后再分析收集的数据。Falco则是围绕一个完全不同的原则设计的:尽可能地靠近端点执行检测,并且只向集中式收集器发送警报。这种方法导致解决方案在执行复杂分析方面的能力有所下降,但其操作简单、成本效益更高,并且可以很好地横向扩展(或称水平扩展)。
说到规模,Falco的另一个重要设计目标是它应该能够扩展以支持世界上最大的基础设施环境。如果你能运行它,Falco就应该能保护它。正如我们刚刚描述的,保持有限的状态和避免集中存储是其中的重要元素。边缘计算也是一个重要的元素,因为分布式规则评估是真正以水平方式扩展Falco等工具的唯一方法。
可伸缩性的另一个关键部分是端点检测。Falco的数据收集栈没有使用sidecar(边车)、库链接或进程检测等技术。原因是所有这些技术的资源利用率都随着要监控的容器、库或进程的数量增加而增长。一台忙碌的主机有太多的容器、库和进程,以至于上述技术无法施展,但它们有且只有一个操作系统内核。在内核中捕获系统调用意味着,无论主机规模有多大,每台主机都只需要部署一个Falco传感器,这使得Falco可以在具有大量活动的大型主机上运行。
使用系统调用作为数据源还有哪些好处呢?答案是系统调用永远不会说谎。你很难跳过Falco,因为它用来收集数据的机制很难被禁用或规避。即使你试图逃避或绕开它,仍然会留下Falco可以捕捉到的痕迹。
另一个关键的设计目标是最小化用户在Falco中获得价值所花费的时间。直接安装Falco无须额外配置就可以带来出色的效果,除非你有更高的要求,否则一般不需要定制。
与此同时,如果你确实需要定制,Falco也提供了灵活性。例如,你可以通过丰富和清晰的语法创建新规则,开发和部署扩展检测范围的新数据源,并将Falco与所需的通知和事件收集工具集成。
简洁性是Falco的最后一个架构设计原则,同时也是最重要的一个。Falco规则的语法设计紧凑、易读,可以快速上手。Falco规则的条件都尽可能地放在一行中。所有人(不一定是专家)都能够轻松地编写新规则或修改现有规则。如果这降低了语法的表达能力也没关系,因为Falco的目标是提供高效的安全规则引擎,而不是完整的领域特定语言,这方面还有其他更好的工具。
简洁性也体现在扩展Falco新数据源和集成新的云服务或容器类型的过程中,无论使用哪种语言(包括Go、C和C++)编写插件。Falco很容易加载这些插件,你可以使用它们来添加对新数据源或规则中使用的新字段的支持。