网络策略

如果您想要在 IP 地址或端口级别控制流量(OSI 第 3 层或第 4 层),NetworkPolicy 允许您指定集群内流量以及 Pod 与外部世界之间流量的规则。您的集群必须使用支持 NetworkPolicy 强制执行的网络插件。

如果您想要在 TCP、UDP 和 SCTP 协议的 IP 地址或端口级别控制流量,那么您可以考虑对集群中的特定应用程序使用 Kubernetes NetworkPolicy。NetworkPolicy 是一种以应用程序为中心的结构,它允许您指定 Pod 如何被允许与网络上的各种网络“实体”进行通信(我们在这里使用“实体”一词来避免使用更常见的术语,如“端点”和“服务”,它们具有特定的 Kubernetes 含义)。NetworkPolicy 应用于连接到或来自 Pod 的连接,与其他连接无关。

Pod 可以与之通信的实体通过以下三个标识符的组合来识别

  1. 允许的其他 Pod(例外:Pod 不能阻止自身访问)
  2. 允许的命名空间
  3. IP 块(例外:无论 Pod 或节点的 IP 地址如何,始终允许 Pod 所在节点的流量出入)

在定义基于 Pod 或命名空间的 NetworkPolicy 时,您使用 选择器 来指定匹配选择器的 Pod 的流量允许哪些。

同时,在创建基于 IP 的 NetworkPolicy 时,我们根据 IP 块(CIDR 范围)定义策略。

先决条件

网络策略由 网络插件 实现。要使用网络策略,您必须使用支持 NetworkPolicy 的网络解决方案。在没有实现它的控制器的环境下创建 NetworkPolicy 资源将不会有任何效果。

两种 Pod 隔离

Pod 有两种隔离方式:出口隔离和入口隔离。它们关注可以建立哪些连接。“隔离”在这里不是绝对的,而是意味着“应用了一些限制”。另一种情况,“$方向未隔离”意味着在所述方向上没有限制。两种隔离(或不隔离)是独立声明的,并且都与从一个 Pod 到另一个 Pod 的连接相关。

默认情况下,Pod 对于出口未隔离;允许所有出站连接。如果任何 NetworkPolicy 都选择 Pod 并且在其 policyTypes 中有“Egress”,那么 Pod 对于出口就是隔离的;我们说这样的策略对于出口应用于 Pod。当 Pod 对于出口被隔离时,Pod 中唯一允许的连接是那些被应用于 Pod 的出口的某些 NetworkPolicy 的 egress 列表允许的连接。对这些允许连接的回复流量也将被隐式允许。这些 egress 列表的效果是累加的。

默认情况下,Pod 对于入口未隔离;允许所有入站连接。如果任何 NetworkPolicy 都选择 Pod 并且在其 policyTypes 中有“Ingress”,那么 Pod 对于入口就是隔离的;我们说这样的策略对于入口应用于 Pod。当 Pod 对于入口被隔离时,Pod 中唯一允许的连接是来自 Pod 节点的连接以及那些被应用于 Pod 的入口的某些 NetworkPolicy 的 ingress 列表允许的连接。对这些允许连接的回复流量也将被隐式允许。这些 ingress 列表的效果是累加的。

网络策略不会冲突;它们是累加的。如果任何策略或策略应用于给定 Pod 的给定方向,则从该 Pod 的该方向允许的连接是所有适用的策略允许的连接的并集。因此,评估顺序不会影响策略结果。

要允许从源 Pod 到目标 Pod 的连接,源 Pod 上的出口策略和目标 Pod 上的入口策略都需要允许连接。如果任一侧不允许连接,则连接将不会发生。

NetworkPolicy 资源

有关资源的完整定义,请参见 NetworkPolicy 参考。

一个示例 NetworkPolicy 可能如下所示

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

必填字段:与所有其他 Kubernetes 配置一样,NetworkPolicy 需要 apiVersionkindmetadata 字段。有关使用配置文件的一般信息,请参见 配置 Pod 以使用 ConfigMap对象管理

spec:NetworkPolicy spec 包含在给定命名空间中定义特定网络策略所需的所有信息。

podSelector:每个 NetworkPolicy 都包含一个 podSelector,它选择策略适用的 Pod 组。示例策略选择具有标签“role=db”的 Pod。空 podSelector 选择命名空间中的所有 Pod。

policyTypes:每个 NetworkPolicy 都包含一个 policyTypes 列表,其中可能包括 IngressEgress 或两者。policyTypes 字段指示给定策略是否应用于选定 Pod 的入站流量、选定 Pod 的出站流量或两者。如果 NetworkPolicy 上没有指定 policyTypes,则默认情况下 Ingress 将始终被设置,如果 NetworkPolicy 具有任何出站规则,则 Egress 将被设置。

ingress:每个 NetworkPolicy 都可能包含一个允许的 ingress 规则列表。每个规则都允许与 fromports 部分都匹配的流量。示例策略包含一个规则,它匹配来自三个来源之一的单个端口上的流量,第一个通过 ipBlock 指定,第二个通过 namespaceSelector 指定,第三个通过 podSelector 指定。

egress:每个 NetworkPolicy 都可能包含一个允许的 egress 规则列表。每个规则都允许与 toports 部分都匹配的流量。示例策略包含一个规则,它匹配在单个端口上到 10.0.0.0/24 中任何目标的流量。

因此,示例 NetworkPolicy

  1. default 命名空间中隔离 role=db Pod,以便进行入站和出站流量(如果它们还没有被隔离)

  2. (入站规则)允许连接到 default 命名空间中所有具有标签 role=db 的 Pod 上的 TCP 端口 6379,这些连接来自

    • default 命名空间中任何具有标签 role=frontend 的 Pod
    • 任何具有标签 project=myproject 的命名空间中的任何 Pod
    • 范围为 172.17.0.0172.17.0.255172.17.2.0172.17.255.255 的 IP 地址(即,所有 172.17.0.0/16 除了 172.17.1.0/24
  3. (出站规则)允许来自 default 命名空间中任何具有标签 role=db 的 Pod 到 CIDR 10.0.0.0/24 上的 TCP 端口 5978 的连接

有关更多示例,请参见 声明网络策略 演练。

tofrom 选择器的行为

ingress from 部分或 egress to 部分中可以指定四种选择器

podSelector:这将选择与 NetworkPolicy 相同命名空间中特定 Pod,这些 Pod 应该被允许作为入站来源或出站目标。

namespaceSelector:这将选择特定命名空间,其中所有 Pod 应该被允许作为入站来源或出站目标。

namespaceSelector podSelector:指定了 namespaceSelectorpodSelector 的单个 to/from 条目将选择特定命名空间中的特定 Pod。请注意使用正确的 YAML 语法。例如

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
      podSelector:
        matchLabels:
          role: client
  ...

此策略包含一个 from 元素,允许来自具有标签 role=client 的 Pod 的连接,这些 Pod 在具有标签 user=alice 的命名空间中。但是,以下策略不同

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
    - podSelector:
        matchLabels:
          role: client
  ...

它包含 from 数组中的两个元素,允许来自本地命名空间中带有标签 role=client 的 Pod 的连接,或者来自任何命名空间中带有标签 user=alice 的任何 Pod 的连接。

如有疑问,请使用 kubectl describe 查看 Kubernetes 如何解释策略。

ipBlock:这将选择特定的 IP CIDR 范围以允许作为入站来源或出站目标。由于 Pod IP 是短暂且不可预测的,因此这些应该是集群外部 IP。

集群入站和出站机制通常需要重写数据包的源或目标 IP。在这种情况下,未定义这是在网络策略处理之前还是之后发生,并且行为对于不同的网络插件、云提供商、Service 实现等组合可能不同。

对于入站,这意味着在某些情况下,您可能能够根据实际的原始源 IP 过滤传入数据包,而在其他情况下,网络策略作用的“源 IP”可能是 LoadBalancer 的 IP 或 Pod 的节点的 IP 等。

对于出站,这意味着来自 Pod 到 Service IP 的连接会被重写为集群外部 IP,这些连接可能会或可能不会受到基于 ipBlock 的策略的影响。

默认策略

默认情况下,如果命名空间中不存在任何策略,则允许所有入站和出站流量进出该命名空间中的 Pod。以下示例允许您更改该命名空间中的默认行为。

默认拒绝所有入站流量

您可以通过创建一个选择所有 Pod 但不允许任何入站流量流向这些 Pod 的网络策略,为命名空间创建一个“默认”入站隔离策略。

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress

这确保即使不受任何其他网络策略选择的 Pod 仍然会因入站而隔离。此策略不会影响任何 Pod 的出站隔离。

允许所有入站流量

如果您想允许所有传入连接到命名空间中的所有 Pod,您可以创建一个明确允许该连接的策略。

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

使用此策略,任何其他策略或策略都不会导致任何传入连接到这些 Pod 被拒绝。此策略对任何 Pod 的出站隔离没有影响。

默认拒绝所有出站流量

您可以通过创建一个选择所有 Pod 但不允许任何出站流量来自这些 Pod 的网络策略,为命名空间创建一个“默认”出站隔离策略。

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes:
  - Egress

这确保即使不受任何其他网络策略选择的 Pod 也不会被允许出站流量。此策略不会更改任何 Pod 的入站隔离行为。

允许所有出站流量

如果您想允许来自命名空间中所有 Pod 的所有连接,您可以创建一个明确允许来自该命名空间中 Pod 的所有传出连接的策略。

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-egress
spec:
  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

使用此策略,任何其他策略或策略都不会导致任何来自这些 Pod 的传出连接被拒绝。此策略对任何 Pod 的入站隔离没有影响。

默认拒绝所有入站和所有出站流量

您可以通过在该命名空间中创建以下网络策略,为命名空间创建一个“默认”策略,该策略阻止所有入站和出站流量。

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

这确保即使不受任何其他网络策略选择的 Pod 也不会被允许入站或出站流量。

网络流量过滤

网络策略针对 第 4 层 连接(TCP、UDP 和可选的 SCTP)定义。对于所有其他协议,行为可能会因网络插件而异。

当定义了 deny all 网络策略时,它只保证拒绝 TCP、UDP 和 SCTP 连接。对于其他协议,如 ARP 或 ICMP,行为未定义。这同样适用于允许规则:当特定 Pod 被允许作为入站来源或出站目标时,ICMP 数据包会发生什么(例如)是未定义的。诸如 ICMP 类的协议可能被某些网络插件允许,而被其他插件拒绝。

目标端口范围

功能状态: Kubernetes v1.25 [稳定]

在编写网络策略时,您可以定位端口范围而不是单个端口。

这可以通过使用 endPort 字段来实现,如下例所示

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: multi-port-egress
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/24
      ports:
        - protocol: TCP
          port: 32000
          endPort: 32768

上述规则允许命名空间 default 上带有标签 role=db 的任何 Pod 与 10.0.0.0/24 范围内的任何 IP 通信,通过 TCP,前提是目标端口在 32000 到 32768 的范围内。

使用此字段时,适用以下限制

  • endPort 字段必须等于或大于 port 字段。
  • 仅当也定义了 port 时,才能定义 endPort
  • 两个端口必须是数字。

通过标签定位多个命名空间

在这种情况下,您的 Egress 网络策略使用其标签名称定位多个命名空间。要使其正常工作,您需要标记目标命名空间。例如

kubectl label namespace frontend namespace=frontend
kubectl label namespace backend namespace=backend

在您的网络策略文档中添加 namespaceSelector 下的标签。例如

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-namespaces
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchExpressions:
        - key: namespace
          operator: In
          values: ["frontend", "backend"]

通过其名称定位命名空间

Kubernetes 控制平面在所有命名空间上设置了一个不可变标签 kubernetes.io/metadata.name,标签的值是命名空间名称。

虽然网络策略无法使用某些对象字段通过其名称定位命名空间,但您可以使用标准化标签来定位特定命名空间。

Pod 生命周期

当创建新的网络策略对象时,网络插件可能需要一些时间来处理新对象。如果受网络策略影响的 Pod 在网络插件完成网络策略处理之前创建,则该 Pod 可能会在未受保护的情况下启动,并且当网络策略处理完成后,将应用隔离规则。

一旦网络插件处理了网络策略,

  1. 所有受给定网络策略影响的全新创建的 Pod 将在启动之前被隔离。网络策略的实现必须确保在整个 Pod 生命周期中过滤有效,即使从 Pod 中任何容器启动的第一刻起也是如此。由于它们应用于 Pod 级,因此网络策略同样适用于初始化容器、边车容器和常规容器。

  2. 允许规则最终将在隔离规则之后应用(或者可能同时应用)。在最坏的情况下,新创建的 Pod 在首次启动时可能根本没有网络连接,如果隔离规则已应用,但尚未应用任何允许规则。

每个创建的网络策略最终将由网络插件处理,但无法从 Kubernetes API 中得知确切的时间。

因此,Pod 必须能够承受在启动时具有与预期不同的网络连接。如果您需要确保 Pod 可以在启动之前到达特定目标,您可以使用 初始化容器 来等待这些目标变得可到达,然后 kubelet 启动应用程序容器。

每个网络策略最终将应用于所有选定的 Pod。由于网络插件可能会以分布式方式实现网络策略,因此当 Pod 首次创建时或当 Pod 或策略更改时,Pod 可能会看到网络策略略有不一致的视图。例如,新创建的 Pod 应该能够到达节点 1 上的 Pod A 和节点 2 上的 Pod B,但可能发现它可以立即到达 Pod A,但不能到达 Pod B 直到几秒钟后。

网络策略和 hostNetwork Pod

hostNetwork Pod 的网络策略行为是未定义的,但它应该限于两种可能性

  • 网络插件可以区分 hostNetwork Pod 流量与所有其他流量(包括能够区分同一节点上不同 hostNetwork Pod 的流量),并将像对待 Pod 网络 Pod 一样将网络策略应用于 hostNetwork Pod。
  • 网络插件无法正确区分 hostNetwork Pod 流量,因此在匹配 podSelectornamespaceSelector 时忽略 hostNetwork Pod。进出 hostNetwork Pod 的流量与进出节点 IP 的所有其他流量的处理方式相同。(这是最常见的实现方式。)

这适用于

  1. hostNetwork Pod 被 spec.podSelector 选择。

      ...
      spec:
        podSelector:
          matchLabels:
            role: client
      ...
    
  2. hostNetwork Pod 被 ingressegress 规则中的 podSelectornamespaceSelector 选择。

      ...
      ingress:
        - from:
          - podSelector:
              matchLabels:
                role: client
      ...
    

同时,由于 hostNetwork Pod 与它们所在的节点具有相同的 IP 地址,因此它们的连接将被视为节点连接。例如,您可以使用 ipBlock 规则允许来自 hostNetwork Pod 的流量。

您无法使用网络策略执行的操作(至少,目前还不行)

截至 Kubernetes 1.31,以下功能在 NetworkPolicy API 中尚不存在,但您可以使用操作系统组件(如 SELinux、OpenVSwitch、IPTables 等)或第 7 层技术(Ingress 控制器、服务网格实现)或准入控制器来实现变通方法。如果您不熟悉 Kubernetes 中的网络安全,那么值得注意的是,以下用户故事还无法使用 NetworkPolicy API 实现。

  • 强制内部集群流量通过公共网关(这可能最适合使用服务网格或其他代理)。
  • 任何与 TLS 相关的内容(为此使用服务网格或 Ingress 控制器)。
  • 节点特定策略(您可以使用 CIDR 表示法,但无法通过其 Kubernetes 身份专门针对节点)。
  • 按名称定位服务(但是,您可以按其 标签 来定位 Pod 或命名空间,这通常是一种可行的解决方法)。
  • 创建或管理由第三方完成的“策略请求”。
  • 应用于所有命名空间或 Pod 的默认策略(有一些第三方 Kubernetes 发行版和项目可以做到这一点)。
  • 高级策略查询和可达性工具。
  • 记录网络安全事件的能力(例如被阻止或接受的连接)。
  • 显式拒绝策略的能力(当前 NetworkPolicies 的模型是默认拒绝,只能添加允许规则)。
  • 阻止环回或传入主机流量的能力(Pod 目前无法阻止 localhost 访问,也无法阻止来自其驻留节点的访问)。

NetworkPolicy 对现有连接的影响

当应用于现有连接的 NetworkPolicies 集合发生变化时 - 这可能是由于 NetworkPolicies 发生变化,或者如果策略选择(主题和对等方)的命名空间/Pod 的相关标签在现有连接的中间发生变化 - 对此变化是否会对该现有连接生效是实现定义的。例如:创建了一个策略导致拒绝先前允许的连接,底层网络插件实现负责定义该新策略是否会关闭现有连接。建议不要修改可能影响现有连接的策略/Pod/命名空间。

接下来是什么

  • 有关更多示例,请参见 声明网络策略 演练。
  • 查看更多 食谱,了解 NetworkPolicy 资源支持的常见场景。
最后修改时间:2024 年 4 月 1 日 下午 3:05 PST:指向 NetworkPolicy 的 API 参考的指示牌(f1c4eb8457)