4. NetworkPolicy 基础:概念、默认拒绝与选择器

在多租户 Kubernetes 集群中,网络隔离是租户安全的第一道防线。NetworkPolicy 是一种 Kubernetes 资源,它通过标签选择器定义 Pod 之间以及 Pod 与外部端点之间的流量规则,实现微隔离。本章将深入讲解 NetworkPolicy 的核心概念、默认拒绝策略的配置方法,以及 Pod 选择器与命名空间选择器的使用方式。

4.1 NetworkPolicy 核心概念

NetworkPolicy 是 Kubernetes 网络安全的基石,它工作在 OSI 模型的第 3/4 层(IP 地址和端口),通过白名单机制控制 Pod 的入站(Ingress)和出站(Egress)流量。默认情况下,Kubernetes 集群中的所有 Pod 可以互相通信,没有任何网络限制。一旦为某个 Pod 应用了 NetworkPolicy,该 Pod 的流量将受到策略规则的约束。

概念 说明 关键字段
Pod 选择器 通过标签选择目标 Pod,策略只作用于匹配的 Pod spec.podSelector
策略类型 定义策略控制的方向:Ingress(入站)、Egress(出站)或两者 spec.policyTypes
Ingress 规则 允许哪些来源访问目标 Pod spec.ingress[].from
Egress 规则 允许目标 Pod 访问哪些目的地 spec.egress[].to
端口规则 限制允许的协议和端口范围 spec.ingress[].ports
关键理解:NetworkPolicy 是“白名单”机制。当策略生效时,未显式允许的流量将被拒绝。这意味着,即使只定义了一条允许规则,所有其他未匹配的流量都会被丢弃。

4.2 默认拒绝策略

默认拒绝策略是构建零信任网络模型的基础。在多租户场景中,通常先为每个租户的命名空间应用默认拒绝策略,然后通过细粒度规则逐步开放必要的通信路径。默认拒绝策略分为三种类型:

  • 拒绝所有入站流量:阻止外部所有来源访问命名空间内的 Pod。
  • 拒绝所有出站流量:阻止命名空间内的 Pod 访问任何外部目标。
  • 拒绝所有入站和出站流量:完全隔离命名空间,实现最大程度的网络隔离。

4.2.1 默认拒绝入站策略示例

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: tenant-a
spec:
  podSelector: {}          # 匹配命名空间内所有 Pod
  policyTypes:
  - Ingress                # 只控制入站流量
  # 不定义 ingress 规则,表示拒绝所有入站流量

4.2.2 默认拒绝出站策略示例

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: tenant-a
spec:
  podSelector: {}
  policyTypes:
  - Egress                 # 只控制出站流量
  # 不定义 egress 规则,表示拒绝所有出站流量

4.2.3 完全隔离策略示例

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: tenant-a
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  # 不定义任何规则,拒绝所有入站和出站流量
注意:默认拒绝策略必须与 CNI 网络插件配合使用。常见的支持 NetworkPolicy 的 CNI 插件包括 Calico、Cilium、Weave Net 和 Antrea。如果集群未安装支持 NetworkPolicy 的 CNI 插件,这些策略将不会生效。

4.3 Pod 选择器与命名空间选择器

NetworkPolicy 通过选择器机制精确控制流量范围。选择器分为 Pod 选择器和命名空间选择器,两者可以组合使用,实现跨命名空间的细粒度访问控制。

4.3.1 Pod 选择器

Pod 选择器使用标签匹配目标 Pod。当 podSelector 为空对象 {} 时,匹配命名空间内的所有 Pod。当指定具体标签时,只匹配带有该标签的 Pod。

# 只允许带有 app=web 标签的 Pod 接收来自 app=api 标签 Pod 的流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-from-api
  namespace: tenant-a
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 8080

4.3.2 命名空间选择器

命名空间选择器允许跨命名空间访问控制。通过 namespaceSelector 选择目标命名空间,再结合 podSelector 选择该命名空间内的 Pod。

# 允许 tenant-b 命名空间中所有 Pod 访问 tenant-a 中 app=web 的 Pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-tenant-b
  namespace: tenant-a
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          tenant: tenant-b
      podSelector: {}    # 匹配 tenant-b 中的所有 Pod

4.3.3 选择器组合规则

选择器组合 匹配范围 使用场景
podSelector 单独使用 同一命名空间内的 Pod 微服务间通信,如前端访问后端
namespaceSelector 单独使用 整个命名空间的所有 Pod 允许某个租户访问另一个租户的全部服务
namespaceSelector + podSelector 指定命名空间中的指定 Pod 跨租户的精确服务访问,如监控系统访问各租户的指标端点
ipBlock 集群外部的 IP 地址段 允许外部监控系统或 CI/CD 工具访问集群内服务
最佳实践:在多租户集群中,建议为每个租户命名空间创建默认拒绝策略,然后使用命名空间选择器配合 Pod 选择器,精确开放必要的跨租户通信路径。避免使用 ipBlock 直接暴露 Pod 到外部网络,除非有明确的业务需求。

4.4 NetworkPolicy 流量控制流程

下图展示了 NetworkPolicy 在 Pod 流量控制中的完整工作流程,从流量发起、策略匹配到最终放行或拒绝的决策路径。

NetworkPolicy 流量控制流程图 NetworkPolicy 流量控制流程 流量发起方 Pod 目标 Pod 是否存在 NetworkPolicy? 无策略 默认允许所有流量 有策略 评估 Ingress/Egress 规则 流量是否匹配允许规则? 匹配 允许流量通过 不匹配 拒绝流量(丢弃) 说明:当目标 Pod 没有 NetworkPolicy 时,默认允许所有流量;一旦应用策略,未显式允许的流量将被拒绝。

4.5 多租户场景下的 NetworkPolicy 设计模式

在多租户集群中,NetworkPolicy 的设计需要兼顾隔离性和可用性。以下是三种常见的设计模式:

  • 完全隔离模式:每个租户命名空间应用默认拒绝所有策略,然后通过命名空间选择器开放必要的跨租户通信。适用于金融、医疗等强合规场景。
  • 共享服务模式:为共享服务命名空间(如监控、日志、DNS)创建允许策略,使所有租户可以访问这些基础服务,但租户之间保持隔离。
  • 分层访问模式:根据租户等级(如免费、付费、企业)设置不同的网络策略,高级别租户拥有更灵活的通信权限。
实践建议:在实施 NetworkPolicy 前,先使用 kubectl describe networkpolicy 和 kubectl get networkpolicy -n <namespace> 检查现有策略。使用 kubectl run 临时 Pod 进行连通性测试,验证策略是否按预期生效。

4.6 常见问题与排错

问题 可能原因 解决方案
策略不生效 CNI 插件不支持 NetworkPolicy 检查集群 CNI 插件类型,更换为 Calico 或 Cilium
Pod 无法访问 DNS 默认拒绝出站策略阻止了 DNS 流量 添加允许 UDP 53 端口的 Egress 规则,或使用 kube-system 命名空间选择器
跨命名空间通信失败 命名空间选择器标签不匹配 使用 kubectl get namespace --show-labels 检查命名空间标签
策略冲突 多个 NetworkPolicy 作用于同一 Pod Kubernetes 会合并所有策略,只要有一个策略允许则放行;建议使用标签统一管理