4. 网络隔离策略(NetworkPolicy)

在多租户 Kubernetes 集群中,仅靠命名空间(Namespace)的逻辑隔离远远不够。恶意 Pod 或配置错误的组件可能绕过命名空间边界,访问其他租户的资源。NetworkPolicy 是 Kubernetes 原生的网络隔离声明式资源,它通过标签选择器定义 Pod 之间、Pod 与外部端点之间的流量规则,是实现多租户网络隔离的核心手段。

4.1 NetworkPolicy 定义与核心字段

NetworkPolicy 属于 networking.k8s.io/v1 API 组,其声明式 YAML 结构包含以下关键字段:

字段 类型 说明
podSelector LabelSelector 选择策略生效的目标 Pod(必须字段)
policyTypes []string 指定策略类型:Ingress、Egress 或两者
ingress []IngressRule 入站规则:允许哪些来源访问目标 Pod
egress []EgressRule 出站规则:目标 Pod 允许访问哪些目的地
关键理解:NetworkPolicy 是“白名单”机制。一旦命名空间内存在任何 NetworkPolicy 匹配某个 Pod,该 Pod 默认拒绝所有未显式允许的流量。没有 NetworkPolicy 的命名空间,默认允许所有流量。

4.2 Pod 选择器与策略类型

4.2.1 Pod 选择器(podSelector)

通过标签选择器精确匹配目标 Pod。空选择器 {} 匹配命名空间内所有 Pod。

# 示例:选择标签 app=web 的 Pod
podSelector:
  matchLabels:
    app: web

4.2.2 策略类型(policyTypes)

显式声明策略生效方向,避免歧义:

  • Ingress:控制入站流量。未指定时,默认只对 Ingress 规则生效。
  • Egress:控制出站流量。必须显式声明才能生效。
  • 同时声明:同时控制入站和出站,实现双向隔离。
常见陷阱:如果只写 ingress 规则但未在 policyTypes 中包含 Egress,出站流量不会被策略限制。反之亦然。建议始终显式声明 policyTypes。

4.3 多租户网络隔离实战

假设集群中有两个租户:租户 A(命名空间 tenant-a)和 租户 B(命名空间 tenant-b)。要求:

  • 租户 A 的 Pod 只能与同命名空间内的 Pod 通信。
  • 租户 B 的 Pod 可以访问租户 A 中标签为 app: api 的 Pod(跨租户白名单)。
  • 所有 Pod 禁止访问公网(除 DNS 解析外)。

4.3.1 租户 A 的隔离策略

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: tenant-a-isolation
  namespace: tenant-a
spec:
  podSelector: {}          # 匹配命名空间内所有 Pod
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: tenant-a
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: tenant-a
    - to:
        - namespaceSelector: {}   # 允许访问 kube-system 的 DNS
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53

4.3.2 租户 B 的跨租户访问策略

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: tenant-b-to-tenant-a-api
  namespace: tenant-a
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: tenant-b
实战要点:
  • namespaceSelector 与 podSelector 可组合使用,实现精细的跨命名空间访问控制。
  • DNS 解析通常由 kube-dns 或 CoreDNS 提供,必须显式放行 UDP 53 端口,否则 Pod 无法解析域名。
  • NetworkPolicy 依赖 CNI 插件支持(如 Calico、Cilium、Weave Net)。部分 CNI 不支持 Egress 策略,需提前验证。

4.4 网络隔离策略工作流程

下图展示了多租户场景下 NetworkPolicy 的匹配与流量控制逻辑:

NetworkPolicy 多租户流量控制流程 命名空间:tenant-a Pod: app=web Pod: app=api 策略:tenant-a-isolation Ingress: 仅允许 tenant-a Egress: 仅允许 tenant-a + DNS 命名空间:tenant-b Pod: app=frontend Pod: app=worker 策略:tenant-b-to-tenant-a-api Ingress: 允许 tenant-b 目标 Pod: app=api (tenant-a) 允许(白名单) 拒绝(无匹配策略) kube-system / CoreDNS UDP 53

4.5 策略验证与排错

部署 NetworkPolicy 后,使用以下方法验证隔离效果:

验证方法 命令/工具 预期结果
查看策略是否生效 kubectl get networkpolicy -n tenant-a 显示已创建的策略列表
测试 Pod 连通性 kubectl exec -n tenant-b pod/frontend -- curl -m 3 http://service-a:8080 白名单路径成功,其他路径超时
检查 DNS 解析 kubectl exec -n tenant-a pod/web -- nslookup kubernetes.default 成功返回 IP(证明 DNS 放行正常)
审计日志 CNI 插件自带工具(如 calicoctl、cilium monitor) 查看被拒绝的流量记录
排错建议:如果策略未按预期生效,首先检查 CNI 插件是否支持 NetworkPolicy(如 Flannel 默认不支持)。其次确认 policyTypes 字段是否显式声明,以及 namespaceSelector 的标签是否正确(Kubernetes 1.22+ 推荐使用 kubernetes.io/metadata.name 标签匹配命名空间名称)。

4.6 多租户网络隔离最佳实践

  • 默认拒绝所有流量:为每个租户命名空间创建一条默认拒绝所有 Ingress 和 Egress 的策略,再逐步添加白名单规则。
  • 使用命名空间标签:为每个租户命名空间打上唯一标签(如 tenant: alpha),便于 namespaceSelector 批量匹配。
  • 分层策略:将全局策略(如允许监控系统访问)与租户级策略分开管理,避免策略冲突。
  • 策略即代码:将 NetworkPolicy YAML 纳入 GitOps 流程,通过 CI/CD 自动部署并验证隔离效果。
  • 监控与告警:集成网络流量审计工具,对违反策略的访问行为进行实时告警。

通过 NetworkPolicy 的声明式定义,多租户集群可以实现细粒度、可审计的网络隔离,为后续的制品签名链路和发布证据链提供安全的网络基础。