4. 网络策略与微隔离:NetworkPolicy 原理、默认拒绝策略、命名空间隔离、跨命名空间通信控制

在云原生环境中,传统的基于 IP 地址的防火墙策略难以应对 Pod 动态调度、IP 频繁变化的特性。Kubernetes NetworkPolicy 提供了一种声明式的、基于标签选择器的网络访问控制机制,是实现微隔离(Micro-Segmentation)的核心 API 资源。本节将深入解析 NetworkPolicy 的工作原理、默认拒绝策略的落地方法、命名空间级别的隔离模式以及跨命名空间通信的精细控制。

4.1 NetworkPolicy 核心原理与资源模型

NetworkPolicy 是一个命名空间级别的资源,通过 spec.podSelector 选定目标 Pod 组,再通过 ingress 和 egress 规则定义允许的流量。其底层实现依赖于 CNI 插件(如 Calico、Cilium、Antrea)将策略翻译为节点上的 iptables、eBPF 或 IPVS 规则。

字段 类型 说明
podSelector LabelSelector 选定策略作用的 Pod 组(默认为空时选中命名空间内所有 Pod)
policyTypes []PolicyType 声明策略生效方向:Ingress、Egress 或两者
ingress[].from []NetworkPolicyPeer 允许入站流量的来源:ipBlock、namespaceSelector、podSelector
egress[].to []NetworkPolicyPeer 允许出站流量的目标
ingress[].ports []NetworkPolicyPort 允许的入站端口与协议(TCP/UDP/SCTP)
egress[].ports []NetworkPolicyPort 允许的出站端口与协议
关键原则: NetworkPolicy 是“白名单”机制。一旦命名空间内任何 Pod 被 NetworkPolicy 选中,未显式允许的流量将被拒绝。如果命名空间内没有任何 NetworkPolicy,则默认允许所有流量。

4.2 默认拒绝策略:零信任的起点

实施微隔离的第一步是建立“默认拒绝”基线。通过创建一条选中所有 Pod 但不允许任何流量的 NetworkPolicy,可以强制所有后续策略必须显式放行。

4.2.1 默认拒绝所有入站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}          # 选中命名空间内所有 Pod
  policyTypes:
  - Ingress                # 仅控制入站方向
  # ingress 列表为空,表示拒绝所有入站流量

4.2.2 默认拒绝所有出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  # egress 列表为空,表示拒绝所有出站流量
最佳实践: 建议在每一个非系统命名空间(如 production、staging)中同时部署 default-deny-ingress 和 default-deny-egress 两条策略,形成双向默认拒绝的零信任基础。

4.3 命名空间隔离:基于标签的租户边界

命名空间是 Kubernetes 的逻辑隔离单元,但默认情况下不同命名空间的 Pod 可以互相通信。通过 namespaceSelector 结合 NetworkPolicy,可以实现命名空间级别的隔离墙。

4.3.1 禁止跨命名空间入站

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-cross-ns-ingress
  namespace: payment
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: payment   # 仅允许同命名空间流量

4.3.2 允许特定命名空间访问

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-monitoring-from-observability
  namespace: payment
spec:
  podSelector:
    matchLabels:
      app: payment-api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: observability
      podSelector:
        matchLabels:
          app: prometheus
    ports:
    - protocol: TCP
      port: 9090
注意: namespaceSelector 与 podSelector 在同一 from 条目中时,是“与”关系(即同时满足命名空间和 Pod 标签)。若需要“或”关系,应拆分为多个 from 条目。

4.4 跨命名空间通信控制:精细化的服务间访问

在微服务架构中,跨命名空间通信是常态(如 frontend 调用 backend,backend 调用 database)。NetworkPolicy 通过组合 namespaceSelector 和 podSelector 实现精细控制。

4.4.1 典型三层架构策略示例

# 在 frontend 命名空间:允许 Ingress 控制器访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-to-frontend
  namespace: frontend
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
      podSelector:
        matchLabels:
          app: nginx-ingress
    ports:
    - protocol: TCP
      port: 80
---
# 在 backend 命名空间:仅允许 frontend 命名空间的 Pod 访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-frontend
  namespace: backend
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: frontend
      podSelector:
        matchLabels:
          app: web
    ports:
    - protocol: TCP
      port: 8080

4.5 NetworkPolicy 微隔离架构图

下图展示了在启用了默认拒绝策略的集群中,通过 NetworkPolicy 实现命名空间隔离与跨命名空间通信控制的完整流量路径。

NetworkPolicy 微隔离架构图 NetworkPolicy 微隔离架构:默认拒绝 + 命名空间隔离 + 跨命名空间通信 命名空间: ingress-nginx nginx-ingress Pod app: nginx-ingress 命名空间: frontend web Pod app: web 默认拒绝入站 + 出站 命名空间: backend api Pod app: api 默认拒绝入站 + 出站 策略: allow-ingress ns: ingress-nginx 策略: allow-from-frontend ns: frontend, app: web ❌ 外部直接访问被拒绝 ❌ 未授权跨命名空间被拒绝 ❌ 出站到外部被拒绝 图例: Ingress 控制器 前端服务 后端服务 NetworkPolicy 规则 允许流量 拒绝流量 注:所有命名空间均部署了 default-deny-ingress 和 default-deny-egress 策略,仅显式允许的流量可通过。

4.6 策略生效顺序与常见陷阱

陷阱场景 错误示例 正确做法
未指定 policyTypes 只写 ingress 规则,未声明 policyTypes 显式声明 policyTypes: [Ingress],避免默认行为歧义
误用空 podSelector podSelector: {} 未理解其含义 明确 podSelector: {} 表示选中命名空间内所有 Pod
忽略 DNS 出站 出站默认拒绝后,Pod 无法解析 DNS 添加允许出站到 kube-dns 的策略:namespaceSelector: { matchLabels: { kubernetes.io/metadata.name: kube-system } } 且端口 53 UDP
策略数量过多导致性能下降 每个 Pod 单独一条策略 使用标签聚合,减少策略总数(建议 < 1000 条/集群)
忘记 CNI 兼容性 使用 ipBlock 但 CNI 不支持 确认 CNI 插件(Calico/Cilium/Antrea)对 ipBlock 的支持程度

4.7 策略审计与可视化建议

在生产环境中,NetworkPolicy 的审计和可视化至关重要。推荐以下工具链:

  • kubectl netpol:命令行工具,快速查看策略与 Pod 的匹配关系。
  • Calico Enterprise / Calico Cloud:提供策略建议、模拟和拓扑图。
  • Cilium Hubble:基于 eBPF 的实时流量与策略可视化。
  • npguard:策略合规性检查工具,防止配置漂移。
核验要点: 在基线核验架构中,NetworkPolicy 的生效状态应作为 Kubernetes 资源模型 的一部分持续监控。建议将策略覆盖率、拒绝事件数、策略变更历史纳入 Prometheus 指标,并通过 Envoy 的访问日志进行二次验证,确保“策略即代码”的可观测性闭环。