在 Kubernetes 世界中,网络策略对于控制集群内的流量至关重要。但它们到底是什么?为什么、何时以及如何实施它们?
无论您是现有的 Kubernetes 用户并想要更好地了解网络,还是试图将您的知识映射到 Kubernetes 的传统网络工程师,您来对地方了。
本指南适用于任何有兴趣详细了解基于策略的 Kubernetes 网络流量控制的人。您将了解不同类型的策略及其重要性、每种策略的优缺点、如何定义它们以及何时将它们组合在一起。
1
什么是网络策略?
网络策略有助于定义哪些流量可以入站(入口)、出站(出口)以及在 Kubernetes 集群中的 pod 之间移动。
与 Kubernetes 中的其他资源一样,网络策略是声明性配置,集群内的组件将使用这些配置来强制执行在什么情况下允许或拒绝哪些流量。
但是,一旦您决定要执行哪些策略,并且需要在 Kubernetes 资源清单中定义它们,您就会遇到几个选项。有 Kubernetes 原生的 NetworkPolicy 资源,但也有生态系统中其他工具定义的其他自定义资源,例如 Cilium、Calico、Istio 以及 Linkerd(本文的重点)。我们不会比较和对比单个工具和选项,而是退一步解释这些不同策略定义所属的两个主要类别。
广义上,网络策略可分为第 4 层 (L4) 和第 7 层 (L7) 策略。这是什么意思?我知道您在想什么,7 层卷饼!很接近,但不是。它们指的是开放系统互连 (OSI) 模型的七层。
(有趣的是:7 层卷饼的灵感来源于 7 层蘸酱,这种蘸酱在 20 世纪 80 年代广受欢迎,但它是在 1980 年 OSI 模型发布后不到一年就首次亮相的。巧合吗?我将为读者留下互联网历史的证据,包括 原始的 OCI 是虚假的咆哮、 IEFT 网络 RFC 提案,以及 隐藏在 xkcd 中的这个小小认可)。
OSI 网络模型被描绘成一个 7 层卷饼(来源)OSI 模型将网络通信分为 7 层。虽然 OSI 模型可能有些过时(人们曾多次指出互联网实际上并非如此运作),但第 4 层和第 7 层对于我们而言仍然是有用的参考。
术语“L4”是指 OSI 模型的第四层 - 传输层,包含 TCP 等协议。“L7”对应于第七 OSI 层 - 应用程序级通信,其中包括 HTTP、gRPC 和其他特定于应用程序的协议。在 Kubernetes 网络策略上下文中,L4 策略在集群级别运行,而 L7 策略在应用程序级别运行。与 OSI 层本身非常相似,L4 和 L7 网络策略旨在协同工作。
本指南将探讨这两种类型,包括它们的定义、优点和局限性,以及它们在实现零信任安全模型中的作用。
2
L4 网络策略
第 7 层网络策略在应用层运行,理解 HTTP 和 gRPC 等协议。与 L4 策略不同,L7 策略允许更精细的控制,例如允许“服务 A 调用服务 B 的 /foo/bar 端点”或“服务 B 仅与 mTLS 服务通信”。
2.1
L4 网络策略如何发挥作用
L4 策略由 CNI 插件实现,用于配置内核的数据包过滤器(例如使用 Netfilter/iptables 或 eBPF),以与不同服务中的 pod 对应的 IP 地址和端口号为目标。例如,如果您要实现“服务 A 不能在端口 8080 上调用服务 B”的策略,系统会随着服务及其对应的 pod 的变化而动态管理这些规则。这是通过使用 podSelector 根据标签定位命名空间或 pod 来实现的。
这是一个简单的 L4 网络策略示例,定义仅允许来自 service-a 的 TCP 流量进入 service-b 中 pod 的端口 8080。一旦创建了策略类型中包含“Ingress”的 NetworkPolicy,并选择了 service-b 中的 pod,这些 pod 就被视为“隔离 Ingress”。这意味着只允许与所有入口列表组合匹配的入站流量。对这些允许连接的回复流量是隐式允许的。Kubernetes 文档中的网络策略 概念页面概述了更多选项,包括显式出口规则,但我们只需要这个简单的例子来解释 Kubernetes 中 L4 策略的整体功能:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: service-a-to-b
namespace: default
spec:
podSelector:
matchLabels:
app: service-b
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: service-a
ports:
- protocol: TCP
port: 8080
2.2
L4 网络策略的优缺点
优点:
内置于大多数 CNI 插件中,使其随时可用。
缺点:
仅限于通过 pod 标签和端口来表达策略,缺乏针对特定路由或服务名称的粒度。
它们可以表达的规则类型受到限制——例如,不能要求所有流量都通过公共网关。
无法记录安全事件。
容易出现“脑裂”情况,即 pod 和 IP 地址之间的映射可能出现分歧,从而可能允许未经授权的访问。
IP 地址和端口可能被伪造,从而导致潜在的安全漏洞。现代安全模式已经超越了这些简单的结构。
2.3
何时应该使用 L4 网络策略?
L4 网络策略的优点是易于理解且在 Kubernetes 中广泛可用。但是,考虑到(轻微但并非无关紧要的)安全漏洞、缺乏表现力以及无法记录安全事件,L4 策略属于“必要但不充分”的控制类别,随着安全状况的成熟,最终应与其他控制措施(例如 L7 网络策略)相结合。
3
L7 网络策略
第 7 层网络策略在应用层运行,理解 HTTP 和 gRPC 等协议。与 L4 策略不同,L7 策略可以直接使用服务名称,并允许诸如“服务 A 可以与服务 B 通信”或“服务 B 只能与 mTLS 服务通信”之类的策略。这些策略还允许更精细的控制,例如允许“服务 A 调用服务 B 的 /foo/bar 端点”。
3.1
使用 Linkerd 实现 L7 策略
在 Kubernetes 中,L7 策略通常通过 Linkerd 等服务网格实现,并以 自定义资源 (例如 Server.policy.linkerd.io )的形式表示。Linkerd 代理 HTTP 和 gRPC 调用,理解这些协议,并相应地执行策略。有关更多详细信息,请参阅 Linkerd 的服务器策略文档更多内容。
3.2
L7 策略如何发挥作用
Linkerd 在服务器端强制执行策略,这意味着服务 A 的代理会保护对它的访问,无论调用者是谁。这些策略基于在相互 TLS (mTLS) 期间建立的服务身份,确保忽略 IP 地址以支持连接的加密属性。此方法旨在在分布式系统中无缝运行,类似于系统之间协调不可靠的开放互联网。
值得注意的是,Linkerd 有两种类型的策略:默认和动态。
安装或升级 Linkerd 时会设置默认策略。这些策略允许您根据客户端是在您的服务网格内还是在同一个集群内来允许或禁止流量(例如,如果您有一个跨多个集群的网格,则最后这个检查很有用)。还有一个拒绝所有流量的策略。除非指定了其中一个策略,否则所有流量都是允许的(因此当您安装 Linkerd 时世界不会崩溃!)。您也可以根据需要按命名空间和工作负载覆盖此策略。您可以 在此处阅读有关默认策略的更多信息,但对于本文来说,知道这些策略存在并与动态策略协同工作就足够了。
动态策略与默认策略不同,它允许您通过更新控制这些策略的自定义资源来动态更改策略行为。动态策略也称为“细粒度”策略,因为它们可以控制特定服务、端口、路由等的流量。与单个 L4 NetworkPolicy.networking.k8s.io 资源相比,Linkerd 动态策略由多个 CRD 表示,以便允许更细粒度的规则,并通过重复使用多个相关策略来减少重复。
一组 CRD 允许您指定要定位的流量的目的地( 服务器或其流量的子集,称为 HTTPRoute )。另一组 CRD 表示身份验证规则(具有 MeshTLSAuthentication 的网格身份 ,或客户端必须是其一部分的 IP 子网集合,称为 NetworkAuthentication),这些规则必须作为策略的一部分得到满足。最后有一个 CRD 代表 AuthorizationPolicy 本身 ,它将自定义资源从第一组 CRD(要保护的流量目标)映射到第二类 CRD 之一(允许访问目标之前所需的身份验证)。
下面是 Linkerd L7 的自定义资源示例,相当于上面的单个 L4 示例资源——一个 Server,一个 MeshTLSAuthentication,以及 引用它们的 AuthorizationPolicy :
流量目的地:
apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
name: service-b
namespace: default
spec:
podSelector:
matchLabels:
app: service-a
port: 8080
proxyProtocol: "HTTP/2"
authN 规则:
apiVersion: policy.linkerd.io/v1alpha1
kind: MeshTLSAuthentication
metadata:
name: service-a
namespace: default
spec:
identityRefs:
- kind: ServiceAccount
name: service-a
authZ 策略:
apiVersion: policy.linkerd.io/v1alpha1
kind: AuthorizationPolicy
metadata:
name: service-a-to-b
namespace: default
spec:
targetRef:
group: policy.linkerd.io
kind: Server
name: service-b
requiredAuthenticationRefs:
- name: service-a
kind: MeshTLSAuthentication
group: policy.linkerd.io
您可以在 Linkerd 的授权策略文档页面中看到更多选项 ,但这可以让您了解 Linkerd 的 L7 策略与早期 L4 NetworkPolicy 示例等效的粒度、灵活性和可重用性。
3.3
L7 网络策略的优缺点
优点:
允许细粒度的策略,例如“仅允许使用 mTLS 加密连接”和“仅允许 Foo 调用 /bar”。
不易受到裂脑情况的影响。
与相互 TLS 结合,还可提供身份验证和加密。
可以提供安全事件的日志记录,例如(试图)违反政策的行为。
缺点:
需要运行服务网格,因为它不是 Kubernetes 原生内置的。
策略不适用于发送到非网状工作负载的流量(即使源工作负载是网状的)。
策略不适用于 UDP 或其他非 TCP 流量。
4
结合 L7 和 L4 策略
某些用例最好通过 L4 策略解决,而其他用例最好通过 L7 策略解决。幸运的是,您不需要选择其中之一!您可以同时在集群中实施这两种类型的策略。上述优缺点将帮助您确定何时使用每种类型的策略。
如上所述 - 当您需要强制执行有关与任何非网格资源通信的策略时,您可以选择 L4 策略。同样,如果您需要强制执行集群范围的策略而不管各个工作负载的网格状态如何,您都可以使用 L4。
您安装的服务网格的当前版本可能还不支持某些要求。Linkerd 在 2.16 版中引入了对 IPv6 的支持,而更早版本不支持特定于 IPv6 的策略。某些要求可能尚不受您服务网格的任何版本的支持。例如,Linkerd 策略尚不支持 UDP 或非 TCP 流量,因为 尚未建立明确的用例。您可能还想关注该问题以获取更新。与此同时,L4 策略在这里是一个不错的选择。
另一方面,L7 策略允许更复杂的场景,需要更精细的控制,从而开辟更多用例。您可以为特定客户端、对单个工作负载端点的访问、检查是否存在加密的 mTLS 连接、特定网络身份验证、客户端是否网格化或在同一集群内网格化以及许多其他选项创建允许或拒绝规则。
最后,有一个用例是将具有重叠功能的 L7 和 L4 策略结合起来,以创建更强大的安全框架。这种双管齐下的方法可以利用两个层的优势来增强安全性。使用上面的示例,您可以探索结合 L4 和 L7 策略,通过定义 Linkerd 服务器 授权策略和 Kubernetes 网络策略 来将与同一服务 ( service-b ) 的所有网络通信限制为您指定的客户端服务 ( service-a )。像这样结合多个层的网络策略是纵深防御安全策略的一个示例 ,该策略建议在一个安全控制失败的情况下提供冗余。
5
结论
网络策略是保护 Kubernetes 集群的基本方面。L4 策略基于 IP 地址和端口提供对流量的基本控制,而 L7 策略则基于强加密身份提供对应用层流量的精细控制。通过结合这两种类型的策略并利用 Linkerd 等服务网格,您可以实现一个强大的零信任安全模型,以应对现代安全挑战。更多内容