中国红客联盟 首页 资讯 国内安全 查看内容

Falco 云原生安全实践指南(二)

2025-3-3 10:39| 发布者: Honkers| 查看: 299| 评论: 0

摘要: 原文:zh.annas-archive.org/md5/901f31c65e11db9dd25e51adeba7505a 译者:飞龙 协议:CC BY-NC-SA 4.0 第八章:输出框架 在前几章中,你学到了 Falco 如何收集事件(

原文:zh.annas-archive.org/md5/901f31c65e11db9dd25e51adeba7505a

译者:飞龙

协议:CC BY-NC-SA 4.0

第八章:输出框架

在前几章中,你学到了 Falco 如何收集事件(其输入)以及如何处理它们以使你能够接收重要的安全通知(其输出)。在这个处理管道的最后,Falco 的一个关键部分——输出框架——使其能够将这些通知(也称为警报)传递到正确的位置。我们将其称为框架,因为其模块化设计提供了你需要的一切,可以将通知传递到任何你希望的目的地。在本章中,你将学习输出框架的工作原理以及如何配置和扩展它。

Falco 的输出架构

输出框架是本书这部分描述的事件处理管道的最后一部分。Falco 的用户空间程序在内部实现了核心机制,但外部工具可以扩展它。它的工作是及时将通知传递到正确的目的地。每当上游事件(由驱动程序、插件或任何 Falco 支持的其他输入源产生)满足规则条件时,规则引擎会要求输出框架向下游消费者发送通知,这可以是环境中的任何其他程序或系统(或仅仅是你自己)。

传送警报的过程涉及两个不同的阶段,如图 8-1 所示。

在第一阶段中,处理程序接收事件数据和事件触发规则的信息。它使用提供的信息准备通知,并根据规则的output键格式化文本表示。然后,为了防止输出目的地阻塞运行在主执行线程中的处理管道,处理程序将通知推入并发队列中^(1)。推送操作是非阻塞的,因此处理管道无需等待通知消费者拉取通知;它可以继续执行其工作而不受干扰。事实上,Falco 需要尽快执行这个阶段,以便处理管道可以处理下一个事件。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_0801.png

图 8-1。Falco 中传送通知的两个阶段

在队列的另一端,等待弹出通知的输出工作者(运行在单独的执行线程中)。这时第二阶段开始。一旦输出工作者收到通知,它立即将该通知扩散到所有配置的输出通道。输出通道(或简称输出)是输出框架的一部分,允许 Falco 将警报转发到目的地。每个输出通道实现了通知特定类别的警报消费者的实际逻辑。例如,一些消费者希望将通知写入文件,而其他人则更喜欢将其发布到 Web 终端点(参见第十章)。

这种两阶段方法允许处理管道在不受输出传递过程干扰的情况下运行。但是,传递可能仍会出现问题。特别是,当传递通知涉及 I/O 操作时,这些操作可能会暂时阻塞调用者(例如,在网络减速时)或无限期阻塞(例如,在目标磁盘上没有剩余空间时)。两个阶段之间的队列非常擅长吸收临时减速,以至于您甚至都不会注意到(默认情况下,Falco 可以在队列中积累未决通知达到两秒)。但是,当通知的接收者长时间(或无限期)阻塞时,Falco 无法自动执行任何操作。作为最后的手段,它会尝试通过记录到标准错误流(stderr)通知您发生了什么。当这种情况发生时,通常是配置错误的症状(例如,目标路径错误)或资源不足(目标中没有剩余空间),用户需要手动修复。

一旦通知传递过程完成,Falco 的用户空间程序已经完成了其目的。接下来由消费者决定如何处理警报。

输出框架适用于许多不同的用例,并且可以处理许多可能的问题。它还足够灵活,可以让您以各种方式和到不同目的地接收通知。本章的其余部分将详细介绍所有可用的可能性。我们还将快速查看一些其他工具,这些工具允许您在将通知传递到最终目的地之前进一步扩展输出处理(我们将在第十三章深入讨论这个问题)。

输出格式化

在通知传递的第一阶段,Falco 会在转发到输出通道之前对通知应用格式化。您可以自定义 Falco 向其消费者呈现通知的方式,以便轻松集成到您的具体用例中。

Falco 配置文件(/etc/falco/falco.yaml)中有两个选项控制此操作。第一个控制时间戳的格式化:

[code]time_format_iso_8601: false [/code]

如果此选项为false(默认值),Falco 将根据*/etc/localtime*的设置显示日期和时间。如果为true(当 Falco 在容器中运行时的默认值),Falco 将使用 ISO 8601 标准表示日期和时间。请注意,此选项不仅控制输出通知,还包括 Falco 记录的任何其他消息。

第二个选项实际上是一组选项,用于启用通知的 JSON 格式化。默认情况下,禁用了 JSON 格式化:

[code]json_output: false [/code]

使用此设置,Falco 将通知格式化为纯文本字符串(包括时间戳、严重性和消息)。如果设置为true,Falco 将通知封装在 JSON 格式的字符串中,包括多个字段。以下两个选项允许您包含或排除输出中的某些字段:

json_include_output_property: true

如果启用此选项(默认情况下是启用的),你仍然可以在 JSON 对象的output字段中找到通知的纯文本表示。如果不需要,可以禁用此选项以节省一些字节。

json_include_tags_property: true

如果启用此选项,您将在 JSON 对象中找到一个tags字段,其中包含匹配规则中指定的标签数组。未定义标签的规则在输出中将具有空数组(tags:[])。如果禁用此选项,您将无法在 JSON 对象中获取tags字段。

注意

尽管名字是json_output,但它并不是一个输出通道。json_output配置控制处理第一阶段的通知格式化,因此它会影响通道传递的通知内容。接下来的部分描述了可用的输出通道。

输出通道

Falco 提供了六种内置输出通道,列在 Table 8-1 中。我们将在接下来的子章节中更详细地描述每一种。默认情况下仅启用了两个通道——标准输出和 syslog 输出——但 Falco 允许您同时启用多个通道。

Table 8-1. Falco 的内置输出通道

通道描述
标准输出将通知发送到 Falco 的标准输出(stdout)
Syslog 输出通过 syslog 发送通知到系统
文件输出将通知写入文件
程序输出将通知发送到程序的标准输入
HTTP 输出将通知发布到 URL
gRPC 输出允许客户端程序通过 gRPC API 消费通知

您可以在 Falco 配置文件(/etc/falco/falco.yaml)中配置这些输出。请注意,本节中的所有配置片段都是该文件的一部分。

每个输出通道至少有一个名为enabled的选项,可以是true或false。其他特定输出可能有其他选项(你很快会发现)。此外,还有一些全局选项可以影响所有或部分输出通道的功能。其中一个选项(你在上一节看到的)是json_output;当启用时,警报消息将以 JSON 格式呈现,无论使用的输出通道是哪种。可以影响输出通道行为的其他全局选项列在 Table 8-2 中。

Table 8-2. 输出通道的全局选项

全局选项(带默认值)描述
buffered_outputs: false此选项启用或禁用输出通道的完全缓冲。当禁用时,Falco 在每次警报时立即刷新输出缓冲区,这可能会导致更高的 CPU 使用率,但在将输出导入另一个进程或脚本时非常有用。除非您遇到默认值的问题,通常不需要启用此选项。请注意,Falco 的--unbuffered命令行标志可以覆盖此选项。并非所有输出通道都遵循此全局选项。某些输出通道可能实现了您无法禁用的特定缓冲策略。
output_timeout: 2000此选项的值指定在超过传递通知截止时间之前等待的持续时间(以毫秒为单位)。当通知消费者阻塞且输出通道无法在给定的截止时间内传递警报时,Falco 将报告一个错误,指示哪个输出正在阻止通知。这样的错误表明消费者中存在配置错误或 I/O 问题,Falco 无法恢复。

| outputs: rate: 1

max_burst: 1000 | 这些选项控制通知速率限制器,以防止输出通道淹没其目标。速率限制器实现了令牌桶算法。要发送通知,系统必须从桶中移除一个令牌。rate设置系统每秒获取的令牌数,max_burst设置桶中的最大令牌数。使用默认设置,Falco 可以连续发送高达 1,000 个通知;然后,必须等待将令牌添加到桶中,该过程以每秒 1 个令牌的速率进行。换句话说,一旦桶被清空,通知的发送速率限制为每秒一个。 |

提示

尽管与输出机制不严格相关,Falco 的其他设置可能会影响您在输出中收到的内容。例如,配置priority: *<severity>*控制要加载和运行的最小规则优先级级别,命令行选项-t *<tag>*允许您仅加载具有特定标签的规则。在这些情况下,显然,您将不会收到 Falco 未加载规则相关的任何输出。一般来说,任何与规则相关的选项或配置都可能间接影响输出。

现在您已经了解了输出通道及其行为可能发生变化的设置,让我们依次进行详细说明。

标准输出

标准输出(配置文件中的stdout_output,默认情况下启用)是 Falco 最直接的输出通道。启用时,Falco 将为每个警报在标准输出打印一行。这允许您在从控制台手动运行 Falco 或查看容器或 Kubernetes Pod 日志时查看警报通知。此输出通道唯一的特定可用选项是enabled(可以是true或false)。但是,它也受全局缓冲选项buffered_outputs的影响。当输出被缓冲时,stdout 流将完全缓冲或在流是交互设备(如 TTY)时进行行缓冲。

Syslog 输出

syslog 输出通道(配置文件中的syslog_output,默认情况下也启用)允许 Falco 为每个警报发送一个 syslog 消息。与标准输出类似,该输出通道唯一的可用选项是enabled(可以是true或false)。启用时,Falco 会使用LOG_USER^(2)设施和由规则定义的优先级值作为严重级别发送消息到 syslog。

根据您使用的 syslog 守护程序,您可以使用类似于tail -f /var/log/syslog或journalctl -xe的命令读取这些消息。实际的消息格式也取决于 syslog 守护程序。

文件输出

如果启用文件输出,Falco 将每个警报写入一个文件。此输出通道的默认配置为:

[code]file_output: enabled: false keep_alive: false filename: ./events.txt [/code]

filename选项允许您指定 Falco 将写入的目标文件。如果文件尚不存在,则会创建该文件,如果文件已存在,则不会尝试截断或旋转该文件。

如果禁用keep_alive(默认情况),Falco 将为每个警报打开文件进行追加写入,然后关闭文件。如果将keep_alive设置为true,Falco 将仅在第一个警报之前打开文件一次,并将保持打开状态以处理所有后续警报。无论keep_alive是否启用,Falco 在接收到SIGUSR1信号时关闭并重新打开文件。如果您想要使用程序来旋转输出文件(例如logrotate),这个特性非常方便。

最后,除非禁用全局缓冲选项,否则写入文件通常会进行缓冲。关闭文件将刷新缓冲区。

程序输出

程序输出与文件输出非常相似,但在这种情况下,Falco 将每个警报的内容写入到配置文件中指定的程序的标准输入中。此输出通道的默认配置为:

[code]program_output: enabled: false keep_alive: false program: > jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services... [/code]

program字段允许您指定将警报发送到的程序。Falco 通过 shell 运行程序,因此您可以在将消息传递到程序之前指定任何处理步骤的命令管道。该字段的默认值显示了其用法的一个很好的例子:当执行时,这个单行程序将警报发布到 Slack webhook 端点。(然而,使用 Falcosidekick 会是一个更好的选择;请参阅第十二章。)

如果将keep_alive设置为false,Falco 在每次有通知需要传递时都会重新启动程序,并将警报内容写入其标准输入。如果将keep_alive设置为true,Falco 会在发送第一个警报之前启动程序一次,并保持程序管道开放以传递后续警报。

当接收到SIGUSR1信号时,Falco 关闭并重新打开程序。然而,该程序与 Falco 运行在同一个进程组中,因此它会接收到 Falco 接收到的所有信号。如果需要,您可以覆盖程序信号处理程序。

缓冲通过全局选项支持。当 Falco 关闭程序时,它也会刷新缓冲区。

HTTP 输出

当您需要通过 HTTP(S)连接发送警报时,最好的选择是使用 HTTP 输出。其默认配置非常简单:

[code]http_output: enabled: false url: http://some.url [/code]

一旦启用,您需要指定的唯一其他配置是您端点的url。Falco 将为每个警报向指定的 URL 发起 HTTP POST 请求。支持未加密的 HTTP 和安全的 HTTPS 端点。该输出通道始终启用缓冲(即使您禁用了全局缓冲选项)。

当您使用 Falcosidekick 时,首选 HTTP 输出通道;它以扇出方式将 Falco 的警报转发到许多不同的目的地(目前支持 50 多个)。如果您希望 Falco 将警报转发到 Falcosidekick,请应用此 Falco 配置:

[code]json_output: true json_include_output_property: true http_output: enabled: true url: "http://localhost:2801/" [/code]

请注意,此配置假定您已经运行并配置了 Falcosidekick 来监听localhost:2801;如果您的设置不同,请相应更改。您可以在第十二章以及其在线文档中找到有关配置 Falcosidekick 的详细信息。

gRPC 输出

gRPC输出是最复杂的输出通道。与其他通道相比,它允许更大的控制权,可以完全控制所接收的信息。如果您希望将警报发送到通过 Falco 的 gRPC API 连接的外部程序,则可以选择此输出通道。其默认配置为:

[code]grpc_output: enabled: false [/code]

如您所见,默认情况下它是禁用的——在您启用它之前,有一些事情您应该考虑。Falco 自带一个暴露 API 的 gRPC 服务器。您需要同时启用 gRPC 服务器和 gRPC 输出(我们稍后会向您展示如何操作)。该 API 提供了多个 gRPC 服务,其中只有一些与 gRPC 输出相关。一个服务允许您获取所有待处理的警报,另一个服务允许您订阅警报流。客户端程序可以决定哪种实现最适合其需求。在两种情况下,当启用 gRPC 输出时,Falco 使用内部队列暂时存储警报,直到客户端程序消费它们。这意味着如果没有设置好客户端程序来消费警报,则不应启用 gRPC 输出;否则,内部队列可能会无限增长。全局缓冲选项不会影响此输出通道。

有了这些,为了使此输出通道正常工作,您首先必须启用 gRPC 服务器。它支持两种绑定类型:在 Unix socket 上和在具有强制性双向 TLS 认证的网络上。

下面是如何在 Unix socket 上启用 gRPC 服务器:

[code]grpc: enabled: true bind_address: "unix:///var/run/falco.sock" threadiness: 0 [/code]

以及如何在网络上启用具有强制性双向 TLS 认证的 gRPC 服务器:

[code]grpc: enabled: true bind_address: "0.0.0.0:5060" threadiness: 0 private_key: "/etc/falco/certs/server.key" cert_chain: "/etc/falco/certs/server.crt" root_certs: "/etc/falco/certs/ca.crt" [/code]

两种绑定类型都提供相同的 gRPC 功能,因此您可以选择满足您需求的那一种。一旦启用了 gRPC 服务器,下一步是启用 gRPC 输出:

[code]grpc_output: enabled: true [/code]

最后,您将需要配置您的客户端程序以连接到 Falco gRPC API。如何完成这一步取决于您使用的程序。Falcosecurity 组织提供了两个可以连接到此输出的程序(参见 第二章):falco-exporter,它连接到 Falco gRPC API 以导出 Prometheus 可消耗的指标(更多信息请参阅 第十二章),以及 event-generator,它可以选择连接到 Falco gRPC API,以测试是否实际处理了虚假事件(在开发集成测试时很有帮助)。您也可以实现自己的程序。Falcosecurity 组织提供了 SDK,允许您轻松地使用多种编程语言为 Falco 创建 gRPC 客户端程序,例如 Golang 的 client-go,Rust 的 client-rs 和 Python 的 client-py。您可以在 第十四章 中找到关于使用 Falco gRPC API 进行开发的更多信息。

最后,这是 Falco 通过 gRCP API 发送的消息的 proto 定义摘录:

[code]// The `response` message is the representation of the output model. // It contains all the elements that Falco emits in an output along // with the definitions for priorities and source. message response { google.protobuf.Timestamp time = 1; falco.schema.priority priority = 2; falco.schema.source source_deprecated = 3 [deprecated=true]; string rule = 4; string output = 5; map<string, string> output_fields = 6; string hostname = 7; repeated string tags = 8; string source = 9; } [/code]

response 消息包括已经格式化的警报字符串(您将在 output 字段中找到)以及所有组件信息,这些信息分布在各种字段中。客户端程序可以根据需要组装和处理它们,这在您希望在 Falco 之上构建自己的应用程序时非常有用。

其他日志选项

到目前为止,我们已经描述了输出框架的核心部分。现在让我们看看一些帮助您进行故障排除的选项。与大多数应用程序一样,Falco 可以输出调试信息和错误。这些信息性的消息涉及到 Falco 本身的功能,而不是其主要输出。

Falco 在内部实现了各种日志消息。它们可能会随着不同的发布版本而有所变化。一个常见的例子是 Falco 启动时打印的初始信息。另一个不太常见的情况是当 Falco 通知您无法加载驱动时:

[code]Mon Dec 20 14:00:23 2021: Unable to load the driver. [/code]

术语 logging 不涉及输出安全通知的过程。本节讨论的日志消息不是安全警报。日志选项不以任何方式影响通知处理。此外,由于这些日志消息不是通知,因此 Falco 不会通过输出渠道输出它们。尽管在终端中运行 Falco 时可能会看到通常的通知与日志消息交织在一起,但请记住它们是不同的。

Falco 通过 标准错误流 输出这些消息,并将它们发送到 syslog。您可以配置 Falco 根据其严重性级别丢弃某些消息。表 8-3 列出了您可以在 Falco 配置文件(/etc/falco/falco.yaml)中配置的日志选项。

表 8-3. Falco 内部日志选项

日志选项(带默认值)描述
log_stderr: true如果启用,Falco 将日志消息发送到 stderr。
log_syslog: true如果启用,Falco 将日志消息发送到 syslog。请注意,此选项与 syslog 输出无关,也不会影响它。
log_level: info此选项定义要包含在日志中的最低日志级别:emergency、alert、critical、error、warning、notice、info 或 debug。请注意,尽管这些值相似,但它们不是规则优先级级别。

结论

本章结束了本书的 第二部分。在这一点上,您应该对 Falco 的架构及其内部工作原理有一个扎实的理解。您对处理管道数据流的熟悉,以输出框架结束,将允许您以多种方式使用 Falco。例如,您可以在喜爱的仪表板中查看安全通知,甚至在 Falco 之上创建响应引擎(在特定事件发生时采取行动的机制)。要发现更多用例,请发挥您的想象力,并继续阅读本书。

接下来是真实的使用案例,所以第 III 部分 是关于在生产环境中运行 Falco 的内容。像往常一样,我们会指导您完成每一步。

^(1) 并发队列 是实现多个运行线程可以安全并行访问的一种 队列数据结构。poppush 操作是队列支持的典型操作(分别用于入队和出队)。大多数实现允许以阻塞或非阻塞方式执行这些操作。

^(2) 在 syslog 协议中,设施值确定创建消息的进程的功能。LOG_USER 用于用户级应用程序生成的消息。

第三部分:在生产环境中运行 Falco

第九章:安装 Falco

欢迎来到本书的第三部分,本部分将指导您如何在实际环境中使用 Falco。现在您已了解 Falco 及其架构的工作原理,下一步是开始使用它来保护您的应用程序和系统。在本章中,您将学习在生产环境中安装 Falco 所需的知识。我们将展示不同的场景和常见的最佳实践,以便您找到适合您用例的正确指导。

首先,我们将为您提供常见使用场景的概述,然后我们将为每种场景描述不同的安装方法。我们强烈建议您阅读所有安装方法的相关内容,即使您只需要其中的一部分,也能全面了解可能性并选择最适合您需求的方法。

选择您的设置

Falco 项目正式支持三种在生产环境中运行 Falco 的方式:

  • 直接在主机上运行 Falco

  • 在容器中运行 Falco

  • 将 Falco 部署到 Kubernetes 集群

每个选项都有不同的安装方法,第一个选项与其他选项之间有一些重要的区别。在您的环境中不包含容器运行时或 Kubernetes 时,直接在主机上安装 Falco 是唯一的选择。这也是运行 Falco 最安全的方式,因为它与容器系统隔离(因此在受损情况下难以侵入)。然而,直接在主机上安装 Falco 通常是最难维护的解决方案。它也不总是可能的(例如,当您的应用程序在托管的 Kubernetes 集群中运行且您无法完全访问主机时)。其他选项通常更直接且更易于管理。特别是如果您的应用程序在 Kubernetes 集群上运行,将 Falco 部署到 Kubernetes 是一个常见的选择。在做出选择之前,请考虑每种选择的利弊以及您的需求。

在使用任何这些方法安装 Falco 之前,您需要决定如何使用 Falco,这会对安装过程和配置产生重要影响。最常见的两种场景是监控系统调用和使用插件提供的数据源。

默认情况是在系统上部署 Falco 传感器以监控系统调用。在这种情况下,您将需要在每台机器或集群节点上部署一个 Falco 传感器,并在每个底层主机上安装驱动程序。

当您使用插件提供的数据源时,您可能只需要安装一个 Falco 传感器(或每个事件生成器一个),并且不需要驱动程序。虽然每个数据源的实际设置可能略有不同,但为简单起见,我们可以将其视为单一安装场景,因为整体过程非常相似。通常,后一种情况的要求较少,实施起来更简单。

如果您需要同时满足多个场景,则需要更多的 Falco 安装。然后,您可以通过使用其他工具(如 Falcosidekick,在 第十二章 中讨论)来汇总来自每个传感器的通知。

您的最终设置将取决于您的需求和选择。以下部分为上述两种情况(监视系统调用和使用插件提供的数据源)中的每种安装方法提供了说明。

直接在主机上安装

直接在主机上安装 Falco 是一项简单的任务——您在 第二章 中已了解了关键方面。此安装方法主要用于 Falco 使用系统调用来安全监控系统的默认情况,因此它还会安装驱动程序并配置 Falco 以使用它。(在 第十章 中,我们将讨论如何更改 Falco 配置并为其他数据源设置它。)

此方法将安装以下内容:

  • 用户空间程序 falco

  • 驱动程序(默认情况下的内核模块)

  • 默认配置文件和位于 /etc/falco 中的默认规则集文件

  • falco-driver-loader 实用程序(您可以使用此工具来管理驱动程序)

  • 一些捆绑插件(这些可能因版本而异)

要安装 Falco,您将使用 Falco 的“下载”页面提供的以下工件 之一:

  • .rpm

  • .deb

  • .tar.gz(二进制)包

如果您打算通过兼容的软件包管理器安装 Falco,则应使用前两个软件包之一;否则,请使用二进制软件包。继续阅读获取更多详细信息。

注意

下面的小节包括您需要在系统上运行的各种命令。确保您有足够的权限来执行它们(例如,使用 sudo)。

使用软件包管理器

此安装方法适用于支持 .deb.rpm 包的 Linux 发行版。.deb.rpm 包的设置过程还将安装一个 systemd 单元,以便在您的系统上将 Falco 作为服务使用,并通过动态内核模块支持(dkms)安装内核模块——默认驱动程序。

aptyum 是最流行的软件包管理器,分别允许安装 .deb.rpm 包。如果您使用支持 .deb.rpm 包的不同软件包管理器,安装过程将非常类似,尽管确切的说明可能会有所不同。请参阅其文档以获取更多详细信息。

使用 apt(.deb 包)

apt 是 Debian 及基于 Debian 的发行版(如 Ubuntu)的默认软件包管理器。它允许您安装分布为 .deb 包的软件应用程序。要使用 apt 安装 Falco,您首先需要信任 Falco 项目的 GPG 密钥 并配置包含 Falco 包的 apt 仓库:

[code]$ curl -s https://falco.org/repo/falcosecurity-3672BA8F.asc | apt-key add - $ echo "deb https://download.falco.org/packages/deb stable main" | tee \ -a /etc/apt/sources.list.d/falcosecurity.list [/code]

然后更新 apt 软件包列表:

[code]$ apt-get update -y [/code]

由于此安装方法还将安装 Falco 的内核模块,您必须首先安装 Linux 内核头文件:

[code]$ apt-get -y install linux-headers-$(uname -r) [/code]

最后,安装 Falco:

[code]$ apt-get install -y falco [/code]

使用 yum(.rpm 软件包)

yum 是用于使用 RPM 软件包管理器的 Linux 发行版的命令行实用程序,例如 CentOS、RHEL、Fedora 和 Amazon Linux。它允许您安装分布为 .rpm 软件包的软件应用程序。在使用 yum 安装 Falco 之前,您必须确保系统上存在 make 包和 dkms 包。您可以通过运行以下命令检查:

[code]$ yum list make dkms [/code]

如果不存在,请安装它们:

[code]$ yum install epel-release $ yum install make dkms [/code]

接下来,信任 Falco 项目的 GPG 密钥 并配置保存 Falco 软件包的 RPM 仓库:

[code]$ rpm --import https://falco.org/repo/falcosecurity-3672BA8F.asc $ curl -s -o /etc/yum.repos.d/falcosecurity.repo \ https://falco.org/repo/falcosecurity-rpm.repo [/code]

由于此安装方法还将安装 Falco 的内核模块,您必须首先安装 Linux 内核头文件:

[code]$ yum -y install kernel-devel-$(uname -r) [/code]
提示

如果 yum -y install kernel-devel-$(uname -r) 没有找到内核头文件包,请运行 yum distro-sync 然后重启系统。重启后,再次尝试上述命令。

最后,安装 Falco:

[code]$ yum -y install falco [/code]

完成安装

现在,您应该已经通过 dkms 安装了内核模块,并安装了一个 systemd 单元以将 Falco 作为服务运行。

在开始使用 Falco 之前,您需要启用 Falco systemd 服务:

[code]$ systemctl enable falco [/code]

现在您的安装已完成。服务将在下次重启时自动启动运行。如果您希望立即启动它,只需运行:

[code]$ systemctl start falco [/code]

从现在开始,您可以通过 systemd 提供的功能来管理 Falco 服务。

切换到 eBPF 探针

Falco 默认使用内核模块,这通常是直接在主机上安装 Falco 的最佳选择。但是,如果您有特定要求或其他原因不使用内核模块,则可以轻松切换到 eBPF 探针。

首先确保系统上已安装 eBPF 探针。您可以使用 falco-driver-loader 脚本安装它,如 “管理驱动程序” 中所述。

然后需要编辑 systemd 单元文件,位置位于 /usr/lib/systemd/user/falco­.ser⁠vice(路径可能因您的发行版而异)。您可以使用 systemctl edit falco 进行修改。您需要在该文件的 [Service] 部分添加一个选项来设置 FALCO_BPF_PROBE 环境变量。此外,在相同部分,注释(或删除)ExecStartPre 和 ExecStartPost 选项,以便 Falco 服务不再加载内核模块。以下摘录自 falco.service 文件中的更改已经突出显示:

[code][Unit] Description=Falco: Container Native Runtime Security Documentation=https://falco.org/docs/ [Service] Type=simple User=root Environment='FALCO_BPF_PROBE=""' #ExecStartPre=/sbin/modprobe falco ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid #ExecStopPost=/sbin/rmmod falco [/code]

完成后,请不要忘记重新启动 Falco 服务:

[code]$ systemctl restart falco [/code]

现在 Falco 应该开始使用 eBPF 探针。

使用插件

Falco 软件包配置为支持系统调用检测场景,因此包含的 systemd 单元在 Falco 启动时加载内核模块。但是,如果您不使用系统调用,则无需加载驱动程序。如前一部分所述,为了防止 Falco 服务加载内核模块,请编辑 /usr/lib/systemd/user/falco.service 文件并删除(或注释掉)ExecStartPre 和 ExecStartPost 选项。选择性地,您还可以通过修改 User 选项的值来配置服务以更少特权的用户运行 Falco。

接下来,您需要配置 Falco 来使用您选择的插件(我们将在第十章中说明如何操作),并重新启动 Falco 服务。Falco 将使用新配置运行。

在不使用软件包管理器的情况下

安装 Falco 而不使用软件包管理器快捷简便。此安装方法适用于不支持兼容软件包管理器的发行版。我们在第二章详细介绍了这些步骤,但在这里我们将为您提供简要复习。

您只需获取最新可用版本的二进制软件包链接,从Falco“下载”页面下载到本地文件夹中:

[code]$ curl -L -O \ https://download.falco.org/packages/bin/x86_64/falco-0.32.0-x86_64.tar.gz [/code]

然后解压软件包并将其内容复制到文件系统的根目录:

[code]$ tar -xvf falco-0.32.0-x86_64.tar.gz $ cp -R falco-0.32.0-x86_64/* / [/code]

最后,如果您计划将系统调用作为数据源,请在使用 Falco 之前手动安装驱动程序(您将在接下来的部分找到说明)。如果要使用插件,则不需要安装驱动程序。还请注意,二进制软件包不提供 systemd 单元或任何其他机制以在系统启动时自动运行 Falco,因此是否执行 Falco 或将其作为服务运行完全取决于您。

管理驱动程序

如果您将系统调用作为数据源,可能需要管理驱动程序。如果您未使用软件包管理器安装 Falco,则需要在手动使用 Falco 之前安装驱动程序。所有可用的软件包都提供一个有用的脚本称为falco-driver-loader(在第二章介绍),您可以用此脚本来执行此操作。如果您在本章前面的说明中已经按照指示操作,您的系统上应该已经安装了它。

我们建议您通过使用 --help 来熟悉脚本的命令行用法。只需运行:

[code]$ falco-driver-loader --help [/code]

此脚本允许您执行多种操作,包括通过编译或下载安装驱动程序(内核模块或 eBPF 探针)。它还允许您移除先前安装的驱动程序。

如果您运行脚本而不带任何选项:

[code]$ falco-driver-loader [/code]

默认情况下,它会尝试通过 dkms 安装内核模块。准确地说,它首先尝试下载预构建的驱动程序,如果你的发行版和内核版本有可用的话。否则,它将尝试在本地编译驱动程序。脚本还会提示你是否缺少任何必需的依赖项(例如,如果系统上没有 dkms 或 make)。

如果你想安装 eBPF 探针,请运行:

[code]$ falco-driver-loader bpf [/code]

在容器中运行 Falco

Falco 项目提供了几个容器镜像,可以用来在容器中运行 Falco。虽然本节描述的 Falco 容器镜像几乎适用于任何容器运行时,但我们在示例中简单地使用 Docker。如果你想使用其他工具,包括 Kubernetes,可以应用相同的概念。即使你只对在 Kubernetes 上部署 Falco 感兴趣,我们仍建议你阅读本节,因为它介绍了一些重要的概念。

表 9-1 列出了主要的可用镜像,你可以从 Falco “下载”页面 获取这些镜像。这些镜像包含了安装驱动程序和运行 Falco 所需的所有组件。本节稍后将讨论如何使用它们来支持一些常见的用例。

表 9-1. docker.io 注册表中托管的 Falco 容器镜像

镜像名称描述
falcosecurity/falco这是默认的 Falco 镜像。它包含了 Falco、falco-driver-loader 脚本和构建工具链(用于即时构建驱动程序)。镜像的入口点将调用 falco-driver-loader 脚本,在运行 Falco 之前自动安装驱动程序到主机。
falcosecurity/falco-driver-loader这个镜像与默认镜像类似,但不会运行 Falco。镜像的入口点只会运行 falco-driver-loader 脚本。当你想在不同的时机安装驱动程序或者使用最少权限原则(参见“最少权限模式”)时,可以使用这个镜像。由于这个镜像本身无法运行 Falco,所以需要与其他镜像结合使用,比如 falcosecurity/falco-no-driver
falcosecurity/falco-no-driver这是默认镜像的替代方案,只包含 Falco,因此无法安装驱动程序。当使用最少权限原则或者数据源不需要驱动程序时(例如使用插件时),可以使用它。

每个分发镜像都有不同的标签可供选择特定版本的 Falco。例如,falcosecurity/falco:0.32.0 包含了 Falco 的 0.32.0 发布版本。:latest 标签指向最新发布的 Falco 版本。

如果您想尝试一个尚未发布的 Falco 版本,:master标签会发布最新的可用开发版本。自动流程会在每次将新代码合并到 Falco GitHub 存储库的主分支时构建和发布带有此标签的镜像。这意味着它不是一个稳定版本——除非您想尝试实验性功能或调试特定问题,否则不要在生产环境中使用它。通常,我们建议始终使用*:latest*标签,因为它包含最新的 Falco 版本和规则集更新。

接下来,我们将描述如何在我们讨论过的两种常见场景中使用这些镜像:系统调用检测,需要驱动程序;使用插件作为数据源则不需要。

系统调用检测场景

系统调用检测需要在主机上直接安装 Falco 驱动程序(可以是内核模块或 eBPF 探针)。Falco 需要足够的权限来与驱动程序交互;当然,如果你想使用一个容器镜像来安装驱动程序,该镜像需要以完全权限运行。

Falco 项目提供两种模式来在运行时安装驱动程序,然后在容器中运行 Falco。第一种和最简单的模式只使用一个具有完全权限的容器镜像。第二种使用两个镜像:一个镜像临时以完全权限运行以安装驱动程序,另一个镜像然后以较低权限运行 Falco。第二种方法允许增强安全性,因为长时间运行的容器只获得受限的权限集,使潜在攻击者的生活更加困难。我们建议在容器中运行 Falco 时使用最低权限模式。

完全权限模式

在 Docker 中以完全权限运行 Falco 非常简单。您只需拉取默认镜像:

[code]$ docker pull falcosecurity/falco:latest [/code]

然后使用以下命令运行 Falco:

[code]$ docker run --rm -i -t \ --privileged \ -v /var/run/docker.sock:/host/var/run/docker.sock \ -v /dev:/host/dev \ -v /proc:/host/proc:ro \ -v /boot:/host/boot:ro \ -v /lib/modules:/host/lib/modules:ro \ -v /usr:/host/usr:ro \ -v /etc:/host/etc:ro \ falcosecurity/falco:latest [/code]

此命令将在运行 Falco 之前动态安装驱动程序。默认情况下,容器镜像使用内核模块。如果您想使用 eBPF 探针,请添加-e FALCO_BPF_PROBE=""选项并删除-v /dev:/host/dev(只有内核模块需要*/dev*)。

如您所见,除了--privileged选项外,上述命令还将一组路径从主机挂载到容器中(每个-v选项都是一个绑定挂载)。

具体来说,-v /var/run/docker.sock:/host/var/run/docker.sock选项共享了 Docker 套接字,因此 Falco 可以使用 Docker 获取容器元数据(如第五章中讨论的 Falco 数据丰富技术)。您可以为系统上可用的每个容器运行时添加类似的选项。例如,如果还有 containerd,则包括-v /run/containerd/containerd.sock:/host/run/containerd/containerd.sock。

Falco 需要共享*/dev/proc*以与驱动程序和系统接口,其他共享路径用于安装驱动程序。

最低权限模式

此运行模式遵循最小权限原则以增强安全性。虽然此模式是在容器中运行 Falco 的推荐方式,但并不一定适用于所有系统和配置。我们建议您尝试并根据实际情况回退到完全权限模式。

正如提到的,此方法使用两种不同的容器镜像。第一步,需要完全权限,是使用 falcosecurity/falco-driver-loader 镜像安装驱动程序。在首次运行 Falco 之前,以及在任何时候想要升级驱动程序时,都需要这样做。(或者,如前所述,您可以直接在主机上使用随二进制软件包提供的 falco-driver-loader 脚本安装驱动程序。如果已这样做,请跳过此步骤。)

要使用容器镜像安装驱动程序,请首先拉取该镜像:

[code]$ docker pull falcosecurity/falco-driver-loader:latest [/code]

然后运行安装命令:

[code]$ docker run --rm -i -t \ --privileged \ -v /root/.falco:/root/.falco \ -v /proc:/host/proc:ro \ -v /boot:/host/boot:ro \ -v /lib/modules:/host/lib/modules:ro \ -v /usr:/host/usr:ro \ -v /etc:/host/etc:ro \ falcosecurity/falco-driver-loader:latest [/code]

此命令默认安装内核模块。如果想要使用 eBPF 探针,请添加 -e FALCO_BPF_PROBE="" 选项。

最后一步是运行 Falco。由于驱动程序已安装,您只需使用 falcosecurity/falco-no-driver 镜像即可。因此,首先拉取它:

[code]$ docker pull falcosecurity/falco-no-driver:latest [/code]

然后运行 Falco:

[code]$ docker run --rm -i -t \ -e HOST_ROOT=/ \ --cap-add SYS_PTRACE --pid=host $(ls /dev/falco* | xargs -I {} $ echo --device {}) \ -v /var/run/docker.sock:/var/run/docker.sock \ falcosecurity/falco-no-driver:latest [/code]

如果使用其他容器运行时,请根据需要添加 -v 选项来自定义此命令。

最后,在使用 eBPF 探针时有一些注意事项。除非您的内核版本至少为 5.8,否则无法使用最低权限模式。这是因为在之前的内核版本中,加载 eBPF 探针需要 --privileged 标志。如果您的内核版本等于或大于 5.8,您可以使用 SYS_BPF 权限来解决此问题,方法是按照以下方式自定义命令:

[code]$ docker run --rm -i -t \ -e FALCO_BPF_PROBE="" -e HOST_ROOT=/ \ --cap-add SYS_PTRACE --cap-add SYS_BPF -pid=host \ -v /root/.falco:/root/.falco \ -v /var/run/docker.sock:/var/run/docker.sock \ falcosecurity/falco-no-driver:latest [/code]

注意,在启用了 AppArmor Linux 安全模块(LSM)的系统上,您还需要传递以下内容:

[code]--security-opt apparmor:unconfined [/code]
提示

根据您使用的 Falco 版本和环境,可能需要自定义本节中描述的命令;请参考在线文档。

插件场景

当您将插件用作数据源时,无需安装驱动程序,也不需要 Falco 具有完全权限运行,因此我们建议您在此场景中使用 falcosecur⁠ity/​falco-no-driver 镜像。无论选择哪种容器镜像,它所包含的默认 Falco 配置都无法直接使用;您必须为插件提供所需的配置。您可以通过使用外部配置文件并将其挂载到容器中来完成这一操作。

作为准备步骤,您需要创建一个本地副本的 falco.yaml 并根据您的插件配置进行修改。我们将在下一章节中说明如何操作。

一旦准备好自定义的 falco.yaml,要运行 Falco,请使用以下命令:

[code]$ docker run --rm -i -t \ -v falco.yaml:/etc/falco/falco.yaml \ falcosecurity/falco-no-driver:latest [/code]

如果您想使用默认 Falco 发行版中未包含的插件,您将需要在容器中挂载插件文件和其规则文件。例如,要挂载 libmyplugin.somyplugin_rules.yaml,请将以下选项添加到前述命令中:

[code]-v /path/to/libmyplugin.so:/usr/share/falco/plugins/libmyplugin.so -v /path/to/myplugin_rules.yaml:/etc/falco/myplugin_rules.yaml [/code]

部署到 Kubernetes 集群

Falco 最常见的用例之一是保护集群,因此将 Falco 部署到 Kubernetes 可能是您需要了解的最重要的安装方法。Falco 项目推荐了两种方法:

Helm

第一种安装方法使用 Helm,这是一个非常流行的工具,用于在 Kubernetes 上安装和管理软件。Falco 社区提供并维护了一个 Helm 图表,用于 Falco 及其与 Falco 集成的其他工具。使用提供的图表安装 Falco 很简单,而且大部分是自动化的。

Kubernetes 清单文件

另一种安装方法,更加灵活,基于一组 Kubernetes 清单文件。这些文件提供了默认的安装设置,用户可以根据需要进行自定义。虽然这种方法需要更多的工作量,但它允许在几乎任何 Kubernetes 集群上安装 Falco,而无需额外的工具。

这两种方法都很可靠,您应选择最适合您的环境和组织需求的方法。在接下来的子章节中,我们将为您详细介绍每种方法。唯一的要求是已安装并运行一个 Kubernetes 集群。

Note

本节描述的 Kubernetes 安装方法使用了讨论中的默认 Falco 容器镜像 “在容器中运行 Falco”。

使用 Helm

如果您更喜欢完全自动化的安装过程或者已经在您的环境中使用 Helm,那么这种安装方法适合您。安装 Helm 是先决条件;有关说明,请参阅 在线文档。

Falco 的 Helm 图表将通过 DaemonSet 将 Falco 添加到集群中的所有节点。然后,每个部署的 Falco Pod 将尝试在其自己的节点上安装驱动程序。这是反映最常见情况的默认配置,即系统调用仪器化。

Tip

Falco Pod 内部使用 falco-driver-loader,它尝试下载预构建的驱动程序;如果失败,将动态构建驱动程序。通常情况下不需要任何操作。如果您注意到 Falco Pod 在部署后不断重启,那么可能是无法安装驱动程序。这种问题通常发生在您的发行版或内核中无法获取预构建的驱动程序,并且主机上没有内核头文件的情况下。要构建驱动程序,必须在主机上安装内核头文件。您可以通过手动安装内核头文件,然后再次部署 Falco 来解决此问题。

Helm 使用由kubectl提供的 Kubernetes 上下文来访问您的集群。在使用 Helm 安装 Falco 之前,请确保您的本地配置指向正确的上下文。您可以通过运行以下命令来检查:

[code]$ kubectl config current-context [/code]

如果上下文未指向您的目标集群或 kubectl 无法访问您的集群,则必须解决此问题。否则,您可以继续进行下一步操作。

在安装图表之前,请添加 Falco 的 Helm 存储库,以便您的本地 Helm 安装程序可以找到 Falco 图表:

[code]$ helm repo add falcosecurity https://falcosecurity.github.io/charts [/code]

运行此命令通常是一次性操作。要获取关于 Falco 图表的最新信息,请使用:

[code]$ helm repo update [/code]

每当您想要使用 Helm 安装和更新 Falco 时,请执行此命令。

下一个也是最后一步是运行以下命令来安装图表:

[code]$ helm install falco falcosecurity/falco [/code]

默认情况下,该图表安装内核模块。如果您想改用 eBPF 探针,则只需在该命令后附加--set ebpf.enabled=true。

完成!过一段时间,Falco 的 Pod 将出现在您的集群中。您可以使用以下命令检查它们是否准备就绪:

[code]$ kubectl get all [/code]

该图表按照默认设置为默认场景(系统调用仪器化)安装 Falco。其他场景的 Helm 安装过程非常类似;只需提供适当的配置即可。我们将在第十章讨论如何自定义您的 Falco 部署。您可以在其在线文档中找到有关 Falco 图表配置的更多信息。

使用清单

Kubernetes 清单是 JSON 或 YAML 文件(主要是 YAML),包含一个或多个 Kubernetes API 对象的规格,并描述您的应用程序及其配置。kubectl 命令行实用程序允许您使用这些文件在 Kubernetes 中部署工作负载。项目通常提供几乎准备好使用的示例清单,但通常需要根据您的需求进行调整。

由于 Falco 支持非常不同的场景和环境,Falco 项目并未为所有用例正式提供清单。但是,对于系统调用仪器化场景,您可以使用Falco 示例清单(列在表 9-2 中)作为起点,以制作您的定制清单。^(1)

表 9-2. Falco 示例清单文件

文件名描述
daemonset.yaml指定DaemonSet,以便每个节点上运行 Falco Pod 的副本(系统调用仪器化场景所需)。Pod 规范使用falcosecurity/falco容器映像。它还包括在此场景中运行映像所需的所有设置,类似于“在容器中运行 Falco”中描述的设置。
configmap.yaml指定了包含默认falco.yaml文件和规则文件的ConfigMap。根据您的需求进行修改。
serviceaccount.yaml指定了一个ServiceAccount,用于运行 Falco 的 Pod。Falco 需要此账户与 Kubernetes API 通信。通常情况下,您不需要修改它,除非您想更改服务账户名称。
clusterrole.yaml指定了一个ClusterRole,包括 Falco 与 Kubernetes API 通信所需的基于角色的访问控制(RBAC)授权。不要更改所需权限列表,否则 Falco 将无法正确丰富 Kubernetes 元数据。
clusterrolebinding.yaml指定了一个ClusterRoleBinding,将clusterrole.yaml中定义的权限授予serviceaccount.yaml中定义的服务账户。通常情况下,您不需要更改此项,除非您已更改了其他文件中的服务账户或集群角色名称。

一旦根据您的需求修改了清单文件,要将它们应用到 Kubernetes(即部署 Falco 到 Kubernetes),只需运行以下命令:

[code]$ kubectl apply \ -f ./templates/serviceaccount.yaml \ -f ./templates/clusterrole.yaml \ -f ./templates/clusterrolebinding.yaml \ -f ./templates/configmap.yaml \ -f ./templates/daemonset.yaml [/code]

一段时间后,Falco 的 Pod 应该会出现在您的集群中。要检查它们是否准备就绪,请使用:

[code]$ kubectl get all [/code]

如果一切顺利,Falco 现在已经在您的生产集群中运行起来了,并且您已经学会如何自定义您的 Falco 部署。恭喜!

结论

本章介绍了 Falco 的不同安装方法,并解释了两种最常见安装场景之间的区别。然而,在某些情况下,您的安装将需要特定的配置或自定义。下一章将为您提供所有必要的补充信息,以便最终在生产环境中运行 Falco 并完全控制您的 Falco 安装。

^(1) Kubernetes 中 Falco 清单示例文件的实际 URL 可能会不时更改,但您始终可以在官方文档中找到它们的链接。Falco 的 Helm 图表也可以生成这些文件。令人惊讶的是,Falco 项目使用此 Helm 功能自动发布最新的清单示例文件,位于Falcosecurity GitHub 组织下。

第十章:配置和运行 Falco

在前一章中,您学习了如何在生产环境中安装 Falco。然而,您仍需了解其配置系统的工作方式。学习如何更改其设置对于随时间管理和适应您的需求至关重要。您可以在安装期间或安装后立即配置 Falco,在更新到新版本时或任何时候根据您的需求进行配置。

本章将帮助您理解和使用可用的设置。首先,我们将解释主要的干预领域:命令行选项、环境变量、配置文件和规则文件。然后,我们将深入探讨每一个。您还将找到关于生产用例的宝贵建议,以及一些微调 Falco 配置的提示。在章节末尾,您将找到一个专门介绍配置插件的部分,并展示如何更新运行中的 Falco 实例配置。

配置 Falco

您可以通过其设置来配置 Falco,我们将这些设置分为三类:

命令行选项和环境变量

命令行选项和环境变量是您运行 Falco 所需的首要设置。其中大多数设置允许 Falco 与您的系统进行通信,这对于系统仪表化和数据丰富化特别重要。这里的其他设置可以帮助您适应特定需求或帮助故障排除。

配置文件

您可以通过主配置文件几乎配置任何 Falco 行为,根据需要进行自定义。例如,您可以加载规则文件,激活所需的输出通道,并在需要时使用插件。默认情况下,Falco 在 /etc/falco/falco.yaml 中查找此文件,但您可以使用命令行选项指定不同的路径。

规则集

Falco 自带丰富的默认规则集,以便您可以立即开始使用它。然而,规则集可能是定制化最关键的方面。它代表了 Falco 引擎的配置,并设置了 Falco 将检测到的内容。按照惯例,规则文件位于 /etc/falco

在详细讨论每个类别之前,我们想向您展示 Falco 如何根据您的安装方式进行变化。

安装方法之间的差异

无论您选择哪种安装方法,Falco 的配置区域始终相同。但是,您可以更改设置的方式可能略有不同。

主机安装

如果您使用软件包管理器安装了 Falco,则可以直接在 systemd 单元文件中指定命令行选项和环境变量,该文件位于 /usr/lib/systemd/user/falco.service。使用 systemctl edit falco 是一种方便的方法。完成后,请记得使用 systemctl restart falco 重新启动服务。

如果您不使用包管理器,运行 Falco 完全由您决定,包括传递命令行选项和设置环境变量。在这种情况下,您可以手动创建一个 systemd 单元。您可以使用 falco-service 文件的源代码 作为示例。

无论您使用哪个包,您都会在 /etc/falco 下找到 Falco 的配置文件和规则文件。您可以直接编辑这些文件,然后重新启动 Falco。

容器

Falco 的容器镜像允许您指定要运行的命令,默认为 /usr/bin/falco。如果需要传递命令行选项,请通过容器运行时的 CLI 进行。例如,在 Docker 中,要传递 --version,可以使用:

[code]$ docker run --rm -it falcosecurity/falco /usr/bin/falco --version [/code]

请注意,falcosecurity/falco 容器镜像的入口点是一个脚本,尝试自动安装驱动程序。如果要跳过安装,需要将 SKIP_DRIVER_LOADER 环境变量设置为任何非空值。在 Docker 中,可以使用 -e 选项设置环境变量。^(1) 例如,要获取版本并同时跳过驱动程序安装,可以运行:

[code]$ docker run --rm -it -e SKIP_DRIVER_LOADER=y \ falcosecurity/falco /usr/bin/falco --version [/code]

Falco 容器镜像还捆绑了默认的配置文件和规则文件。如果需要修改其中任何文件,通常的做法是制作文件的外部副本(例如,/etc/falco/falco.yaml),然后挂载到容器中。您可以从二进制包中获取配置和规则文件(确保与容器中运行的 Falco 版本匹配),根据需要进行修改。然后,在 Docker 中,使用 -v 选项将修改后的文件挂载到容器中。^(2)

Kubernetes 部署

在 Kubernetes 中部署 Falco 时,还需在 DaemonSet 或 Deployment 清单中指定命令行选项和环境变量。如果使用 Helm 或来自 第九章 的示例清单,部署将已经配置了连接到您的容器运行时和 Kubernetes API 服务器的所有选项。如果需要修改选项,请查找相应的 Falco 图表配置 或直接修改 清单。

另一个重要的区别是配置和规则文件存储在 ConfigMap 内,其内容会覆盖容器镜像中包含的文件。对于 Helm 用户,维护者会将 Falco 的图表、配置和规则文件与 Falco 发行版同步更新。另一方面,如果使用清单文件,您完全可以确保 ConfigMap 嵌入了正确的文件。

命令行选项和环境变量

在运行 Falco 时,有时通过命令行选项或设置环境变量是更改某些设置的唯一方式。您通过命令行配置的设置始终优先于从配置文件加载的设置。

要获取 Falco 的命令行选项完整列表,请运行 falco --help。Falco 将按字母顺序打印每个选项(以及简要描述)。可用选项可能根据 Falco 版本的不同而变化。有疑问时,请始终参考 falco --help。

在本节的其余部分,为了帮助您熟悉最重要的设置,我们按功能对其进行分组。我们还提供了关于使用环境变量的详细信息,这些信息在 falco --help 中找不到。

配置设置

在 表 10-1 中显示的两个命令行选项与 Falco 的配置文件相关(默认位于 /etc/falco/falco.yaml)。第一个选项允许您从不同位置加载配置文件;第二个选项允许您即时覆盖某些配置值。通常情况下不需要使用它们,但在故障排除时可能会很有用。此外,在生产环境中运行 Falco 时,请确保没有人错误地设置它们,以便 Falco 使用正确的配置文件和预期的设置。

表 10-1. 配置命令行选项

选项描述
-c设置 Falco 将加载的配置文件路径。如果未设置,则 Falco 将使用默认路径: /etc/falco/falco.yaml
-o, --option *<key>*=*<val>*通过将值 *<val>* 设置为指定的配置选项 *<key>* 来覆盖配置文件中的值。您可以使用点表示法(.)指定嵌套选项,或使用方括号表示法([])访问列表:例如,-o key.subkey.list[0]=myValue。

仪表设置(仅系统调用)

如您在第 4 和 9 章节中学到的,Falco 默认使用内核模块驱动程序。您可以通过设置 FALCO_BPF_PROBE 环境变量切换到 eBPF 探针。您可以将其设置为您想使用的探针路径,例如 FALCO_BPF_PROBE="/path/to/falco-bpf.o"。否则,您可以将其设置为空字符串(FALCO_BPF_PROBE=""),Falco 将默认使用 ~/.falco/falco-bpf.o

当您在容器或 Kubernetes 中运行 Falco 时,容器镜像支持 FALCO_BPF_PROBE 控制即时驱动程序安装,以及其他环境变量。 (falco-driver-loader 脚本暴露了大部分,因此您也可以使用 falco-driver-loader --help 获取更多信息。)现在让我们看看这些环境变量:

DRIVERS_REPO

如果您创建了预构建驱动程序的存储库(无论是内核模块还是 eBPF 探针),可以使用此选项指示脚本从您的存储库下载驱动程序。驱动程序存储库以以下 URL 结构托管文件:

<DRIVERS_REPO>/<DRIVER_VERSION>/falco_<OS_ID>​_<KER⁠NEL_RELEASE>_<KERNEL_VERSION>.[ko|o]

此变量允许您设置您存储库的基本 URL(末尾没有斜杠)。如果您在离线环境中运行 Falco 或者不希望从互联网下载预构建的驱动程序,可能希望使用此设置。如果未设置,此变量默认为 The Falco Project 的 public driver repository。

DRIVER_INSECURE_DOWNLOAD

如果您的驱动程序存储库不支持 HTTPS,请将其设置为任何值(例如 yes),以允许脚本从不安全的 URL 下载文件。

SKIP_DRIVER_LOADER

如果您通过其他方式在主机上安装了驱动程序,很可能希望在容器启动时禁用 falco-driver-loader 脚本。在这种情况下,请将此环境变量设置为任何值(例如 yes)。此设置仅影响使用 falco-driver-loader 作为入口点的 Falco 容器镜像,例如 falcosecurity/falco 容器镜像。

HOST_ROOT

这个环境变量与这里列出的其他环境变量不同,它与驱动程序安装无关,直接影响 Falco。HOST_ROOT 期望一个基本路径,影响仪表盘的设置和增强系统。如果该值不为空,Falco 在访问主机文件系统时会将其用作路径前缀(例如 /dev 下的内核模块设备或从 /proc 和容器运行时 Unix 套接字路径中获取数据增强的信息)。falco-driver-loader 脚本也会为类似的目的使用这个变量(例如,访问 /boot/lib/usr/etc)。

在容器中运行 Falco 时,请使用 HOST_ROOT。通常的约定是将 HOST_ROOT=/host 并将所有相关路径挂载到容器中的 /host 目录下。Kubernetes 部署使用这种方法;详见第五章和第九章了解更多详情。

为了完整起见,与系统调用仪表盘相关的其他设置列在 Table 10-2 中。这些设置对性能有显著影响,因此除非必要,否则不要使用它们。

Table 10-2. 系统调用仪表盘命令行选项

OptionDescription
-AFalco 默认不监视所有系统调用,因此通常无法在规则条件中使用所有事件类型(驱动程序跳过大多数嘈杂或处理昂贵的系统调用,如 read、write、send 和 recv)。如果您启用此设置,驱动程序将发送所有支持的系统调用事件到 Falco,这在边缘用例中可能会有所帮助。但启用此设置会严重影响性能。Falco 可能无法跟上事件流。支持的系统调用完整列表可在 syscall_info_table.c 中找到。默认情况下,驱动程序跳过那些标记为 EF_DROP_SIMPLE_CONS 的系统调用。
-u, --userspace仅在无法使用内核空间工具时使用此选项。此选项必须与像 pdig(在 第四章 中讨论的用户空间驱动程序)一样使用。

数据丰富设置(仅系统调用)

使用系统调用作为数据源时,Falco 需要连接到驱动程序。它还需要从主机、容器运行时和 Kubernetes 获取信息。在 第五章 中,我们简要讨论了本节描述的设置;表 10-3 提供了影响数据丰富机制的命令行选项和环境变量的详细使用说明。

表 10-3. 数据丰富命令行选项

选项描述
--cri *<path>*使用此选项指定 CRI 兼容容器运行时的 Unix 套接字路径。如果 Unix 套接字有效,Falco 将连接到运行时以获取容器元数据。在最新版本的 Falco 中,您可以多次指定此选项。Falco 将按顺序尝试每个给定的路径,并使用第一个连接成功的路径。如果未设置此选项,Falco 将仅尝试使用 /run/containerd/containerd.sock
--disable-cri-async此选项禁用异步 CRI 元数据获取。通常不需要设置它。但如果 Falco 间歇性显示容器元数据,则此选项可以帮助您解决问题。
-k *<url>*, --k8s-api *<url>*通过连接到由 *<url>* 指定的 Kubernetes API 服务器,启用 Kubernetes 元数据丰富。或者,您可以使用 FALCO_K8S_API 环境变量,它接受与此选项允许的相同值。
-K *<bt_file>* &#124; *<cert_file>*:*<key_file[#pwd]>* [:*<ca_cert_file>*], --k8s-api-cert *<bt_file>* &#124; *<cert_file>*:*<key_file[#pwd]>* [:*<ca_cert_file>*]使用此选项与 Kubernetes API 服务器进行身份验证。你可以提供一个令牌文件^(a) (*<bt_file>*) 或证书和私钥 (*<cert_file>*:*<key_file>*)。如果使用后者,你可以选择使用密码 (*#pwd*) 访问私钥(如果加密),以及 CA 证书 (:*<ca_cert_file>*) 用于验证 API 服务器的身份。证书和私钥必须以 PEM 文件格式提供。作为替代方案,你可以使用 FALCO_K8S_API_CERT 环境变量,该变量接受此选项允许的相同值。
--k8s-node *<node_name>*此选项启用了 Kubernetes 元数据增强的重要性能优化:Falco 在从 API 服务器请求 Pod 的元数据时将使用节点名称作为过滤器,丢弃来自其他节点的不必要的元数据。你应该始终设置此选项。如果不设置,Falco 将工作,但在大型集群上可能存在性能问题。
^(a) 一个持有者令牌文件包含了用于验证 API 请求的字符串,这是 Kubernetes 的可用 认证策略 之一。

规则集设置

表 10-4 显示了可能影响规则集的命令行选项。如果没有使用这些选项,Falco 将仅使用配置文件来加载规则。

表 10-4. 规则集命令行选项

选项描述
-D *<substring>*此选项允许你禁用其名称中匹配*<substring>*的一个或多个规则。你可以多次指定它,但与-t选项(见下文)不兼容。
-r *<rules_file>*此选项允许你指定 Falco 用来加载规则的文件或目录。对于目录,Falco 将加载其中包含的所有文件。你可以多次指定 -r 来加载多个文件或目录。如果使用此选项,Falco 将忽略配置文件(/etc/falco/falco.yaml)中指定的规则文件和目录。因此,我们不建议在生产环境中使用它,除非用于调试或特殊情况。
-T *<tag>*此选项禁用具有给定 *<tag>* 的所有规则。你可以多次指定它,但与 -t 选项不兼容(见下文)。
-t *<tag>*此选项仅启用具有给定 *<tag>* 的规则,并禁用所有其他规则。你可以多次指定它,但与 -T 和 -D 选项不兼容。

输出设置

我们在 第 8 章 中描述了大部分的输出格式选项(以及 Falco 输出通道配置)。然而,还有另外两个命令行选项(列在 表 10-5 中),允许您进一步自定义 Falco 的输出行为。

表 10-5. 输出命令行选项

选项描述

| -p*<output_format>*, --print*<output_format>* | 启用时,此选项将额外信息附加到 Falco 通知的输出中。有几种不同的风格可用;例如:

  • -pc 或 -pcontainer 将添加容器信息,例如名称和 ID。

  • -pk 或 -pkubernetes 将添加 Kubernetes 信息,例如命名空间和 Pod 名称。

在 Kubernetes 环境中使用 Falco 时,我们建议使用 -pk。 |

-U, --unbuffered此选项禁用输出通道中的完全输出缓冲(参见 第 8 章)。仅在将 Falco 输出导入另一个进程或脚本时遇到问题时使用。关闭输出缓冲可能会增加 CPU 使用率。

其他用于调试和故障排除的设置

迄今为止我们描述的命令行选项是您在操作 Falco 时可能经常使用的选项。但是,还有另一组选项(列在 表 10-6 中),用于更偶尔的使用,比如当您需要关于 Falco 安装的信息或尝试解决问题时。

表 10-6. 调试和故障排除的命令行选项

选项描述
-e *<events_file>*告诉 Falco 使用由 *<events_file>* 指定的跟踪文件(参见 第 3 章)作为数据源,而不是使用实时事件源。一旦 Falco 消耗完文件中的所有事件,它就会退出。适用于测试和规则编写。
-L打印有关所有加载的规则的信息。
-l *<rule>*打印具有名称 *<rule>* 的规则的名称和描述(如果已加载)。
--list[=*<source>*]按类别列出所有可用的条件字段(参见 第 6 章)。如果还提供 *<source>*,Falco 将仅列出该数据源的字段。*<source>* 的值可以是 syscall 或由已配置的插件提供的任何其他数据源。
--list-plugins打印已配置插件的信息。
-s *<stats_file>*告诉 Falco 创建文件 *<stats_file>* 并在运行时填充统计信息。
--stats-interval *<msec>*设置更新由 -s *<stats_file>* 创建的文件的刷新间隔(以毫秒为单位)。
--support打印有关加载的 Falco 配置和规则集以及其他有用的故障排除信息的详细信息,您在请求帮助时可以提供这些信息(例如,在 Falco GitHub 存储库中 提交问题)。
-V, --validate *<rules_file>*验证给定的 *<rules_file>* 内容。用于测试和规则编写。
-v在 Falco 运行时启用详细日志记录。此选项不影响通常的 Falco 通知,但日志消息可能会交错。用于调试非常有用。
--version打印您正在使用的 Falco 版本。

配置文件

在本书中,我们一直在讨论 Falco 的配置文件,并且已经涵盖了它的大部分重要方面。本节提供了一个概述和指向您可能需要的所有内容的指针。

默认情况下,配置文件是一个 YAML 文件,位于 /etc/falco/falco.yaml。在此文件中,您可以配置:

规则文件

rules_file 配置节点是配置文件中第一个找到的节点。它允许您选择 Falco 将加载的规则文件(更多细节将在下一节介绍)。

插件

您可以通过 load_plugins 和 plugins 配置节点启用插件并传递设置(参见“使用插件”)。

输出通道

各种配置节点允许您配置格式化、日志记录和输出通道选项。有关输出框架的更多信息,请参阅第 8 章。

嵌入式服务器

Falco 提供了一个嵌入式 Web 服务器,公开了一个健康的端点。[³] 容器编排器和其他应用程序可以使用此端点检查 Falco 是否正在运行。webserver 配置节点允许您启用和配置服务器。

Falco 还提供了一个 gRPC 服务器,您可以使用 grpc 配置节点启用和配置它(参见第 8 和 12 章)。

高级调优设置(仅限系统调用)

系统调用仪器是 Falco 支持的最复杂功能之一,因此配置文件还提供了其高级设置。这些设置因 Falco 版本而异,因此我们建议您始终参考在线文档和配置文件中的内联注释。

在这里需要注意的选项包括 syscall_event_drops,用于控制事件丢弃的检测;syscall_event_timeouts,帮助检测事件缺失(对于系统调用来说是不常见的情况);以及 metadata_download,提供了几个选项来微调从容器编排器 API 服务器下载信息。

规则集

Falco 自带一组预定义的规则,您可以直接使用。然而,有很多理由尽可能定制您的规则集。默认的规则集旨在覆盖主要的攻击向量,但这些规则无法涵盖所有可能的情况。攻击机制始终在发展,因此您的规则集需要跟上这些变化。如果您希望达到最高级别的安全性,您需要一个根据特定环境定制的规则集。

定制规则的额外好处包括避免噪声误报和优化 Falco 的性能。出于所有这些原因,你需要学会如何正确配置规则集。

加载规则文件

有两种方式告诉 Falco 要加载哪些规则文件:通过命令行或配置文件。在命令行上,你可以使用 -r 标志指定规则文件。在配置文件中,将规则文件放在 rules_file 部分下。请注意,通过命令行设置的内容会优先于配置文件。出于这个原因,在生产环境中,我们建议仅通过配置文件加载规则文件。

无论你选择哪种方法,你都可以指定多个规则文件或目录。因此,你可以这样做:

[code]$ falco -r path/to/my/rulefile1.yaml -r path/to/my/rulefile2.yaml [/code]

或者:

[code]rules_file: - path/to/my/rulefile1.yaml - path/to/my/rulefile2.yaml [/code]

需要注意的是,规则文件会按照指定的顺序加载和解析。(当条目是目录时,Falco 会按字母顺序加载该目录中的每个文件。)这使得可以在后续文件中自定义规则、宏和列表(参见 第七章),这些定义在一个文件中。默认的 Falco 配置经过精心设计以利用这种机制。

让我们来看看随 Falco 一起提供的默认配置文件中的 rules_file 部分:

[code]rules_file: - /etc/falco/falco_rules.yaml - /etc/falco/falco_rules.local.yaml - /etc/falco/rules.d [/code]

主规则文件 falco_rules.yaml 包含系统调用的规则,随后是名为 falco_rules.local.yaml 的文件。你应该在 falco_rules.local.yaml 中进行对 falco_rules.yaml 的修改。默认情况下,这个文件是空的,你可以在其中工作而不必担心污染主规则文件。根据需要,你可以创建其他本地文件。

通常,Falco 每个数据源提供一个规则文件。你可以使用这种方法或根据需要使用多个文件。只需记住加载顺序很重要。还要注意,Falco 只会加载与配置的数据源匹配的规则;所有其他规则将被忽略。这意味着你无需担心手动删除或禁用用于其他数据源的规则文件。

调整规则集

调整规则集最重要的一点是理解你的用例需要检测什么。这将帮助你决定哪些规则对你有用,哪些不需要。避免不必要的规则不仅可以增加性能(Falco 将使用更少的 CPU 资源),还可以减少误报。

一旦完成初步浏览,禁用你不感兴趣的规则(如 第七章 中描述)。我们不建议从规则文件中删除它们,除非你从头开始创建自己的规则文件。我们还建议定期评估你的规则集,因为随时间推移,你需要的规则会发生变化。

接下来,查看规则的条件。我们将在 第十三章 中详细介绍编写 Falco 规则的细节,但现在我们将提供两个一般评估 Falco 规则的指南。

首先,避免在条件中使用过多的异常,例如,长链条的and not (...) and not (...)。Falco 必须顺序检查条件中的任何异常,这是一项昂贵的任务。在可能的情况下,更短的条件可以显著改善规则评估性能。

第二条准则仅适用于系统调用,并且认为规则条件应始终匹配一个事件类型或一小组事件类型。例如,evt.type=connect和evt.type in (open,openat,openat2)都可以接受,但evt.type!=execve不可以,因为该过滤器将匹配除一个之外的所有事件类型,这太多了。Falco 通过事件类型对规则进行索引,以优化其内部评估过程;匹配太多事件类型的规则会使此索引变得低效。为了帮助规则作者发现此问题,Falco 对匹配所有事件类型的规则发出警告。

使用插件

默认情况下,Falco 配置为使用系统调用。如果你想使用插件作为数据源,请确保:

  • 插件文件已经存在于*/usr/share/falco/plugins*中(一些插件已随 Falco 一起提供);如果没有,你需要将其安装到该文件夹中。

  • 插件的规则文件已准备好(我们建议将其放在*/etc/falco*下)。

  • 你已经阅读了插件的文档,并理解了它需要哪些配置参数。

然后,准备 Falco 的配置文件以使用插件是一个三步骤的过程:选择正确的规则文件、配置插件并启用它。

为了说明这个过程,我们将使用CloudTrail 插件,它获取包含CloudTrail事件的日志文件(有关使用此插件的详细信息将在下一章提供)。CloudTrail 插件具有一个规则集,需要另一个具有字段提取能力的插件:JSON 插件。这两个插件和规则集都与 Falco 捆绑在一起,所以如果你已经安装了 Falco,你应该已经拥有它们。你会在*/usr/share/falco/plugins下找到插件文件libcloudtrail.solibjson.so*,规则文件在*/etc/falco/aws_cloudtrail_rules.yaml*。

插件的规则文件通常不会在 Falco 配置中默认配置,因此你需要添加一个rules_file条目来加载正确的规则文件(如果需要,也可以删除不必要的规则文件):

[code]rules_file: - /etc/falco/aws_cloudtrail_rules.yaml [/code]

接下来,在plugins下添加相关条目:

[code]plugins: - name: cloudtrail library_path: libcloudtrail.so init_config: sqsDelete: true open_params: "sqs://my-sqs-queue" - name: json library_path: libjson.so init_config: "" [/code]

name字段必须与插件名称匹配,library_path必须与*/usr/share/falco/plugins*下的插件文件匹配。

在init_config中,添加 Falco 将传递给插件的初始化参数(有关详细信息,请参阅插件的文档)。大多数插件接受纯文本或 JSON 格式的字符串。如果插件支持 JSON 字符串,你仍然可以使用 YAML 语法来编写init_config(如前面的示例);Falco 会自动为你进行转换。

open_params设置仅适用于具有事件源能力的插件(例如 CloudTrail 插件),并且仅接受纯文本字符串。它提供打开事件流的参数(再次参考插件的文档)。某些插件可能不需要此设置;在这种情况下,您可以将其设置为空字符串("")。

最后一步是启用您的插件:

[code]load_plugins: [cloudtrail, json] [/code]

load_plugins设置接受一个插件名称数组。您可以同时启用多个插件。

就这样!您的插件现在已配置并准备在 Falco 中运行。

修改配置

安装和配置 Falco 后,您可能需要不时地更改其配置。有两种方式告知 Falco 加载更新的配置(即配置文件或规则文件的任何修改)。

最简单的方法就是修改配置然后重新启动 Falco。如果您是通过包管理器在主机上安装的 Falco,您可以使用systemctl restart falco命令来实现这一点。如果您在容器中运行 Falco,则重新启动容器。如果您在 Kubernetes 集群中运行 Falco,则需要重新部署 Falco。重新启动 Falco 是升级到新版本或更改其命令行设置的唯一方法。

第二种加载更新配置的方式是热重载,即告诉 Falco 在不停止其运行进程的情况下重新加载配置和规则文件。您可以通过发送SIGHUP 信号来告诉 Falco 自行重新加载:

[code]$ kill -HUP *<falco process ID here>* [/code]

一旦 Falco 收到信号,它将重新加载配置文件和配置的规则文件。

自 0.32.0 版本以来,当修改配置文件或规则文件时,Falco 可以自动进行热重载。在配置文件中,watch_config_files设置控制此功能(默认启用)。因此,在最新版本的 Falco 中,您只需修改配置文件或规则文件,无需手动发送 SIGHUP 信号。

请注意,在 Falco 重新启动或热重载时,它不会检测事件。然而,与重新启动进程所需的时间相比,热重载 Falco 所需的时间显著缩短,通常可以忽略不计。

结论

本章和前一章深入讲解了在生产环境中安装、配置和运行 Falco 的各个方面,无论是系统调用仪器化场景还是使用插件作为数据源的场景。现在是深入探讨具体插件案例的时候了:如何利用 Falco 进行云安全。在下一章中,您将了解如何通过使用 CloudTrail 插件来保护您的云环境。

^(1) 在 Docker 运行容器时,还有几种设置环境变量的方法;更多信息请参阅 Docker 的在线文档。

^(2) 有几种方法可以将文件挂载到容器中。详细信息请参阅 Docker 的文档。

^(3) Falco 的开发人员最初引入了 Web 服务器来支持 Kubernetes 审计日志作为数据源。最近,他们将此功能因子分解为插件。因此,您可以在不同的 Falco 版本下的webserver配置节点中找到的实际设置可能会有很大差异。

^(4) 带有插件系统的 Falco 的首个版本不允许您同时启用具有事件源能力的多个插件。然而,您可以仅启用具有字段提取能力的多个插件(参见第四章)。

第十一章:使用 Falco 进行云安全

现在您已经学会了如何配置和运行 Falco 的所有必要知识,是时候关注一个对您的安全姿态有重大影响的重要主题了:云安全。

如果您正在阅读本书,那么您的一些软件(或者全部!)很可能在云中运行。由于 AWS 是云服务的领先提供者,您的软件很可能也在那里运行。

公共云环境非常适合运行软件。它们对弹性、灵活性和自动化的支持使得构建和运行应用程序更加容易和高效。然而,基于云的应用程序及其使用的数据面临来自全球的攻击。它们还容易受到来自内部团队的配置错误、失误和恶意行为的影响。

综合安全姿态需要考虑许多领域,包括应用程序、用户(内部和外部)以及数据。如果不能正确保护这些领域中的任何一个,将会产生漏洞,从而导致风险。例如,保护在容器和主机中运行的工作负载(你可以通过 Falco 有效实现)如果不涵盖这些工作负载所运行的云基础设施,就不会有实际益处。

幸运的是,Falco 可以填补这一差距,并帮助您实现所需的覆盖范围。让我们来学习如何做到!

为什么选择 Falco 用于 AWS 安全?

云安全是一个肥沃且不断发展的领域,具有许多实施选项。从架构上讲,大多数选项都可以归为两种基本类别:

  1. 查询云 API 或监视云数据存储以检测配置错误或漏洞的工具

  2. 将云日志流式传输到后端并对其进行索引以及让您进行查询的工具

如果您的目标是检测基于云的软件中的威胁,那么第一类工具并不是非常有用。轮询对于检测漏洞和验证合规性很有用,但缺乏检测威胁并快速响应所需的实时性质。第二类工具功能强大,但在像公共云这样产生大量日志的环境中非常昂贵,并且部署和使用起来也不友好。

Falco 的运行时安全方法为解决这一问题提供了非常有效的解决方案。Falco 的理念基于三个关键概念。首先,它以流式处理方式解析数据,实时检测威胁。其次,它在轻量级易于运行和部署的引擎上实现检测。第三,它提供一种紧凑的规则语言,快速学习但灵活表达。正如您在整本书中看到的那样,这种理念在系统调用和像 AWS CloudTrail 生成的日志中同样有效。

Falco 资源消耗极少,并且最重要的是,以流式方式分析数据——无需执行昂贵的复制或等待数据索引。Falco 实时查看您的数据,并在几秒钟内通知您存在的问题。正如您在本书的 Part I 中看到的那样,只需几分钟即可使其运行,并将其用于云日志和系统调用允许了统一的威胁检测方法。让我们看看它是如何工作的。

Falco 的架构与 AWS 安全

当部署在 AWS 基础设施安全环境中时,Falco 在 AWS CloudTrail 生成的日志之上实施检测。其工作原理如 Figure 11-1 所示。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_1101.png

Figure 11-1. Falco 用于 AWS 安全的高级架构

CloudTrail 是亚马逊提供的日志聚合服务。它从数百个 AWS 服务收集日志,并使用一致且有文档化的格式存储在 S3 中。CloudTrail 容易设置,并提供一致的层,使客户免受收集用户和服务活动日志的复杂性影响。

CloudTrail 事件是 CloudTrail 定期写入 S3 存储桶中的 JSON 文件条目。Falco 通过 CloudTrail 插件(Figure 11-2)理解如何读取和解析这些事件,该插件由 Falco 社区创建和维护。(如果您需要了解 Falco 插件及其工作原理,请参阅 Chapter 4。)

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_1102.png

Figure 11-2. 使用 CloudTrail 插件进行事件收集

除了提供多种收集 CloudTrail 日志的方法(本章稍后详细介绍每种方法),CloudTrail 插件还使用 AWS 特定字段扩展了 Falco,您可以使用这些字段创建类似这样的规则:

[code]- rule: Console Login Without MFA desc: Detect a console login without MFA. condition: > ct.name="ConsoleLogin" and ct.error="" and ct.user.identitytype!="AssumedRole" and json.value[/responseElements/ConsoleLogin]="Success" and json.value[/additionalEventData/MFAUsed]="No" output: > Detected a console login without MFA (requesting user=%ct.user, requesting IP=%ct.srcip, AWS region=%ct.region) priority: CRITICAL source: aws_cloudtrail [/code]

一旦将 Falco 的 CloudTrail 插件配置为以 CloudTrail 跟踪作为输入,Falco 将持续分析跟踪的即将到来的数据,提供实时异常和威胁检测。这就像为您的云活动安装了安全摄像头!

检测示例

这是配置为 AWS 安全时 Falco 可以检测到的一些事物:

  • 有人在 AWS 控制台上未使用多因素身份验证(MFA)登录。

  • 有人为根用户停用了多因素身份验证(MFA)。

  • 有人创建了新的 AWS 用户或组。

  • 有人在非批准的区域运行实例。

  • 有人更改了 S3 存储桶的权限。

  • 有人禁用了 CloudTrail 日志记录。

要获取完整列表,请参考 CloudTrail rules file。

配置和运行 Falco 以保障 CloudTrail 安全

本章的这部分将概述使用 Falco 设置云安全的方法,描述各组件,并指导您正确配置所有内容。正如我们提到的,Falco 与 CloudTrail 的集成通过CloudTrail 插件完成。可以配置插件以三种不同方式接收日志文件:

  • 一个 Simple Queue Service(SQS)队列,传递有关新日志文件的 Simple Notification Service(SNS)通知

  • 一个 S3 存储桶

  • 本地文件系统路径

在这三种方法中,第一种是您在绝大多数生产情况下将使用的方法,因此我们将首先重点介绍它。

通过 SQS 队列接收日志文件

此部署方法利用 SQS 来通知 Falco 新的 CloudTrail 日志产生。当新日志到达时,Falco 会监视 SQS 队列并实时解析这些日志。该过程如图 11-3 所示。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_1103.png

图 11-3. SQS 队列集合图示

在此配置中设置 Falco 的过程包括三个步骤:

  1. 创建 CloudTrail 跟踪并配置与 SNS 主题关联。SNS 主题检测到跟踪将文件存储在其中的 S3 存储桶的更改并广播到全球。

  2. 创建 SQS 队列并将其附加到 SNS 主题。这将创建一个 Falco 可以使用来检测新数据到达的端点。

  3. 配置 Falco 以使用 SQS 队列接收日志。

我们将通过逐步说明来指导您设置所有这些内容,以便您全面了解各个组成部分。但在此之前,我们将向您展示一个简单的快捷方式:一个 Terraform 模块将为您完成这些工作。

基于 Terraform 的部署

您可以在GitHub上找到 Terraform 模块。将存储库克隆到本地计算机,然后执行以下命令:

[code]$ cd examples/single-account $ terraform init $ terraform validate $ terraform apply [/code]

如果一切顺利,您应该获得类似于以下输出:

[code]Apply complete! Resources: 14 added, 0 changed, 0 destroyed. Outputs: cloudtrail_sns_subscribed_sqs_arn = "arn:aws:sqs:*ZZZZ*" cloudtrail_sns_subscribed_sqs_url = "https://sqs.*<REGION>*.amazonaws.com/.../ *<QUEUE_NAME>*" [/code]

您现在可以在falco.yaml文件中使用*<QUEUE_NAME>*了:

[code]plugins: - name: cloudtrail library_path: libcloudtrail.so init_config: "" open_params: "sqs://*`<QUEUE_NAME>`*" - name: json library_path: libjson.so init_config: "" load_plugins: [cloudtrail, json] [/code]

接下来,配置falco.yaml的rules_file部分以加载 CloudTrail 规则:

[code]rules_file: - /etc/falco/aws_cloudtrail_rules.yaml [/code]

现在您可以启动 Falco 了!

手动部署

如果您不想使用 Terraform 脚本,以下是设置使用 SQS 队列的 Falco 的步骤。第一步是创建跟踪。您可以按以下步骤执行:

  1. 转到 AWS 控制台的 CloudTrail 部分。

  2. 单击“创建跟踪”。

  3. 将跟踪命名为Falco

  4. 作为存储位置,您可以选择一个现有的跟踪或告诉 AWS 创建一个新的跟踪。

  5. 不选中“日志文件 SSE-KMS 加密”。SSE 加密是您应该使用的良好实践,但配置它超出了本章的范围。

  6. 勾选“SNS 通知交付”。

  7. 在“创建新 SNS 主题”下,选择新建并命名主题falco-cloudtrail-logs

  8. 单击下一步。

  9. “选择日志事件”页面让您选择要捕获的日志。默认设置足以使 Falco 正常运行。勾选“数据事件”或“排除 Amazon RDS 数据 API 事件”将允许您如有需要创建更精细的数据事件规则,例如 S3 存储桶级别和对象级别的访问。

  10. 点击下一步。

  11. 点击“创建跟踪”。

接下来,创建 SQS 队列:

  1. 转到 AWS 控制台的 SQS 部分。

  2. 点击“创建队列”。

  3. 将队列命名为 falco-queue

  4. Falco 可以直接使用默认访问策略正常运行。但是,考虑实施一个更少权限的访问策略,例如使用 AWS 策略生成器。

  5. 在页面底部点击“创建队列”。这将带您进入 falco-queue 详细信息页面。

  6. 点击“订阅 Amazon SNS 主题”。

  7. 选择名称以 falco-cloudtrail-logs 结尾的主题。

  8. 点击保存。

现在您需要配置 Falco。这涉及设置 AWS 身份验证和配置 Falco 本身。要从 S3 存储桶读取日志文件或从 SQS 队列接收 SNS 通知,Falco 需要身份验证凭据,并且需要配置 AWS 区域。Falco 依赖于与 AWS Go SDK 相同的身份验证机制:环境变量或共享配置文件。请按以下方式配置这些内容:

环境变量

使用 AWS_REGION=*xxx* 指定 AWS 区域,使用 AWS_ACCESS_KEY_ID=*xxx* 指定访问密钥 ID,使用 AWS_SECRET_ACCESS_KEY=*xxx* 指定秘密密钥。以下是一个示例命令行:

[code]AWS_DEFAULT_REGION=us-west-1 \ AWS_ACCESS_KEY_ID=*xxx* \ AWS_SECRET_ACCESS_KEY=*xxx* \ falco -c *<path-to-falco.yaml>* -r *<path-to-falco-rules>* [/code]

共享配置文件

H O M E / . a w s / c o n f i g ∗ 文件中指定 A W S 区域,并在 ∗ HOME/.aws/config* 文件中指定 AWS 区域,并在 * HOME/.aws/config∗文件中指定AWS区域,并在∗HOME/.aws/credentials 文件中指定凭证。以下是这些文件的示例内容:

[code]$HOME/.aws/config [default] region = us-west-1 $HOME/.aws/credentials [default] aws_access_key_id=*<YOUR-AWS-ACCESS-KEY-ID-HERE>* aws_secret_access_key=*<YOUR-AWS-SECRET-ACCESS-KEY-HERE>* [/code]

现在,设置 Falco 本身:

  1. falco.yaml 中添加以下片段以配置基于 SQS 的日志收集:

    [code]plugins: - name: cloudtrail library_path: libcloudtrail.so init_config: "" open_params: "sqs://falco-queue" - name: json library_path: libjson.so init_config: "" load_plugins: [cloudtrail, json] [/code]
  2. 配置 falco.yaml 中的 rules_file 部分以加载 CloudTrail 规则:

    [code]rules_file: - /etc/falco/aws_cloudtrail_rules.yaml [/code]
  3. 启动 Falco。

Et voilà: 您的 AWS 基础设施现在受到保护!

从 S3 存储桶或本地文件系统读取事件

虽然推荐使用基于 SQS 的设置进行实时检测,但 Falco 也可以直接从 S3 存储桶或本地文件系统中读取 CloudTrail 日志。基于 SQS 的设置在处理到达的“实时”日志时起作用,而 S3 和本地文件系统的设置则读取存储的数据。这意味着它们实际上是在过去运行,并且在到达当前存储数据的末尾时会导致 Falco 退出。这种方法在几个方面非常有价值。首先,它允许您在规则开发过程中快速迭代。其次,它允许您在 CloudTrail 日志上“回溯”运行 Falco(即使这些日志已存储了很长时间)。想知道在过去三周内是否有人更改了存储桶的权限?指向日志,您就可以轻松找出!

让我们看看如何以此模式运行 Falco。

S3 存储桶

首先,你需要设置 AWS 认证。我们刚刚描述了如何为 SQS 访问做这些设置,对于 S3 来说也是一样的,所以回到上一节的结尾,按照步骤操作即可。

配置好 AWS 认证后,在 falco.yaml 中添加以下片段:

[code]plugins: - name: cloudtrail library_path: libcloudtrail.so init_config: s3DownloadConcurrency: 64 open_params: > s3://my-s3-bucket/AWSLogs/411571310278/CloudTrail/us-west-1/2021/09/23/ - name: json library_path: libjson.so init_config: "" load_plugins: [cloudtrail, json] [/code]

注意 open_params 键仅仅是 S3 上路径的 URI,你可以通过访问 S3 控制台中的数据并点击 “复制 S3 URI” 轻松获取。你不需要指定整个存储桶;你可以指向子目录甚至特定的日志文件。

现在你需要配置 falco.yaml 中的 rules_file 部分以加载 CloudTrail 规则:

[code]rules_file: - /etc/falco/aws_cloudtrail_rules.yaml [/code]

之后,你只需运行 Falco。它会处理提供的 S3 URI 下的每个文件,并在完成后返回。

从 AWS 外部的机器(比如你的笔记本电脑)解析日志可能会非常慢,因为机器需要下载数据以便处理。你可以通过增加下载并发数(在 init_config 键中的 s3DownloadConcurrency)来加快速度,或者预先使用 AWS CLI 将数据下载到本地,然后指向 Falco 到本地日志(接下来我们将描述)。

本地文件系统路径

你可以通过将以下配置放入 falco.yaml 中来处理存储在本地文件系统中的 CloudTrail 日志:

[code]plugins: - name: cloudtrail library_path: libcloudtrail.so init_config: "" open_params: > /home/user/cloudtrail-logs/059797578166_CloudTrail_us-east-1_2021... - name: json library_path: libjson.so init_config: "" load_plugins: [cloudtrail, json] [/code]

你可以指向单个文件或目录,Falco 将递归读取目录中的所有文件。

你还需要编辑 falco.yaml 中的 rules_file 部分以加载 CloudTrail 规则:

[code]rules_file: - /etc/falco/aws_cloudtrail_rules.yaml [/code]

完成以上步骤后,只需运行 Falco。它会处理所有文件并在完成后退出。

扩展 Falco 的 AWS 规则集

Falco 提供了一个强大的基于 CloudTrail 的规则集。然而,如果需要定制,CloudTrail 插件导出了丰富的字段集,可以用于以高精度制定自己的规则。

Falco 规则的编写将在第十三章中进行详细讨论。然而,由于该章节主要集中在基于系统调用的规则上,这里有一些可以帮助你开始云规则开发的提示:

  • CloudTrail 规则需要包含以下关键字:source: aws_cloudtrail。这告诉 Falco 规则条件和输出中的字段必须来自 CloudTrail 插件。

  • 通过使用 --list=aws_cloudtrail Falco 命令行开关,你可以获取可以在 CloudTrail 规则中使用的字段列表。同时,请参阅第六章中的 Table 6-10。

其他云平台呢?

AWS 是云计算中非常重要的一部分,所以 Falco 首先增加了对它的支持。然而,在撰写本文时,Falco 社区正在努力增加对 Microsoft Azure 和 Google Cloud Platform 的支持。预计长远来看会添加更多的云平台!

如果您想了解 Falco 是否支持您的云平台,请查看GitHub 上的插件仓库。

结论

在本章中,您了解到 Falco 不仅涉及系统调用和容器,还了解了如何利用它来保护您的云软件并大大提升安全姿态。在下一章中,我们将转向输出方面,并展示如何收集和处理 Falco 事件。

第十二章:消费 Falco 事件

到目前为止,您已经学会了如何运行和配置 Falco。您了解 Falco 如何用于运行时和云安全,以及它如何检测广泛的威胁。现在,是时候关注您可以如何处理 Falco 检测的内容了。消费 Falco 的输出是这个拼图的最后一块,也是本章的主题。

Falco 生成的警报对于观察和保护生产系统非常有帮助,我们将为您提供如何有效使用这些警报的建议。本章的第一部分是关于帮助您有效消费 Falco 输出的工具。我们将教您如何在 Falco 检测到安全威胁时立即获得通知,以便您的安全团队尽快采取适当的对策。最后,我们将展示一种自动响应威胁以加快响应时间的机制。

处理 Falco 输出

最小化的 Falco 安装会输出一个简单的文本日志,您可以稍后查阅,但这并不是很有用。幸运的是,更智能的工具允许您处理 Falco 的输出并扩展其功能,这些工具是将 Falco 整合到您生态系统中的重要部分。

本节将详细讨论本书中已提及的两个工具。第一个工具是 falco-exporter,它专为一个目标而设计:从 Falco 检测的事件生成指标。第二个工具 Falcosidekick 则是 Falco 输出的瑞士军刀,它允许您聚合来自多个 Falco 传感器的数据,过滤通知,并将它们转发到您环境中的任何其他应用程序或平台。

falco-exporter

falco-exporter 项目 提供了用于 Falco 输出事件的 Prometheus 指标导出器。它通过流式 gRPC API 消费 Falco 输出,并公开指标端点。这些指标包括触发规则的数量信息,以及与规则相关的优先级和标签的详细信息,还包括用于识别每个事件来源的标签,例如主机名、命名空间和 Pod 名称。它还提供了一个预配置的 Grafana 仪表板。^(1) falco-exporter 对于只需要关于安全事件的指标非常有用。(相比之下,Falcosidekick 也可以导出指标,但它具有许多其他功能和输出。)

在安装 falco-exporter 之前,请确保已安装并配置了 Falco,且启用了通过 Unix socket 的 gRPC 服务器和 gRPC 输出(参见“gRPC 输出”进行复习)。

主机安装

要直接在主机上安装 falco-exporter,您需要从 发布页面 下载最新版本,解压存档,并将可执行文件 falco-exporter 复制到您喜欢的位置(例如 /usr/bin)。无论您是手动执行还是作为服务运行都可以。默认选项与 gRPC Unix 套接字 /var/run/falco.sock(Falco 的默认选项)兼容。如果您需要自定义选项,请运行 falco-exporter --help 获取帮助。

在容器中运行

要在使用 Docker 容器中运行 falco-exporter,请使用以下命令:

[code]$ docker pull falcosecurity/falco-exporter:latest $ docker run -v /var/run/falco.sock:/var/run/falco.sock \ falcosecurity/falco-exporter:latest [/code]

docker run 命令假设 Falco 已安装在主机上,并且 Falco 的 gRPC Unix 套接字位于 /var/run/falco.sock

部署到 Kubernetes

您可以使用 Helm 或清单文件将 falco-exporter 部署到 Kubernetes 集群(有关两种安装方法的详细信息,请参阅 第九章)。我们推荐使用 Helm。首先需要添加 Falcosecurity 图表存储库:

[code]$ helm repo add falcosecurity https://falcosecurity.github.io/charts $ helm repo update [/code]

然后,要安装图表,请运行:

[code]$ helm install falco-exporter falcosecurity/falco-exporter [/code]

有关详细说明,请参阅 falco-exporter 图表文档。如果要使用清单文件,请按照 falco-exporter 文档 中的步骤操作。

Falcosidekick

Falcosidekick 项目 提供了连接 Falco 到您生态系统的完整解决方案。它在 Falco 输出的基础上工作,并允许您将其通知转发到许多其他目的地(参见 图 12-1)。Falcosidekick 可以向通知添加自定义字段或按优先级过滤事件(按目的地分)。特别支持的输出包括以下平台和应用程序:

  • 沟通与协作

  • 指标和可观察性

  • 警报

  • 日志和存储

  • 函数即服务(FaaS)和无服务器

  • 消息队列和流式传输

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_1201.png

图 12-1. Falcosidekick 标志(左)及其支持的部分通知目标(右)

Falcosidekick 还允许您使用一个辅助项目,falcosidekick-ui,在愉快的 web UI 中可视化 Falco 事件(如 图 12-2 所示)。Web UI 显示有关检测事件的统计信息,并以聚合形式和时间线显示值。您还可以筛选您感兴趣的事件并快速获取所有事件详细信息。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_1202.png

图 12-2. Falcosidekick web UI

使用 Falcosidekick 需要对 Falco 的配置进行小修改:在使用之前,启用 JSON 格式化并配置 HTTP 输出以将事件发送到 Falcosidekick 端点(默认监听端口 2801)。有关 Falco 输出配置说明,请参阅 第八章,有关特定细节,请参阅 Falcosidekick 在线文档。

主机安装

要直接在主机上安装 Falcosidekick,请从发布页面下载最新版本,解压缩存档,并将可执行文件 falcosidekick 复制到您喜欢的位置(例如 /usr/bin)。是否手动执行或作为服务运行完全取决于您。您还需要创建一个 YAML 配置文件并将其路径作为参数传递。例如:

[code]$ falcosidekick -c falcosidekick_config.yaml [/code]

Falcosidekick 仓库包含一个示例配置文件,您可以从中开始。Falcosidekick 还支持环境变量,您可以用其作为配置文件值的替代方案或进行覆盖。

在容器中运行

若要在使用 Docker 的容器中运行 Falcosidekick,请使用以下命令:

[code]$ docker pull falcosecurity/falcosidekick:latest $ docker run -d -p 2801:2801 falcosecurity/falcosidekick:latest [/code]

docker run 命令假定 Falco 已安装在主机上,并且 HTTP 输出已配置为将事件发送到端口 2801。使用 Docker 的 -e 选项,您可以使用环境变量传递配置。或者,使用 Docker 的 -v 选项给它一个 YAML 配置文件。

部署到 Kubernetes

与 falco-exporter 类似,您可以使用 Helm 或清单文件将 Falcosidekick 部署到 Kubernetes 集群中。我们建议使用 Helm 安装选项,它有两种变体。在我们探索它们之前,如果您还没有将 Falcosecurity 图表仓库添加到 Helm,请通过运行以下命令来添加:

[code]$ helm repo add falcosecurity https://falcosecurity.github.io/charts $ helm repo update [/code]

现在,您可以准备部署到您的 Kubernetes 集群了。这样做的第一种更普通的方式是,当您已经部署并配置了 Falco 来发送事件到 Falcosidekick,并且只需安装 Falcosidekick 图表:

[code]$ helm install falcosidekick falcosecurity/falcosidekick [/code]

另一种变体允许您在单个 Helm 安装中部署 Falco 和 Falcosidekick,并自动配置这两个图表以共同工作。通常这是最方便的解决方案。要执行此操作,请运行:

[code]$ helm install falco falcosecurity/falco --set falcosidekick.enabled=true [/code]

可选地,如果您还想要部署 Falcosidekick 的 Web UI,请在安装命令中添加 --set webui.enabled=true(无论您选择哪种变体)。

您可以在Falcosidekick 图表文档中找到关于其他选项的详细信息。如果您想使用清单文件,可以使用提供的在线示例。^(2)

可观察性和分析

Falco 允许您观察和分析您的云原生环境的安全性。如果您计划利用 Falco 的检测功能进行审计或取证,通常需要尽可能多地存储信息,并使 Falco 的结果易于访问和搜索。本章描述的工具将为您提供充分的支持。

存储 Falco 事件就像摄取任何其他应用程序日志一样。这意味着您可以重用现有的日志后端用于 Falco。此外,Falcosidekick 可以轻松地将 Falco 事件发送到允许您存储和分析大量日志数据的系统,如 Elasticsearch 和 Splunk。由于您可能会使用这种方法进行后续分析,我们建议保留 Falco 发出的所有事件,不进行任何过滤。

您可能还希望收集指标,因为这可以帮助您检测应用程序中的错误和异常。例如,一个指标报告 Falco 规则在特定机器上定期触发可能是安全问题、配置错误或正在运行的应用程序中的实现 bug 的症状。用于此目的的可靠工具是 falco-exporter:它公开指标,连接 Falco 到 Prometheus,并提供一个预配置的 Grafana 仪表板(图 12-3)。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_1203.png

图 12-3. falco-exporter 提供的预配置 Grafana 仪表板,用于展示 Falco 事件指标

接收通知

尽管存储和聚合 Falco 事件对于可观察性是可以的,但在需要立即对安全事件做出反应时并不有用。您可能希望立即且在正确的位置接收重要的通知,以便您或您的团队可以立即采取对策或开始调查。

Falco 的内置输出通道没有提供特定的即时通知机制,但是 Falcosidekick 允许您仅转发重要的通知。例如,假设您希望在事件触发 Sudo 潜在权限升级 规则(具有 priority: CRITICAL)时收到通知,而不是其他优先级较低的更嘈杂的规则。Falcosidekick 允许您配置一个最低优先级级别,以便将事件发送到特定目的地,并可以为每个目的地调整此配置。它支持大多数的呼叫系统,如 PagerDuty、Opsgenie 和 Prometheus Alertmanager,并且可以将通知发送到包括 Slack、Mattermost、Rocket.Chat、Microsoft Teams 和 Discord 在内的大多数常见通信平台。

您可以使用 Falcosidekick 的配置轻松地将 Falco 警报集成到现有环境中。而且因为 Falcosidekick 允许您同时将 Falco 通知发送到多个目的地,例如同时将警报发送到 PagerDuty 和 Slack 频道。

响应威胁

另一种有意义且更复杂的使用 Falco 事件的方式是创建系统,以自动响应威胁或安全事件。实施针对威胁的自定义操作比您想象的要容易。

虽然 Falco 项目本身不提供专门用于此目的的工具,但社区中的一些新兴项目正在实现这一概念。这类系统有时被称为 响应引擎,通常专门用于管理 Kubernetes 中的威胁。

响应引擎提供了一个简单的机制,用于在违反 Falco 规则条件时执行预定义任务。您可以使用 Falcosidekick 创建一个简单的实现,将 Falco 通知转发到一个 FaaS 平台或无服务器解决方案,该解决方案进而执行所需的操作。例如,您可以通过实现一个使用 Kubernetes API 删除受损 Pod 的云函数来自动终止 Kubernetes Pod,每当 Falco 规则确定该 Pod 受到威胁时。Figure 12-4 展示了这种方法,并展示了 Falcosidekick 支持的一些云函数提供者。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/pcns_1204.png

图 12-4. Kubernetes 响应引擎功能方案示例,使用 Falcosidekick 输出执行操作

您可能希望无论规则的优先级如何都收到通知,但您可能只希望针对特定规则执行操作。例如,您可能只希望具有 CRITICAL 优先级的规则终止 Pods。Falcosidekick 在此方面非常有帮助,因为它允许您基于其优先级值过滤通知,从而控制每个目标接收的信息。

我们建议您分析您的需求并设计响应引擎以满足这些需求。Falco 和类似 Falcosidekick 的工具将为支持您的解决方案提供所需的一切。

结论

本章结束了 第三部分。您已经了解了在生产环境中运行 Falco 的所有基本方面,并且现在可以为几乎任何需求和场景配置和定制它。您还了解了如何正确消费 Falco 事件并将其集成到您的生态系统中。

在 第四部分 中,您将超越普通用户的知识,学习如何扩展 Falco 以满足任何高级需求。

^(1) Grafana 仪表板 是一组组织良好的 UI 元素,用于可视化数据。仪表板配置可以存储在文件中并进行共享。您可以从 Grafana 的 在线画廊 获取大多数可用的仪表板。

^(2) Falcosidekick 示例清单文件的实际 URL 可能会不时更改,但您始终可以在 Falcosecurity GitHub 组织下找到它们。请注意,任何 Helm 图表都可以生成这样的文件。事实上,与 Falco 的清单文件一样,Falcosidekick 的文件也是从其图表开始渲染的。

第四部分:扩展 Falco

第十三章:编写 Falco 规则

欢迎来到本书的第 IV 部分!现在你已经了解了 Falco 的基本信息和功能(第 I 部分),理解了其架构的复杂性(第 II 部分),并且在部署和运行它方面已经很专业了(第 III 部分),现在是时候再次提升你的水平了。

本书的最后部分(第十三章至第十五章)讨论的是超越默认内容的内容。你将学习如何根据自己的特定需求定制 Falco,以及如何(如果你愿意的话)将你的改进贡献给项目,使整个社区受益。这是释放你创造力的地方。

我们在本书中已经广泛讨论了规则,特别是在第七章中。但是,当你能够创建自己的规则并将现有规则适应你的环境时,你才能解锁 Falco 的真正力量——这正是我们将在这里向你展示如何做到的。

本章假设你对字段和过滤器有很好的理解(在第六章中介绍),以及规则和规则文件的基础知识(在第七章中介绍)。如果你觉得需要恢复记忆,只需回到那些章节。我们会等你准备好的。

定制默认的 Falco 规则

虽然 Falco 的默认规则集是丰富且不断扩展的,但在遇到需要自定义这些规则的情况下并不少见。以下是一些例子:

  • 你希望扩展某个规则的范围或增加其覆盖范围。

  • 你希望缩减 Falco 加载的规则数量,以降低其 CPU 使用率。

  • 你希望通过控制规则的行为或向其添加异常来减少警报噪声。

Falco 提供了一个框架,可以在不必分叉默认规则文件并维护自己的副本的情况下完成这些事情。第七章 教会了你如何替换和追加宏、列表和规则,以及如何禁用规则。这尤为重要,因为正如你在第十章中学到的那样,规则文件加载的顺序很重要,而你可以控制这个顺序。这意味着你可以在初始化链中后加载的单独文件中更改现有规则。

默认的 Falco 配置被设计为利用这种机制,提供了两个可以在不触及默认规则集的情况下定制现有规则的地方。 第一个是falco_rules.local.yaml。 这个文件最初是空的,在加载falco_rules.yaml之后加载,因此是禁用或修改默认规则集中规则的好地方。 第二个是*/etc/falco/rules.d*。 默认情况下,Falco 会加载此目录中找到的所有规则文件,在加载falco_rules.yamlfalco_rules.local.yaml后加载。 这使其成为另一个进行自定义的好地方。

写作新的 Falco 规则

从本质上讲,编写新规则只是制作条件和输出的问题,因此在概念上它是一个非常简单的过程。 然而,在实践中,需要考虑几个因素。 即兴的规则开发通常导致不完善甚至无法使用的规则。 经验丰富的 Falco 用户倾向于开发自己的规则编写流程,我们建议您也这样做。 最佳流程取决于您的设置、目标环境和喜好,因此我们无法为您提供绝对的处方。 相反,我们将分享我们的做法,希望它能为您提供灵感和指导。

我们的规则开发方法

本书作者使用的规则开发方法由九个步骤组成:

  1. 复制您想要检测的事件。

  2. 捕获事件并将其保存在跟踪文件中。

  3. 使用 sysdig 的帮助制作和测试条件过滤器。

  4. 使用 sysdig 的帮助来制作和测试输出。

  5. 将 sysdig 命令行转换为规则。

  6. 在 Falco 中验证规则。

  7. 模块化和优化规则。

  8. 创建一个回归。

  9. 将规则与社区分享。

在接下来的几节中,我们将扩展列表中的每一项,并提供一个真实的例子,引导您完成制作一个新规则的过程,该规则检测试图在*/proc*、/bin和*/etc*目录内创建符号链接的尝试^(1)。 这至少是奇怪的行为,并且可能表明可疑活动。 下面是如何应用我们的方法来构建这样一个规则。

1. 复制您想要检测的事件

要创建可靠的规则,几乎不可能没有测试和验证,因此第一步是重新创建规则应该检测到的场景(或场景)。 在这种情况下,您想要检测三个特定目录中的符号链接的创建。 您可以使用终端中的ln命令重新创建该场景:

[code]$ ln -s ~ /proc/evillink $ ln -s ~ /bin/evillink $ ln -s ~ /etc/evillink [/code]

2. 捕获事件并将其保存在跟踪文件中

现在,您可以使用 sysdig 捕获可疑活动。 (如果您需要 sysdig 和跟踪文件的复习,请返回到“观察系统调用”。) sysdig 允许您使用-w命令行标志轻松将活动存储在跟踪文件中。 要查看其工作原理,请在终端中发出以下命令:

[code]$ sysdig -w evillinks.scap [/code]

在另一个终端中,再次运行三个ln命令,然后返回第一个终端并使用 Ctrl-C 停止 sysdig。现在,您可以随意检查您的活动跟踪文件多次:

[code]$ sysdig -r evillinks.scap [/code]

您会注意到跟踪文件包含所有主机的活动,而不仅仅是您的ln命令。您还会注意到文件相当大。通过在运行捕获时使用过滤器,您可以使其更小并更易于检查:

[code]$ sysdig -w evillinks.scap proc.name=ln [/code]

现在,您拥有一个少于 1 MB 大小的无噪声文件,其中只包含您需要制作规则的特定活动。将触发规则的活动保存在跟踪文件中有几个优点:

  • 它只需要复制复杂行为一次。(并非所有可疑行为都像运行ln三次那样简单!)

  • 它允许您专注于事件并留在单个终端中,而无需多次复制触发规则的命令。

  • 它允许您在不同的机器上开发规则。您甚至不需要在行为发生的机器上部署和配置 Falco!如果您希望捕获云容器或边缘设备等“不友好”环境中的行为,这真是太好了。

  • 它使您能够以普通用户权限开发规则。

  • 它提供了一致性,不仅对于创建规则很有用,而且在完成规则后实施回归测试时也很有用。

3. 使用 sysdig 制作并测试条件过滤器

现在您已经拥有所需的数据,是时候处理条件了。通常,在这个阶段,您会想要回答几个问题:

  1. 您需要针对什么类型的系统调用(或系统调用)?当然,并非所有的 Falco 规则都基于系统调用;例如,您可能在使用插件。但总体而言,识别将触发规则的事件类型是首要任务。

  2. 一旦确定要解析的事件,您需要检查其参数或参数中的哪些?

sysdig 可以帮助您回答这些问题。使用它来读取和解码捕获文件:

[code]$ sysdig -r evillinks.scap [/code]

在输出文件的末尾就是魔法发生的地方:

[code]2313 11:21:22.782601383 1 ln (23859) > symlinkat 2314 11:21:22.782662611 1 ln (23859) < symlinkat res=0 target=/home/foo linkdirfd=-100(AT_FDCWD) linkpath=/etc/evillink [/code]

我们的系统调用是symlinkat。系统调用的manpage告诉您它是另一个系统调用symlink的变体。您还可以看到linkpath参数包含符号链接的文件系统路径。这正是您需要了解的内容,以便制作您的过滤器,应如下所示:

[code](evt.type=symlink or evt.type=symlinkat) and ( evt.arg.linkpath startswith /proc/ or evt.arg.linkpath startswith /bin/ or evt.arg.linkpath startswith /etc/ ) [/code]

您可以立即利用 sysdig 验证这是正确的过滤器:

[code]$ sysdig -r evillinks.scap \ "(evt.type=symlink or evt.type=symlinkat) and \ (evt.arg.linkpath startswith /proc/ or \ evt.arg.linkpath startswith /bin/ or \ evt.arg.linkpath startswith /etc/)" 438 11:21:13.204948767 2 ln (23814) < symlinkat res=-2(ENOENT) target=/home/foo linkdirfd=-100(AT_FDCWD) linkpath=/proc/evillink 1679 11:21:19.420360948 0 ln (23850) < symlinkat res=0 target=/home/foo linkdirfd=-100(AT_FDCWD) linkpath=/bin/evillink 2314 11:21:22.782662611 1 ln (23859) < symlinkat res=0 target=/home/foo linkdirfd=-100(AT_FDCWD) linkpath=/etc/evillink [/code]

太好了!输出正确显示了三个应触发规则的系统调用。

4. 使用 sysdig 制作并测试输出

sysdig 非常方便,可以帮助你创建规则的输出。特别是 sysdig 的-p标志,接收一个与 Falco 兼容的字符串作为输入,并用它打印类似 Falco 的输出到终端,以便于测试规则的输出,知道当规则触发时 Falco 将显示相同的内容。例如,以下看起来是规则的一个很好的输出:

[code]a symlink was created in a sensitive directory (link=%evt.arg.linkpath, target=%evt.arg.target, cmd=%proc.cmdline) [/code]

在 sysdig 中与过滤器一起进行测试:

[code]$ sysdig -r evillinks.scap \ -p"a symlink was created in a sensitive directory \ (link=%evt.arg.linkpath, target=%evt.arg.target, cmd=%proc.cmdline)" \ "(evt.type=symlink or evt.type=symlinkat) and \ (evt.arg.linkpath startswith /proc/ or \ evt.arg.linkpath startswith /bin/ or \ evt.arg.linkpath startswith /etc/)" a symlink was created in a sensitive directory (link=/proc/evillink, target=/home/foo, cmd=ln -s /home/foo /proc/evillink) a symlink was created in a sensitive directory (link=/bin/evillink, target=/home/foo, cmd=ln -s /home/foo /bin/evillink) a symlink was created in a sensitive directory (link=/etc/evillink, target=/home/foo, cmd=ln -s /home/foo /etc/evillink) [/code]

注意过滤器和输出条件周围的引号。这可以防止 Shell 因为它们包含的任何字符而混淆。

你的条件和输出看起来非常不错。是时候切换到 Falco 了!

5. 将 sysdig 命令行转换为规则

下一步是将你拥有的内容转换为 Falco 规则。这只是一个复制粘贴的练习,因为你已经知道条件和输出是如何工作的:

[code]- rule: Symlink in a Sensitive Directory desc: > Detect the creation of a symbolic link in a sensitive directory like /etc or /bin. condition: > (evt.type=symlink or evt.type=symlinkat) and ( evt.arg.linkpath startswith /proc/ or evt.arg.linkpath startswith /bin/ or evt.arg.linkpath startswith /etc/) output: > a symlink was created in a sensitive directory (link=%evt.arg.linkpath, target=%evt.arg.target, cmd=%proc.cmdline) priority: WARNING [/code]

6. 在 Falco 中验证规则

将规则保存在名为symlink.yaml的 YAML 文件中。现在在 Falco 中测试它只需使用-r标志加载它,然后使用-e标志使用捕获文件作为输入:

[code]$ falco -r symlink.yaml -e evillinks.scap 2022-02-05T01:09:23+0000: Falco version 0.31.0 (driver version 319368f1ad778691164d33d59945e00c5752cd27) 2022-02-05T01:09:23+0000: Falco initialized with configuration file /etc/falco/falco.yaml 2022-02-05T01:09:23+0000: Loading rules from file symlink.yaml: 2022-02-05T01:09:23+0000: Reading system call events from file: evillinks.scap 2022-02-04T19:21:13.204948767+0000: Warning a symlink was created in a sensitive directory (link=/proc/evillink, target=/home/foo, cmd=ln -s /home/foo /proc/evillink) 2022-02-04T19:21:19.420360948+0000: Warning a symlink was created in a sensitive directory (link=/bin/evillink, target=/home/foo, cmd=ln -s /home/foo /bin/evillink) 2022-02-04T19:21:22.782662611+0000: Warning a symlink was created in a sensitive directory (link=/etc/evillink, target=/home/foo, cmd=ln -s /home/foo /etc/evillink) Events detected: 3 Rule counts by severity: WARNING: 3 Triggered rules by rule name: Symlink in a Sensitive Directory: 3 Syscall event drop monitoring: - event drop detected: 0 occurrences - num times actions taken: 0 [/code]

规则触发了预期次数,并显示了正确的输出。恭喜!

注意,在 Falco 中,你可以利用与 sysdig 创建的相同跟踪文件。-e命令行选项告诉 Falco:“从给定文件读取系统调用,而不是使用驱动程序。当你到达文件末尾时,打印摘要并返回。”对于快速迭代非常方便!

7. 模块化和优化规则

你已经有一个工作规则并进行了测试,但还有改进的空间。第 7 步是将规则模块化:

[code]- macro: sensitive_sylink_dir condition: > (evt.arg.linkpath startswith /proc/ or evt.arg.linkpath startswith /bin/ or evt.arg.linkpath startswith /etc/) - macro: create_symlink condition: (evt.type=symlink or evt.type=symlinkat) - rule: Symlink in a Sensitive Directory desc: > Detect the creation of a symbolic link in a sensitive directory like /etc or /bin. condition: create_symlink and sensitive_sylink_dir output: > a symlink was created in a sensitive directory (link=%evt.arg.linkpath, target=%evt.arg.target, cmd=%proc.cmdline) priority: WARNING [/code]

这将条件的检查移入宏中,使条件更短更易读。这很棒,但你还可以做得更好:

[code]- list: symlink_syscalls items: [symlink, symlinkat] - list: sensitive_dirs items: [/proc/, /bin/, /etc/] - macro: create_symlink condition: (evt.type in (symlink_syscalls)) - macro: sensitive_sylink_dir condition: (evt.arg.linkpath pmatch (sensitive_dirs)) - rule: Symlink in a Sensitive Directory desc: > Detect the creation of a symbolic link in a sensitive directory like /etc or /bin. condition: create_symlink and sensitive_sylink_dir output: > a symlink was created in a sensitive directory (link=%evt.arg.linkpath, target=%evt.arg.target, cmd=%proc.cmdline) priority: WARNING [/code]

在这里所做的是将条件常量移入列表中。这有多个好处。首先,以一种非侵入性的方式使规则易于扩展。如果你想要添加另一个敏感目录,可以通过将相关项目添加到列表或者更好地说,通过创建第二个symlink_syscalls列表来添加它。这还让你有机会通过使用in和pmatch等操作符来优化规则,以便进行高效的多重检查。

8. 创建一个回归测试

当你创建一个新规则时,特别是如果你的目标是将其包含在官方规则集中,你可能希望在将来能够进行测试。例如,你可能希望确保它仍然能在 Falco 的新版本或不同的 Linux 发行版上工作。你还可能希望在压力下测量其性能(如 CPU 利用率)。你在过程开始时创建的捕获文件是回归测试的良好基础。

作为替代方案,Falco 社区创建了一个名为事件生成器的工具(在第二章中提到),用于测试。该工具对于你添加规则操作非常有用,你或其他人可以在任意机器上实时触发规则。该工具可以以灵活的方式重播触发规则的场景,包括多次触发规则和特定频率触发规则。因此,你可以精确测量其 CPU 利用率。你还可以检查在重压下,规则是否会导致 Falco 性能下降到驱动程序开始丢弃系统调用的程度。

讨论事件生成器的全部内容超出了本书的范围,但你可以查看其GitHub 存储库以了解更多信息。

9. 与社区分享规则

恭喜,你已经完成了全新规则的开发!现在很重要的一点是,Falco 是社区为社区编写的工具。你编写的每一个新规则都可能对许多其他人有价值,因此你应考虑将其贡献给默认规则集。第十五章将教你一切关于向 Falco 贡献的知识。作为 Falco 的维护者和社区成员,我们预先感谢你决定与社区分享的所有规则。

写规则时需要记住的事项

现在我们已经掌握了基础知识,让我们讨论一些略微高级但在开发规则时非常重要的概念。

优先级

如第七章所述,每个 Falco 规则必须有一个优先级。规则优先级通常与输出一起报告,可以有以下值之一:

  • EMERGENCY

  • ALERT

  • CRITICAL

  • ERROR

  • WARNING

  • NOTICE

  • INFORMATIONAL

  • DEBUG

选择适当的规则优先级非常重要,因为通常会基于优先级筛选规则。将规则分配过高的优先级可能会导致警报洪水并降低其价值。

官方 Falco 文档关于如何在默认规则集中使用优先级的解释如下:

  • 如果规则涉及写入状态(文件系统等),其优先级为ERROR。

  • 如果规则涉及未经授权的状态读取(读取敏感文件等),其优先级为WARNING。

  • 如果规则涉及意外行为(在容器中生成意外 shell、打开意外网络连接等),其优先级为NOTICE。

  • 如果规则涉及违反良好实践(意外的特权容器、挂载敏感文件系统、以 root 身份运行交互式命令),其优先级为INFORMATIONAL。

噪音

噪音是制定规则时需要考虑的最关键因素之一,也是安全领域中一般复杂话题。检测工具如 Falco 中检测精度和误报生成之间的权衡是一个持续的紧张源。

通常说,唯一没有误报的规则集是没有规则的规则集。完全避免误报是极其困难并且常常是不切实际的目标,但您可以遵循一些指导原则来减少这个问题:

指南 1:测试和验证。

在生产环境中使用规则之前,请确保在尽可能多的环境中广泛测试它(不同的操作系统发行版、内核、容器引擎和编排器)。

指南 2:优先级及基于优先级的过滤是您的好帮手。

避免首次使用ERROR或CRITICAL作为优先级部署规则。从DEBUG或INFO开始,观察情况,如果噪音不大,再逐步提升优先级。低优先级规则可以在输出管道的不同阶段轻松过滤,因此不会在半夜唤醒安全运营中心团队。

指南 3:利用标签。

您分配给规则的标签包含在 Falco 的 gRPC 和 JSON 输出中。这意味着您可以使用它们来补充优先级并更加灵活地过滤 Falco 的输出。

指南 4:计划异常。

良好的规则设计考虑到已知和未知的异常情况,以一种可读且模块化的方式,并且可以轻松扩展。

例如,看看默认规则集中的写入 rpm 数据库以下规则:

[code]- rule: Write below rpm database desc: an attempt to write to the rpm database by any non-rpm related program condition: > fd.name startswith /var/lib/rpm and open_write and not rpm_procs and not ansible_running_python and not python_running_chef and not exe_running_docker_save and not amazon_linux_running_python_yum and not user_known_write_rpm_database_activities output: > Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline container_id=%container.id image=%container.image.repository) priority: ERROR tags: [filesystem, software_mgmt, mitre_persistence] [/code]

注意已知异常如何作为宏(rpm_procs,ansible_running_python等)包含在规则中,但规则还包括一个宏(user_known_write_rpm_database_activities),让用户通过覆盖机制添加自己的异常。

性能

性能是撰写和部署规则时需要考虑的另一个重要主题,因为 Falco 通常与高频数据源一起运行。当您将 Falco 与诸如内核模块或 eBPF 探针之类的系统调用源一起使用时,您的整个规则集可能需要每秒评估数百万次。在这样的频率下,规则的性能至关重要。

拥有紧凑的规则集绝对是保持 Falco CPU 利用率可控的良好实践,正如您在第十章中学到的那样。然而,同样重要的是确保您创建的每个新规则都针对性能进行了优化。您的规则的开销或多或少与规则条件需要为每个输入事件执行的字段比较数量成正比。因此,您应该期望像这样一个简单条件:

[code]proc.name=p1 [/code]

与像这个更复杂的规则相比,将会使用大约 20%的 CPU:

[code]proc.name=p1 or proc.name=p2 or proc.name=p3 or proc.name=p4 or proc.name=p5 [/code]

优化规则就是确保在大多数常见情况下,Falco 引擎需要执行尽可能少的比较。

以下是降低规则 CPU 利用率的一些指南:

  • 规则应始终从事件类型检查开始(例如evt.type=open或evt.type in (mkdir, mkdirat))。Falco 在这方面很智能:它能理解当你的规则仅限于某些事件类型时,并且仅在接收到匹配事件时评估规则。换句话说,如果你的规则以evt.type=open开头,Falco 甚至不会为任何非open系统调用的事件开始评估它。这是如此有效(和重要!)以至于当规则不包含事件类型检查时,Falco 会发出警告。

  • 在你的规则中,包括那些有较高失败概率的激进比较,最好是在早期而不是晚期。Falco 条件类似于编程语言中的if语句:它从左到右评估,直到某些条件失败为止。你越早让条件失败,完成工作所需的工作量就越少。尝试找到限制规则范围的简单方法。你能将其限制在特定的进程、文件或容器吗?能够仅应用于特定用户的子集吗?在规则中编码这些限制,尽早实现。

  • 复杂的重型规则逻辑应包含在激进比较和限制之后(向右)。例如,长的异常列表应放在规则的末尾。

  • 尽可能使用多值运算符,如in和pmatch,而不是编写多个比较。换句话说,evt.type in (mkdir, mkdirat)比evt.type=mkdir or evt.type=mkdirat更好。多值运算符经过了大量优化,在值数量增多时效果更好。

  • 通常情况下,小而简单是好的。养成尽可能保持简单的习惯。这不仅会加快处理规则的速度,还会确保它们易读且易维护!

标记

标记是制定规则的强大工具。它有三个重要用途:灵活过滤 Falco 加载的规则、为其输出添加上下文、支持通知过滤和优先级设置,从而减少噪音。慷慨地使用标记将提高你的 Falco 体验,并确保你充分利用你的规则。

结论

这是一章的高强度内容!编写规则是一个要求严格但也可以很有趣和创造性的主题。而且,编写完美的规则以执行令人印象深刻的检测将使你在同事中获得很多赞誉。

^(1) 符号链接(symlink)一词是符号连接(symbolic link)的缩写;在 Unix 中,它表示对另一个文件或目录的引用。

第十四章:Falco 开发

扩展 Falco 是确保其完全符合您独特需求的最佳方式。本章将展示三种扩展 Falco 的方法。我们将首先概述 Falco 的代码库,并快速指导如何从源代码构建 Falco,这样您可以直接处理 Falco 的代码。这种第一种方法给予您更多自由,但可能比其他两种方法更困难,也许不太方便。第二种方法允许您通过与 gRPC API 交互构建处理 Falco 通知的应用程序。第三种方法是扩展 Falco 的标准且最简单的方式:编写您自己的插件。

对于最后两种方法,我们将通过示例来进行讲解。在这些代码片段中,我们使用 Go 编程语言,因此对其有一些了解将会有所帮助,但不是必需的。本章还假定您已经阅读了本书的第二部分。如果您担心这些材料可能过于困难,不要害怕:我们认为即使您不是开发人员,您也会发现它易于理解且有趣。

与代码库一起工作

Falco 是开源的,其所有源代码都存储在 GitHub 上的 Falcosecuriy 组织下。要开始浏览代码库,您只需要一个浏览器。如果您希望将源代码存储在本地并使用您喜欢的编辑器打开它,您需要使用 Git。

Falcosecurity 组织托管了 Falco 和许多其他相关项目。社区非常活跃,因此您还会找到许多实验性项目。Falco 项目的核心存放在两个主要仓库中:falcosecurity/falcofalcosecurity/libs

falcosecurity/falco 仓库

falcosecurity/falco 仓库 包含 falco 用户空间程序(通常与您进行交互的程序)的源代码。这是主要且最重要的仓库。该项目组织如下:

/cmake

在这里,您可以找到 Falco 构建系统用于拉取依赖项和实现特定功能的 cmake 模块,包括在构建过程中拉取 falcosecurity/libs 源代码的 cmake 文件。

/docker

此文件夹分为各种子目录,每个子目录包含 Falco 容器镜像的源代码。一些并未发布,因为它们仅供开发使用。详细信息请参阅README 文件。

/proposals

此文件夹包含由社区提出并由维护者批准的设计提案。您可能会在这里找到有用的信息,帮助您理解 Falco 作者在某些架构决策及其背后的理由上做出的决定。

/rules

默认的规则文件存储在这里。

/scripts

此文件夹中包含各种脚本文件。例如,您将在此找到 falco-driver-loader 脚本的源代码。

/test/tests

这两个文件夹分别包含 Falco 的回归测试和单元测试。

/userspace

Falco 的实际 C++源代码位于这个文件夹中。它的内容被组织成两个子目录:engine,其中包含规则引擎实现,以及falco,其中包含高层次功能的实现,如输出通道、gRPC 服务器和 CLI 应用程序。

尽管这是 Falco 主仓库,但项目的大部分源代码并不在这里。大部分实际上在falcosecurity/libs仓库中,它包含 Falco 的核心低级逻辑的实现。

falcosecurity/libs 仓库

在本书的整个过程中,我们多次提到了libscaplibsinsp和驱动程序。falcosecurity/libs仓库托管这些组件的源代码。它的组织如下:

/cmake/modules

此文件夹包含用于拉取外部依赖项的 cmake 模块和libscaplibsinsp的模块定义,这些消费者应用程序(如 Falco)可以使用。

/driver

此文件夹包括内核模块和 eBPF 探针的源代码(主要用 C 编写)。

/proposals

与 Falco 仓库中的类似,此文件夹包含设计提案文档。

/userspace

组 这里的几个子目录中,你可以找到libsinsplibscap的源代码(C 和 C++)以及其他共享代码。

本仓库包含用于内核仪器和数据丰富的所有低级逻辑。过滤语法、插件框架实现和许多其他功能都托管在这里。libs代码库庞大,但不要让它吓倒你:理解它所需的只是良好的 C/C++知识。

从源构建 Falco

从其源代码编译 Falco 类似于编译其他使用 cmake 的 C++项目。构建系统需要一些依赖项:cmake、make、gcc、wget,当然,还有 git(获取 Falco 仓库的本地副本也需要 Git)。你可以在文档中找到如何安装这些依赖项的说明。

一旦确保系统上安装了所需的依赖项,可以使用以下命令获取本地副本:

[code]$ git clone git@github.com:falcosecurity/falco.git [/code]

Git 会将仓库克隆到一个名为falco的新创建文件夹中。进入该目录:

[code]$ cd falco [/code]

准备一个目录来包含构建文件,然后进入其中:

[code]$ mkdir -p build $ cd build [/code]

最后,在构建目录中运行:

[code]$ cmake -DUSE_BUNDLED_DEPS=On .. $ make falco [/code]

第一次运行此命令可能需要大量时间,因为 cmake 会下载并构建所有依赖项。这是因为我们使用了-DUSE_BUNDLED_DEPS=On进行配置;或者,你可以设置-DUSE_BUNDLED_DEPS=Off来使用系统依赖项,但如果这样做,你需要在构建 Falco 之前手动安装所有必需的依赖项到你的系统上。你可以在文档中找到更新的依赖项列表和其他有用的 cmake 选项。

当make命令完成后,如果没有错误,你应该会在*./userspace/falco/falco*(相对于构建目录的路径)下找到新创建的 Falco 可执行文件。

现在,如果你也想从源代码构建驱动程序,并且你的系统已经安装了内核头文件,请运行:

[code]$ make driver [/code]

此命令默认仅构建内核模块。如果你想构建 eBPF 探针,请使用:

[code]$ cmake -DBUILD_BPF=True .. $ make bpf [/code]

在两种情况下,你会在*./driver*(相对于构建目录的路径)下找到新构建的驱动程序。

使用 gRPC API 扩展 Falco

虽然你可能会考虑直接向代码库引入新功能,但还有更方便的方法。例如,如果你想扩展 Falco 的输出机制,你可以创建一个在 Falco 之上运行并实现你的业务逻辑的程序。特别是,gRPC API 允许你的程序轻松消费 Falco 通知并接收元数据。

本节将使用一个示例程序向你展示如何开始使用 Falco gRPC API 进行开发。为了跟随示例,请确保你的系统上有一个运行的 Falco 实例,并启用了 gRCP 服务器和 gRPC 输出通道(参见第八章)。你将通过 Unix 套接字使用 gRPC,因此请确保已安装并配置了 Falco。

我们在以下示例中使用client-go库,它使得使用 gRPC API 变得简单直接:

[code]package main import ( "context" "fmt" "time" "github.com/falcosecurity/client-go/pkg/api/outputs" <https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/1.png> "github.com/falcosecurity/client-go/pkg/client" <https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/1.png> ) func main() { // Set up a connection to Falco via a Unix socket c, err := client.NewForConfig(context.Background(), &client.Config{ UnixSocketPath: "unix:///var/run/falco.sock", <https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/2.png> }) if err != nil { panic(err) } defer c.Close() // Subscribe to a stream of Falco notifications err = c.OutputsWatch(context.Background(), <https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/3.png> func(res *outputs.Response) error { // Put your business logic here fmt.Println(res.Output, res.OutputFields) <https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/4.png> return nil }, time.Second) if err != nil { panic(err) } } [/code]

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/#code_id_14_1

我们首先导入client-go库。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/#code_id_14_2

main函数建立一个连接(由变量c表示)到 Falco 的 gRPC 服务器,通过 Unix 套接字使用默认路径。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/#code_id_14_3

连接c允许调用OutputsWatch函数,订阅通知流并使用回调函数处理任何传入的通知。

https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/prac-cldntv-sec-falco/img/#code_id_14_4

这个示例使用一个匿名函数,它将通知打印到标准输出。在实际应用中,你应该实现自己的业务逻辑来消费 Falco 通知。

使用 gRPC API 来实现与 Falco 交互的程序非常方便直接。如果你需要使 Falco 与其他数据源一起工作,插件系统可能是你需要的。

使用插件扩展 Falco

插件是扩展 Falco 的主要方式,我们在整本书中多次提到过它们。简而言之,插件是符合特定 API 的 共享库。在 Falco 插件框架中,插件的主要责任是通过连接 Falco 到外部源并生成事件来添加新的数据源,并通过导出字段列表并解码事件数据以在 Falco 需要时生成字段值,从事件中提取数据。

插件包含生成和解释数据的逻辑。这很强大,因为这意味着 Falco 只关心从插件中收集字段值并将它们组合成规则条件。换句话说,Falco 只知道哪些字段可以使用以及如何获取它们的值;其他所有操作都委托给插件。由于这种系统,你可以将 Falco 连接到任何领域。

设计插件时有几个重要方面需要考虑。首先,具有事件源功能的插件隐式定义了事件负载格式(插件返回给框架的序列化原始事件数据)。具有与数据源兼容的字段提取功能的同一插件或其他插件稍后将能够访问负载,并在提取字段时使用。其次,具有字段提取功能的插件显式定义了绑定到数据源的字段。最后,规则依赖于数据源规范,以消耗其期望格式的事件。

由于描述插件开发的每个技术细节都需要一本专门的书,因此在本节中,我们只提供一个教育性示例,展示如何实现一个既可以生成事件又可以提取字段的插件。如需更全面的覆盖范围,请参阅文档。

我们的示例将实现一个插件,该插件从 bash 历史文件中读取(默认位于 ~/.bash_history)。每当用户在 shell 中输入命令时,bash 都会将该命令行存储下来。当 shell 会话结束时,bash 会将输入的命令行追加到历史文件中。它基本上就是一个日志文件。虽然它没有令人信服的用例,但它是学习如何创建从日志文件生成事件的插件的简单方法。因此,让我们开始用一些 Go 代码来玩乐。

准备一个 Go 中的插件

首先,创建一个文件(我们称之为 myplugin.go),并导入一堆 Go 包以简化开发。你还将导入tail,一个模拟tail命令的库(我们的示例使用它从日志文件中读取),以及来自 Falcosecurity 的 Go 插件 SDK中的一组包,让你可以实现具有提取器功能的源插件。你必须使用 main 包,否则 Go 将不允许你将其编译为共享对象:

[code]package main import ( "encoding/json" "fmt" "io" "os" "time" "github.com/hpcloud/tail" "github.com/falcosecurity/plugin-sdk-go/pkg/sdk" "github.com/falcosecurity/plugin-sdk-go/pkg/sdk/plugins" "github.com/falcosecurity/plugin-sdk-go/pkg/sdk/plugins/extractor" "github.com/falcosecurity/plugin-sdk-go/pkg/sdk/plugins/source" ) [/code]

SDK 定义了一组接口,帮助您按照简化且明确定义的模式实现插件。正如您马上将看到的,您需要通过向表示您的插件的一对数据结构添加方法(也称为 带接收器的函数 在 Go 中)来满足这些接口。在幕后,SDK 导出这些方法作为插件框架所需的调用约定函数(或简单的 C 符号)。(如果您需要回顾,请参阅 “Falco 插件”。)

插件状态和初始化

SDK 需要一个表示插件及其状态的数据结构。它可以实现各种可组合的接口,但所有类型的插件至少必须实现 Info 接口以公开有关插件的一般信息,并实现 Init 接口以使用给定的配置字符串初始化插件。

例如,此示例称此数据结构为 bashPlugin。您还将定义另一个数据结构(称为 bashPluginCfg),表示插件的配置,以在其中存储选项。这不是强制性的,但通常很方便:

[code]// bashPluginCfg represents the plugin configuration. type bashPluginCfg struct { Path string } // bashPlugin holds the state of the plugin. type bashPlugin struct { plugins.BasePlugin config bashPluginCfg } [/code]

现在,您将实现第一个公开有关插件一般信息的必需方法:

[code]func (b *bashPlugin) Info() *plugins.Info { return &plugins.Info{ ID: 999, Name: "bash", Description: "A Plugin that reads from ~/.bash_history", Version: "0.1.0", EventSource: "bash", } } [/code]
提示

所有源插件都需要 ID 字段,并且在它们之间必须是唯一的,以确保互操作性。特殊值 999 仅保留用于开发目的;如果您打算分发您的插件,您应该在 插件注册表 中注册它以获取唯一的 ID。

另一个重要的互操作性字段是 EventSource,您可以在其中声明数据源的名称。提取器插件可以使用该值来确定它们是否与数据源兼容。

另一个必需的方法是 Init。Falco 仅在加载插件时调用此方法,并传递配置字符串(在 Falco 配置中为插件定义的字符串)。通常,配置字符串是 JSON 格式的。我们的示例首先为我们之前声明的插件配置数据结构 b.config 的成员设置默认值。然后,如果给定的 config 字符串不为空,函数将 JSON 值解码到 b.config 中:

[code]func (b *bashPlugin) Init(config string) error { // default value homeDir, _ := os.UserHomeDir() b.config.Path = homeDir + "/.bash_history" // skip empty config if config == "" { return nil } // else parse the provided config return json.Unmarshal([]byte(config), &b.config) } [/code]

添加事件源功能

特别是对于具有事件源功能的插件,SDK 需要另一个表示 捕获会话(事件流)的数据结构。它还需要以下方法:

  • Open 用于启动和初始化捕获会话

  • NextBatch 用于生成事件

Falco 在初始化后立即调用Open。这表示捕获会话的开始。该方法的主要责任是实例化保存会话状态的数据结构(在我们的示例中为bashInstance)。具体来说,我们在这里创建一个*tail.Tail实例(模仿tail -f -n 0的行为)并将其存储在t中。然后我们创建一个bashInstance实例(可以将t分配给它)并返回它:

[code]// bashInstance holds the state of the current session. type bashInstance struct { source.BaseInstance t *tail.Tail ticker *time.Ticker } func (b *bashPlugin) Open(params string) (source.Instance, error) { t, err := tail.TailFile(b.config.Path, tail.Config{ Follow: true, Location: &tail.SeekInfo{ Offset: 0, Whence: os.SEEK_END, }, }) if err != nil { return nil, err } return &bashInstance{ t: t, ticker: time.NewTicker(time.Millisecond * 30), }, nil } [/code]

插件系统存储Open返回的值,并将其作为源插件的最重要方法的参数传递:NextBatch。与其他方法不同,此方法属于会话数据结构(bashInstance),而不属于插件数据结构(bashPlugin)。在捕获会话期间,Falco 重复调用NextBatch,后者又生成一批新事件。批处理的最大大小取决于其底层可重用内存缓冲区的大小。然而,批处理中的事件数可以少于其最大容量;它可以仅包含一个事件,甚至是空的。该方法通常实现源插件的核心业务逻辑,但本例中仅实现了一些简单的逻辑:尝试从b.t.Lines通道接收行并将它们添加到批处理中。如果没有,则在一段时间后会超时:

[code]func (b *bashInstance) NextBatch( bp sdk.PluginState, evts sdk.EventWriters, ) (int, error) { i := 0 b.ticker.Reset(time.Millisecond * 30) for i < evts.Len() { select { case line := <-b.t.Lines: if line.Err != nil { return i, line.Err } // Add an event to the batch evt := evts.Get(i) if _, err := evt.Writer().Write([]byte(line.Text)); err != nil { return i, err } i++ case <-b.ticker.C: // Timeout occurred, return early return i, sdk.ErrTimeout } } // The batch is full return i, nil } [/code]

如您所见,SDK 提供了一个sdk.EventWriters接口。这自动管理批处理的可重用内存缓冲区,并允许实现者将原始事件负载作为字节序列写入。函数evts.Len返回批处理中允许的最大事件数。

事件负载格式的选择由插件作者决定,因为插件 API 允许数据的编码(在我们的示例中,为了简单起见,我们将整行文本作为普通文本存储在负载中)和数据的解码(稍后我们将看到)。这允许您创建可用于规则的字段。选择正确的格式至关重要,因为它不仅对性能有影响,还对与其他插件的兼容性有影响(其他作者可能希望实现与您的事件兼容的提取器插件)。

到目前为止,您已经看到了实现源插件所需的最小方法集。但是,如果我们不添加一种方法来导出字段以用于规则条件和输出,此时插件实际上并不会真正有用。

添加字段提取能力

具有字段提取能力的插件可以从事件数据中提取值并导出 Falco 可以使用的字段。一个插件可以只具有事件源功能(在前一节中描述),也可以只具有字段提取功能,或者两者兼有(就像我们的示例插件一样)。具有字段提取能力的插件将在其他插件提供的数据源上工作,而具有两种能力的插件通常只在自己的数据源上工作。然而,机制是相同的,无论数据源如何。SDK 允许您定义以下方法,这些方法在两种情况下都适用:

  • Fields 用于声明插件能够提取哪些字段

  • Extract 从事件数据中提取给定字段的值

让我们在示例插件中实现这些方法。第一个方法 Fields 返回一个 sdk.FieldEntry 切片。每个条目包含单个字段的规范。下面的代码告诉 Falco 插件可以提取名为 shell.command 的字段(本例仅添加了一个字段):

[code]func (b *bashPlugin) Fields() []sdk.FieldEntry { return []sdk.FieldEntry{ {Type: "string", Name: "shell.command", Display: "Shell command line", Desc: "The command line typed by user in the shell"}, } } [/code]

现在,为了使提取工作正常,我们需要实现 Extract 方法,该方法提供实际的业务逻辑来提取字段。该方法接收提取请求(包含所请求字段的标识符)和一个读取器(用于访问事件负载)作为参数。由于本例只有一个字段,实现起来非常简单,它将简单地返回事件负载的所有内容。在实际场景中,您通常会有更多字段和特定的提取逻辑:

[code]func (m *bashPlugin) Extract(req sdk.ExtractRequest, evt sdk.EventReader) error { bb, err := io.ReadAll(evt.Reader()) if err != nil { return err } switch req.FieldID() { case 0: // shell.command req.SetValue(string(bb)) return nil default: return fmt.Errorf("unsupported field: %s", req.Field()) } } [/code]

有了字段提取功能,我们的示例插件几乎准备好了。让我们看看如何完成并使用它。

完成插件

你已经快完成了。接下来,你将创建插件的一个实例,并在 SDK 中注册其能力。您可以在 Go 初始化阶段通过使用特殊的 init 函数 来完成这一过程。(不要与 Init 方法混淆!)由于我们的示例插件具有源和提取器功能,因此我们必须使用提供的函数通知 SDK 两者的能力:

[code]func init() { plugins.SetFactory(func() plugins.Plugin { p := &bashPlugin{} extractor.Register(p) source.Register(p) return p }) } func main() {} [/code]

注意空的 main 函数。正如您马上会看到的,Go 构建系统需要它来正确构建插件,但它永远不会调用 main,所以您可以始终将其保持为空。

使您的代码成为真正的 Go 项目的最后一步是初始化 Go 模块并下载依赖项:

[code]$ go mod init *example.com/my/plugin* $ go mod tidy [/code]

这些命令分别创建了 go.modgo.sum 文件。现在,您的插件代码已经准备就绪。是时候编译它,以便您可以在 Falco 中使用它了!

构建用 Go 编写的插件

插件是一个共享库(也称为 共享对象),具体来说是一个编译文件,它导出了插件框架所需的一组 C 符号。(我们在示例中使用的 SDK 通过使用高级接口隐藏了这些 C 符号,但它们仍然存在于底层。)

Go 编译器有一个特定的命令称为 cgo,用于创建与 C 代码接口的 Go 包。它允许您编译插件并获得一个共享库文件(一个 .so.dll 文件)。该命令非常简单。在存放源代码的同一文件夹中运行:

[code]$ go build -buildmode=c-shared -o libmyplugin.so [/code]

该命令创建了 libmyplugin.so,您可以在 Falco 中使用它。 (按照惯例,类 Unix 系统中的共享对象文件以 lib 开头,并以 .so 作为扩展名。)您在 第十章 中了解了插件配置,但以下部分将为您提供一些关于开发时如何使用插件的提示。

在开发过程中使用插件

默认情况下,Falco 会在*/usr/share/falco/plugins中查找已安装的插件。但是,你可以在配置中指定绝对路径,并将插件放在任何你想放置的位置。(在开发过程中这很方便,因为你不需要将插件安装在默认路径下。)我们建议在开发插件的同时构建插件(使用上一节中的命令)。然后,在同一文件夹中,复制falco.yaml*,根据需要添加你的插件配置,并将library_path选项设置为插件的绝对路径。例如:

[code]plugins: - name: bash library_path: /path/to/your/plugin/libmyplugin.so init_config: "" load_plugins: [bash] [/code]

现在,在使用插件之前,你需要一个与插件提供的数据源匹配的规则文件。(Falco 即使没有规则文件也会加载插件,但你将不会收到任何通知。)你可以在同一文件夹中创建一个规则文件,例如myplugin_rules.yaml,并在其中添加如下规则:

[code]- rule: Cat in the shell desc: Match command lines starting with "cat". condition: shell.command startswith "cat " output: Cat in shell detected (command=%shell.command) priority: DEBUG source: bash [/code]

一旦准备好你定制的falco.yamlmyplugin_rules.yaml,最后一步就是运行 Falco 并传递这些文件给相应的选项:

[code]$ falco -c falco.yaml -r myplugin_rules.yaml [/code]

完成!在开发过程中以这种方式运行 Falco 插件非常方便,因为它不需要你安装任何文件或干扰本地的 Falco 安装。

小贴士

如果你按照我们示例中的方法构建了插件,并希望触发规则,可以运行:

[code]$ bash $ cat --version $ exit [/code]

结论

有几种方法可以扩展 Falco。编写插件通常是最佳选择,特别是如果你希望 Falco 能够处理新的数据源以启用新的用例。如果需要与输出进行接口化,gRPC API 可能会对你有所帮助。在极少数情况下,你可能需要直接修改 Falco 核心及其组件。

无论如何,你都需要阅读文档。有时你可能需要学习和理解高级主题。由于 Falco 是开源的且是一个协作项目,你总是有机会与其充满活力的社区联系。与他人分享想法和知识将帮助你更快找到答案。

你可能还会发现其他人有与你完全相同的需求,并愿意帮助你改进或扩展 Falco。这将是为 Falco 项目做贡献的绝佳机会。每个人都可以为 Falco 做贡献。这不仅是一种有益的经验,而且为项目和所有用户(包括你)提供了极大的帮助。想知道如何做?请阅读下一章!


免责声明:本内容来源于网络,如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

路过

雷人

握手

鲜花

鸡蛋

发表评论

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行