2、K8s网络策略(NetworkPolicy)基础:NetworkPolicy资源定义、Pod选择器、Ingress/Egress规则、默认拒绝策略

2.1 NetworkPolicy 资源定义

NetworkPolicy 是 Kubernetes 原生的网络安全资源对象,用于控制 Pod 组之间的网络通信。它工作在 OSI 第 3/4 层(IP 地址和端口),通过标签选择器匹配目标 Pod,并定义允许的入站(Ingress)和出站(Egress)流量规则。

一个完整的 NetworkPolicy 资源定义包含以下核心字段:

字段 类型 说明
apiVersion string 固定为 networking.k8s.io/v1
kind string 固定为 NetworkPolicy
metadata ObjectMeta 名称、命名空间、标签等元数据
spec.podSelector LabelSelector 选择策略生效的目标 Pod 组
spec.policyTypes []PolicyType 声明策略类型:Ingress、Egress 或两者
spec.ingress []NetworkPolicyIngressRule 入站规则列表(可选)
spec.egress []NetworkPolicyEgressRule 出站规则列表(可选)
关键原则:NetworkPolicy 是“白名单”机制——只定义允许的流量,未明确允许的流量默认被拒绝。策略生效的前提是集群已安装支持 NetworkPolicy 的 CNI 插件(如 Calico、Cilium、Weave Net)。

以下是一个基础的 NetworkPolicy YAML 示例:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web
      tier: frontend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-gateway
    ports:
    - protocol: TCP
      port: 8080

2.2 Pod 选择器(podSelector)

Pod 选择器是 NetworkPolicy 的核心定位机制,通过标签(Label)匹配确定策略作用的目标 Pod 组。选择器支持两种匹配模式:

  • matchLabels:精确匹配,要求 Pod 包含所有指定的标签键值对。
  • matchExpressions:表达式匹配,支持 In、NotIn、Exists、DoesNotExist 四种操作符。

选择器行为要点:

  • 如果 podSelector 为空({}),策略将匹配命名空间内的所有 Pod。
  • 策略只作用于 metadata.namespace 指定的命名空间,不会跨命名空间生效。
  • 一个命名空间可以应用多个 NetworkPolicy,规则之间是“或”关系——只要任一策略允许,流量即被放行。
多租户隔离提示:在多租户场景中,建议为每个租户的 Pod 打上明确的租户标签(如 tenant: alpha),然后通过 podSelector 精确匹配租户标签,避免策略误覆盖其他租户的 Pod。

2.3 Ingress / Egress 规则

Ingress 规则控制入站流量(谁可以访问目标 Pod),Egress 规则控制出站流量(目标 Pod 可以访问谁)。每条规则由 来源/目的地选择器 和 端口列表 组成。

2.3.1 Ingress 规则结构

ingress:
- from:                    # 来源选择器列表(多个来源之间是“或”关系)
  - podSelector:           # 来源 Pod 标签选择
      matchLabels:
        app: api
  - namespaceSelector:     # 来源命名空间标签选择
      matchLabels:
        env: staging
  - ipBlock:               # 来源 IP 段(CIDR)
      cidr: 10.0.0.0/16
      except:              # 排除的 IP 段(可选)
      - 10.0.1.0/24
  ports:                   # 目标端口列表(多个端口之间是“或”关系)
  - protocol: TCP
    port: 443
  - protocol: UDP
    port: 53

2.3.2 Egress 规则结构

egress:
- to:                      # 目的地选择器列表(多个目的地之间是“或”关系)
  - podSelector:
      matchLabels:
        app: database
  - namespaceSelector:
      matchLabels:
        name: monitoring
  - ipBlock:
      cidr: 0.0.0.0/0      # 允许访问所有外部 IP
      except:
      - 10.0.0.0/8
  ports:
  - protocol: TCP
    port: 5432

选择器组合规则:

  • podSelector + namespaceSelector:当两者同时出现在同一个 from/to 条目中时,表示“且”关系——来源 Pod 必须同时匹配两个选择器。
  • 多个 from/to 条目:条目之间是“或”关系——匹配任一条目即允许。
  • 空 ports:如果未指定端口,规则匹配所有端口。
常见误区:Egress 规则中的 ipBlock 如果设置为 0.0.0.0/0,会允许访问所有外部 IP,包括集群外部的公网地址。在多租户隔离场景中,应严格限制出站 IP 范围,避免数据外泄。

2.4 默认拒绝策略

Kubernetes 默认允许所有 Pod 之间的通信。要实现“默认拒绝”,需要显式创建 NetworkPolicy 来锁定命名空间的流量边界。默认拒绝策略分为三种类型:

策略类型 YAML 关键配置 效果
默认拒绝所有入站 podSelector: {}
policyTypes: [Ingress]
不定义 ingress 规则
拒绝所有进入命名空间内 Pod 的流量
默认拒绝所有出站 podSelector: {}
policyTypes: [Egress]
不定义 egress 规则
拒绝所有从命名空间内 Pod 发出的流量
默认拒绝所有双向 podSelector: {}
policyTypes: [Ingress, Egress]
不定义 ingress 和 egress 规则
完全隔离命名空间,内外流量均被拒绝

默认拒绝所有入站流量的示例:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  # 没有 ingress 规则,所有入站流量被拒绝

默认拒绝所有出站流量的示例:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  # 没有 egress 规则,所有出站流量被拒绝
多租户隔离最佳实践:在创建租户命名空间时,首先应用“默认拒绝所有双向”策略,然后根据租户的实际通信需求逐步添加白名单规则。这种“先锁后开”的方式可以避免因遗漏策略导致的安全漏洞。

2.5 NetworkPolicy 流量控制流程

下图展示了 NetworkPolicy 在 Pod 通信中的决策流程:

NetworkPolicy 流量控制决策流程 源 Pod NetworkPolicy 规则匹配检查 允许通过 拒绝丢弃 目标 Pod 决策说明: 1. 源 Pod 发起流量时,系统检查目标 Pod 所在命名空间的所有 NetworkPolicy。 2. 如果存在匹配的 Ingress 规则,流量被允许;否则被拒绝。 3. 如果命名空间没有任何 NetworkPolicy,默认允许所有流量(K8s 默认行为)。 4. 一旦存在至少一条 NetworkPolicy,未显式允许的流量即被拒绝(隐式拒绝)。 5. Egress 规则同理,在源 Pod 侧进行出站流量检查。

2.6 多租户场景下的策略组合示例

以下是一个典型的多租户隔离策略组合,展示如何通过多个 NetworkPolicy 实现“默认拒绝 + 按需开放”:

# 策略1:默认拒绝所有双向流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: tenant-deny-all
  namespace: tenant-alpha
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
---
# 策略2:允许租户内部 Pod 互相通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: tenant-allow-internal
  namespace: tenant-alpha
spec:
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: tenant-alpha
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: tenant-alpha
---
# 策略3:允许从 API 网关访问 Web Pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-gateway-to-web
  namespace: tenant-alpha
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: shared-infra
      podSelector:
        matchLabels:
          app: api-gateway
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 443
策略生效顺序:Kubernetes 对 NetworkPolicy 的评估顺序是“先匹配先允许”——只要有一条策略的规则匹配流量,流量即被放行,不再继续检查后续策略。因此,默认拒绝策略必须放在最前面,白名单策略放在后面。