6. eBPF 工具集
既然你已经了解了 eBPF 是什么,以及 eBPF 程序是如何工作的,那么让我们转向探索一些基于该技术构建的工具,你可能会在生产部署中使用这些工具。我们将考虑一些基于 eBPF 的开源项目示例,这些项目在三个重要领域提供功能:网络、可观察性和安全性。
网络
eBPF 程序可以附加到网络接口和内核网络栈中的各个附加点。在每个附加点,eBPF 程序都可以丢弃数据包、将它们发送到不同的目的地,甚至修改内容。这就实现了一些非常强大的功能。让我们看看现在通常使用 eBPF 实现的一些网络功能。
负载均衡
如果你对网络 eBPF 的可扩展性有任何疑问,要知道它正在 Facebook 大规模使用。他们是 BPF 的早期采用者并在 2018 年引入了 Katran ,其是一个开源的第 4 层负载均衡器。
另一个高度扩展的负载均衡器示例来自 Cloudflare 的 Unimog 边缘负载均衡器。通过在内核中运行,eBPF 程序可以操作网络数据包并将它们转发到适当的目的地,而无需每个数据包都必须通过网络栈并到达用户空间。
Cilium 项目以 eBPF Kubernetes 网络插件而闻名(稍后我将讨论),但它作为独立的负载均衡器用于大型电信和企业内部署中。同样,在早期阶段处理数据包而不必转换到用户空间的能力使其具有高性能。
Kubernetes 网络
CNCF 项目 Cilium 是最初的基于 eBPF 的 CNI 实现。它最初是由一群致力于 eBPF 的内核维护者发起的,他们很早认识到其在云原生网络中的应用潜力。Cilium 现在被用作 Google Kubernetes Engine、Amazon EKS Anywhere 和阿里云的默认数据平面。
在云原生世界中,Pod 一直在停止和启动,每个 Pod 都被分配一个 IP 地址。在启用 eBPF 的网络之前,每个节点都必须不断更新一组 iptables 规则,以便在 pod 之间进行路由;而管理这些 iptables 规则在规模上会变得非常不方便。如图 6-1 所示,Cilium 极大地简化了路由,因此它本质上是 eBPF 中的一个简单的表查找,从而使得[显著的性能改进](https://cilium.io/blog/2021/05/11/cni-benchmark)。
除了传统的 iptables 版本之外,另一个添加了 eBPF 实现的 Kubernetes CNI 是 Project Calico。
图 6-1. 用 eBPF 绕过主机网络栈
服务网格 Service Mesh
eBPF 作为更高效的服务网格数据平面的基础也非常有意义。许多服务网格功能在第 7 层即应用程序层运行,并使用 Envoy 等代理组件代表应用程序执行操作。在 Kubernetes 中,这些代理通常部署在 sidecar 模型中,每个 pod 有一个代理容器,以便代理可以访问 pod 的网络命名空间。正如你在第 5 章中所看到的,eBPF 提供了一种比 sidecar 模型更有效的方法。由于内核可以访问所有 pod 命名空间,我们可以使用 eBPF 在 pod 中的应用程序和主机上的单个代理之间建立连接,如图 6-2 所示。
图 6-2. eBPF实现了一个高效的服务网格模型,每个节点一个代理,而不是每个 pod 一个。
我还有另一篇关于使用 eBPF 实现更高效的服务网格数据平面的文章,Solo.io 也是如此。在撰写本文时,Cilium Service Mesh 处于测试阶段,与传统的 Sidecar 代理方法相比,显示出早期的性能提升 .
可观测
正如你在本报告前面所见,eBPF 程序可以了解机器上发生的一切。通过收集有关事件的数据并将它们传递到用户空间,eBPF 启用了一系列强大的可观察性工具,可以向你展示应用程序是执行和表现如何,而无需对这些应用程序进行任何更改。eBPF 还支持整个系统的可观察性,而不仅仅是单个应用程序,因此你可以了解主机的行为。
你在本报告的前面部分已经接触过了 BCC 项目,多年来,Brendan Gregg 在 Netflix 开展了开创性工作,并展示了如何使用这些 eBPF 工具在大规模和高性能常见下观察你感兴趣的几乎任何指标。
Kinvolk 的 Inspektor Gadget 将其中一些源自 BCC 的工具引入了 Kubernetes 的世界,这样你就可以轻松地在命令行上观察特定的工作负载。
新一代项目和工具正在这项工作的基础上提供基于 GUI 的可观察性。CNCF 项目 Pixie 允许你运行预先编写或自定义的脚本,并通过强大且具有视觉吸引力的 UI 查看指标和日志。因为其基于 eBPF,这意味着你可以自动检测所有应用程序并获取性能数据,而无需进行任何代码更改或配置。图 6-3 仅显示了 Pixie 中可用的许多可视化的一个示例。
另一个名为 Parca 的可观察性项目专注于持续分析,使用 eBPF 来有效地采样 CPU 使用率等指标,你可以使用这些指标来检测性能瓶颈。
图 6-3 Pixie 运行在一个 Kubernetes 集群上运行的所有运行的火焰图
Cilium 的 Hubble 组件是一个具有命令行界面和 UI(如图 6-4 所示)的可观察性工具,专注于 Kubernetes 集群中的网络流。
图 6-4 Cilium 的 Hubble 用户界面显示了 Kubernetes 集群中的网络流量。
在云原生环境中,IP 地址不断被动态分配和重新分配,基于 IP 地址的传统网络可观察性工具的用途非常有限。作为 CNI,Cilium 可以访问工作负载身份信息,这意味着 Hubble 可以显示由 Kubernetes pod、服务和命名空间标识的服务地图和流数据。这对于诊断网络问题非常宝贵。
如果可以观察活动,(这是安全工具的基础),你就可以将正在发生的事情与策略或规则进行比较,以了解该活动是预期的还是可疑的。让我们转向一些使用 eBPF 提供云原生安全功能的工具。
安全
有强大的云原生工具可用,通过使用 eBPF 来检测甚至阻止恶意活动来增强安全性。我将这些分为两类:保护网络活动和保护应用程序在运行时的预期行为。
网络安全
因为 eBPF 允许检查和操作网络数据包,所以它在网络安全方面有很多用途。基本原则是,如果一个网络数据包被认为是恶意的或有问题的,如不符合某些安全验证标准,它可以简单地被丢弃。eBPF 是一种高效的实现方式,因为它可以挂接到内核中网络栈的相关部分,甚至可以挂接到网络接口卡上。1 这意味着可以丢弃不符合策略或恶意的数据包在产生由网络堆栈处理并传递给用户空间的处理成本之前。
eBPF 在大规模生产中的早期用途之一是用于 [Cloudflare] (https://blog.cloudflare.com/how-to-drop-10-million-packets/) 的 DDoS(分布式拒绝服务)保护。 DDoS 攻击者用许多网络消息淹没目标机器,希望目标无法足够快地处理它们,并忙于处理这些消息,以至于它无法做有用的工作。 Cloudflare 工程师使用 eBPF 程序在数据包到达后立即对其进行检查,并快速确定数据包是否是此类攻击的一部分,如果是则将其丢弃。数据包不必通过内核的网络栈,因此处理所需的资源要少得多,并且目标可以应对更高速率的恶意流量。
eBPF 程序还被用作针对“死亡数据包”内核漏洞的动态缓解措施。2攻击者制作网络数据包的方式是利用内核中的一个错误,该错误会阻止它正确处理该数据包。无需等待内核补丁推出,可以通过加载 eBPF 程序来缓解攻击,该程序会查找这些特制数据包并丢弃它们。这样做的真正美妙之处在于,可以动态加载 eBPF 程序,而无需更改机器上的任何内容。
在 Kubernetes 中,网络策略 是一等公民,但它留给网络插件来执行。一些 CNI,包括 Cilium 和 Calico,为更强大的规则提供扩展的网络策略功能,例如允许或禁止流量到由完全限定域名而不是 IP 地址指定的目的地。 app.networkpolicy.io 有一个很好的工具可以探索网络策略及其影响,如图 6-5 所示。
标准 Kubernetes 网络策略规则适用于进出应用程序 pod 的流量,但由于 eBPF 对所有网络流量具有可见性,它也可用于主机防火墙功能,限制进出主机(虚拟)机器的流量。3
eBPF 也可以用来提供透明加密,无论是通过 WireGuard 还是 IPsec。4这里,透明意味着应用程序不需要任何修改——事实上,应用程序可以完全不知道它的网络流量是加密的.
图 6-5. 网络策略编辑器显示了策略的效果的可视化
运行时安全
eBPF 还被用于构建检测应用程序何时以非预期或恶意方式运行的工具,其中一些工具还可用于防止不良行为。一些可疑行为的示例可能包括意外访问文件、运行可执行程序或试图获得额外权限。
事实上,你可能已经以 seccomp 的形式使用了基于 BPF 的安全实施,这是一种用于限制任何应用程序可以调用的系统调用集的 Linux 特性。
CNCF 项目 Falco 扩展了限制应用程序可以进行的系统调用的想法。Falco 的规则定义是在 YAML 中创建的,这比 seccomp 配置文件更易于人类阅读和解释。默认的 Falco 驱动程序是一个内核模块,但也有一个附加到“原始系统调用”事件的 eBPF 探针驱动程序。它不会阻止这些系统调用完成,但它可以生成日志或其他通知,以提醒运维人员注意潜在的恶意事件。
正如我们在第 3 章中看到的,可以将 eBPF 程序附加到 LSM 接口以防止恶意行为或缓解已知漏洞。例如,Denis Efremov 编写了一个 eBPF 程序 来防止 exec() 系统调用在没有传递任何参数的情况下运行,以减轻 PwnKit* 5 高危漏洞。eBPF 也可用于缓解投机执行 “Spectre” 攻击。6
Tracee 是另一个使用 eBPF 实现运行时安全的开源项目。除了基于系统调用的检查外,它还使用了 LSM 接口。这有助于避免在仅检查系统调用时容易受到 TOCTTOU 条件竞争的影响。 Tracee 支持 Open Policy Agent 的 Rego 语言中定义的规则,也允许使用 Go 中定义的插件规则。
Cilium 的 Tetragon 组件提供了另一种强大的方法,使用 eBPF 来监控容器安全可观察性的四个黄金信号:进程执行、网络套接字、文件访问和 7 层网络身份。这使得运维可以准确地查看导致任何恶意或可疑事件的原因,直至特定 pod 中的可执行名称和用户身份。例如,如果受到挖矿攻击,你可以准确地看到哪个可执行文件打开了与矿池的网络连接,从哪个 pod 以及何时打开。这些取证对于了解危害是如何发生的以及使构建安全策略以防止将来发生类似攻击变得非常宝贵。
如果你想更深入地研究 eBPF 的安全可观察性主题,请查看 Natália Ivánkó 和 Jed Salazar 的报告7。密切关注云原生 eBPF 空间,因为不久我们就会看到利用 BPF LSM 和其他 eBPF 定制来提供安全实施和可观察性的工具。
我们介绍了几个在网络、可观察性和安全性方面的云原生工具。与此前工具相比,他们使用 eBPF 为他们带来了两个关键优势:
从内核中的优势来看,eBPF 程序对所有进程都有可见性。
通过避免内核和用户空间执行之间的转换,eBPF 程序提供了一种非常高效的方式来收集事件数据或处理网络数据包。
这并不意味着我们应该对所有事情都使用 eBPF!在 eBPF 中编写特定于业务的应用程序不太可能有意义,就像我们通常将应用程序编写为内核模块一样。这条规则可能有一些例外,可能是针对高频交易等极高的性能要求。正如我们在本章中所看到的,eBPF 主要是作为工具来检测其他应用程序的。
1. 一些网络接口卡和驱动程序支持 XDP 或 eXpress 数据路径挂钩,从而允许将 eBPF 程序完全卸载到内核之外。 ↩
2. Daniel Borkmann 在他的演讲,“BPF as a Fundamentally Better Dataplane”(eBPF 峰会(虚拟),2020)中讨论了这个问题。 ↩
3. 请参阅 Cilium 的主机防火墙文档。 ↩
4. Tailscale 有这两种加密协议的比较。 ↩
5. 参见 Bharat Jogi 的博客,“PwnKit:本地特权升级漏洞”(Qualys,2022 年 1 月 25 日)。 ↩
6. 参见 Daniel Borkmann 的演讲,“BPF and Spectre: Mitigating Transient Execution Attacks”(eBPF 峰会(虚拟),2021 年 8 月 18 日至 19 日)。 ↩