网络策略

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

如果你想为 TCP、UDP 和 SCTP 协议在 IP 地址或端口级别控制流量流向,那么你可以考虑针对集群中的特定应用使用 Kubernetes NetworkPolicies。NetworkPolicies 是一种以应用为中心的结构,它允许你指定一个 Pod 如何通过网络与各种网络“实体”进行通信(我们在此处使用“实体”一词,以避免重载“端点 (endpoints)”和“服务 (services)”等具有特定 Kubernetes 内涵的常用术语)。NetworkPolicies 适用于与 Pod 的一端或两端建立的连接,与其他连接无关。

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

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

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

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

先决条件

网络策略由 网络插件 实现。要使用网络策略,你必须使用支持 NetworkPolicy 的网络解决方案。在没有实现该策略的控制器的情况下创建 NetworkPolicy 资源不会产生任何效果。

Pod 的两种隔离方式

Pod 有两种隔离方式:出口(egress)隔离和入口(ingress)隔离。它们关乎可以建立哪些连接。这里的“隔离”并非绝对,而是指“适用某些限制”。另一种情况“未隔离(针对特定方向)”,意味着在声明的方向上不适用任何限制。这两种隔离方式(或非隔离)是独立声明的,并且对于从一个 Pod 到另一个 Pod 的连接都具有相关性。

默认情况下,Pod 对出口方向是未隔离的;允许所有出站连接。如果存在任何选择该 Pod 且其 policyTypes 中包含“Egress”的 NetworkPolicy,则该 Pod 被视为出口隔离;我们称此类策略适用于该 Pod 的出口方向。当 Pod 对出口进行隔离时,该 Pod 仅允许通过适用于该 Pod 的某个 NetworkPolicy 的 egress 列表所允许的连接。对于那些允许的连接,回复流量也将被隐式允许。这些 egress 列表的影响是累加的。

默认情况下,Pod 对入口方向是未隔离的;允许所有入站连接。如果存在任何选择该 Pod 且其 policyTypes 中包含“Ingress”的 NetworkPolicy,则该 Pod 被视为入口隔离;我们称此类策略适用于该 Pod 的入口方向。当 Pod 对入口进行隔离时,仅允许来自 Pod 节点以及适用于该 Pod 的某个 NetworkPolicy 的 ingress 列表所允许的入站连接。对于那些允许的连接,回复流量也将被隐式允许。这些 ingress 列表的影响是累加的。

网络策略不会冲突;它们是累加的。如果一个或多个策略适用于给定的 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

说明

将此配置 POST 到集群的 API 服务器不会产生任何效果,除非你选择的网络解决方案支持网络策略。

必需字段:与其他所有 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 部分的流量。示例策略包含一条规则,该规则匹配在 TCP 端口 5978 上发往 10.0.0.0/24 中任何目标的流量。

因此,该示例 NetworkPolicy

  1. default 命名空间中 role=db 的 Pod 隔离,用于入站和出站流量(如果它们尚未被隔离)

  2. (入口规则)允许来自以下源的、在 TCP 端口 6379 上发往 default 命名空间中带有标签 role=db 的所有 Pod 的连接

    • default 命名空间中带有标签 role=frontend 的任何 Pod
    • 命名空间中带有标签 project=myproject 的任何 Pod
    • IP 地址范围 172.17.0.0172.17.0.255172.17.2.0172.17.255.255(即 172.17.0.0/16 中除 172.17.1.0/24 之外的所有地址)
  3. (出口规则)允许 default 命名空间中带有标签 role=db 的任何 Pod 发起发往 CIDR 10.0.0.0/24 且在 TCP 端口 5978 上的连接

请参阅 声明网络策略 教程获取更多示例。

tofrom 选择器的行为

ingressfrom 部分或 egressto 部分中可以指定四种选择器

podSelector:这会选择与 NetworkPolicy 位于同一命名空间中的特定 Pod,作为入站流量源或出站流量目标。

namespaceSelector:这会选择特定命名空间,该命名空间中的所有 Pod 都被允许作为入站流量源或出站流量目标。

namespaceSelector podSelector:同时指定 namespaceSelectorpodSelector 的单个 to/from 条目,会选择特定命名空间中的特定 Pod。请务必使用正确的 YAML 语法。例如

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

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

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

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

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

ipBlock:这会选择特定的 IP CIDR 范围,作为入站流量源或出站流量目标。这些应该是集群外部的 IP,因为 Pod IP 是临时且不可预测的。

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

对于入口流量,这意味着在某些情况下,你或许可以基于实际的原始源 IP 过滤入站数据包,而在其他情况下,NetworkPolicy 作用的“源 IP”可能是 LoadBalancer 或 Pod 所在节点的 IP 等。

对于出口流量,这意味着从 Pod 发往被重写为集群外部 IP 的 Service IP 的连接,可能会也可能不会受到基于 ipBlock 的策略的约束。

默认策略

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

默认拒绝所有入站流量

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

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

这确保了即使是没有被任何其他 NetworkPolicy 选择的 Pod,也会进行入口隔离。此策略不影响任何 Pod 的出口隔离。

允许所有入站流量

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

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

应用此策略后,没有任何其他策略可以导致拒绝到达这些 Pod 的任何入站连接。此策略不影响任何 Pod 的出口隔离。

默认拒绝所有出站流量

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

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

这确保了即使是没有被任何其他 NetworkPolicy 选择的 Pod,也不会被允许有出站流量。此策略不会改变任何 Pod 的入口隔离行为。

注意

默认拒绝所有出口的策略也会阻止 DNS 流量。如果你的工作负载需要 DNS 解析,则必须添加一个单独的 NetworkPolicy,允许向集群的 DNS 服务发起出口流量。

允许所有出站流量

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

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

应用此策略后,没有任何其他策略可以导致拒绝来自这些 Pod 的任何出站连接。此策略不影响任何 Pod 的入口隔离。

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

你可以通过在命名空间中创建以下 NetworkPolicy,来为命名空间创建阻止所有入站和出站流量的“默认”策略。

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

这确保了即使是没有被任何其他 NetworkPolicy 选择的 Pod,也不会被允许有入站或出站流量。

网络流量过滤

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

说明

你必须使用支持 SCTP 协议 NetworkPolicies 的 CNI 插件。

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

定位一系列端口

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

编写 NetworkPolicy 时,你可以定位一系列端口,而不是单个端口。

这可以通过使用 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 通过 TCP 与 10.0.0.0/24 范围内的任何 IP 进行通信,前提是目标端口在 32000 到 32768 之间。

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

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

说明

你的集群必须使用支持 NetworkPolicy 规范中 endPort 字段的 CNI 插件。如果你的 网络插件 不支持 endPort 字段,而你指定了一个带有该字段的 NetworkPolicy,则该策略将仅应用于单个 port 字段。

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

在这种场景下,你的 Egress NetworkPolicy 使用标签名称定位多个命名空间。要使其生效,你需要标记目标命名空间。例如

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

在 NetworkPolicy 文档的 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"]

说明

无法在 NetworkPolicy 中直接指定命名空间的名称。你必须使用带有 matchLabelsmatchExpressionsnamespaceSelector 来基于标签选择命名空间。

按名称定位命名空间

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

虽然 NetworkPolicy 无法通过某些对象字段按名称定位命名空间,但你可以使用该标准化标签来定位特定命名空间。

Pod 生命周期

说明

以下内容适用于具有合规网络插件和合规 NetworkPolicy 实现的集群。

当创建新的 NetworkPolicy 对象时,网络插件处理该新对象可能需要一些时间。如果一个受 NetworkPolicy 影响的 Pod 在网络插件完成 NetworkPolicy 处理之前创建,该 Pod 可能在启动时不受保护,而隔离规则将在 NetworkPolicy 处理完成后应用。

一旦 NetworkPolicy 被网络插件处理,

  1. 所有受给定 NetworkPolicy 影响的新创建的 Pod 在启动前都将被隔离。NetworkPolicy 的实现必须确保在整个 Pod 生命周期内过滤都是有效的,即使是从启动该 Pod 中任何容器的那一刻起。因为它们是在 Pod 级别应用的,所以 NetworkPolicies 同样适用于初始化容器、边车容器和常规容器。

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

每个创建的 NetworkPolicy 最终都会被网络插件处理,但无法从 Kubernetes API 中确定具体发生的时间。

因此,Pod 必须具有在启动时连接性与预期不同的适应能力。如果你需要确保 Pod 在启动前可以访问某些目标,可以使用 初始化容器 在 kubelet 启动应用容器之前等待这些目标变为可访问状态。

每个 NetworkPolicy 最终都会应用于所有选定的 Pod。因为网络插件可能以分布式方式实现 NetworkPolicy,所以当 Pod 首次创建,或者当 Pod 或策略发生变化时,Pod 看到的网络策略视图可能会稍有不一致。例如,一个旨在能够访问节点 1 上的 Pod A 和节点 2 上的 Pod B 的新创建的 Pod,可能会发现它可以立即访问 Pod A,但几秒钟后才能访问 Pod B。

NetworkPolicy 和 hostNetwork Pod

hostNetwork Pod 的 NetworkPolicy 行为是未定义的,但它应该局限于两种可能性

  • 网络插件可以将 hostNetwork Pod 的流量与所有其他流量区分开来(包括能够区分同一节点上不同 hostNetwork Pod 的流量),并将 NetworkPolicy 应用于 hostNetwork Pod,就像它对 Pod 网络 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.36,以下功能在 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 资源启用的常见场景的 方案

最后修改时间:2026 年 4 月 14 日凌晨 1:15(太平洋标准时间):fix(links): update kubernetes/community links from master to main (03c191bcc4)