第280篇:云原生网络策略 NetworkPolicy 实现

关键词

NetworkPolicy、K8s 网络策略、Pod 选择器、Ingress/Egress 规则、策略规则、CiliumNetworkPolicy、Calico NetworkPolicy、零信任网络


一、NetworkPolicy 基础

1.1 什么是 NetworkPolicy

NetworkPolicy 是 K8s 原生资源,控制 Pod 之间以及 Pod 与外部之间的流量:

NetworkPolicy 核心模型:

NetworkPolicy spec: podSelector: {} ← 选择目标 Pod policyTypes: - Ingress ← 控制入方向 - Egress ← 控制出方向 ingress: ← 入规则 - from: - ipBlock: {...} - namespaceSelector: {...} - podSelector: {...} ports: - protocol: TCP port: 8080 egress: ← 出规则 - to: - ipBlock: {...} ports: [...]

1.2 流量控制模型

NetworkPolicy 的流量控制:

┌─ 入方向(Ingress)控制 ┌─ 出方向(Egress)控制
外部 ──► Pod-A ┌─ ipBlock Pod-A ──► 外部 ┌─ ipBlock ┌───────── ┤─ namespaceSelector ┌───────── ┤─ namespaceSelector ▼ ▼ 通过规则? → 允许/拒绝 通过规则? → 允许/拒绝 ┌──┴──┐ ┌──┴──┐ └─────┘ └─────┘ └─ podSelector 通过 └─ podSelector 通过
关键行为:
┌─ 未匹配任何 NetworkPolicy → 默认允许
├─ 匹配到一条 NetworkPolicy → 默认拒绝(白名单模式)
├─ 多条策略取并集 → 任一策略允许即放行
└─ 空 podSelector({})→ 匹配 Namespace 中所有 Pod

二、策略规则详解

2.1 podSelector —— 目标 Pod

podSelector 示例:

  # 选择 app=web 的 Pod
  podSelector:
    matchLabels:
      app: web

  # 选择所有 Pod(空选择器)
  podSelector: {}

  # 表达式选择
  podSelector:
    matchExpressions:
      - key: tier
        operator: In        # In/NotIn/Exists/DoesNotExist
        values:
          - frontend
          - backend

2.2 from/to —— 流量来源/目标

from/to 支持四种选择器:

  1. podSelector(同 Namespace)

    ┌─ 选择源 Namespace 内的 Pod └─ 示例: from: - podSelector: matchLabels: app: frontend

  2. namespaceSelector(跨 Namespace)

    ┌─ 选择目标 Namespace 的所有 Pod └─ 示例: from: - namespaceSelector: matchLabels: tenant: monitoring

  3. namespaceSelector + podSelector 组合

    ┌─ 同时匹配 Namespace 和 Pod └─ 示例: from: - namespaceSelector: {} podSelector: matchLabels: app: monitoring

  4. ipBlock(外部 IP)

    ┌─ 基于 CIDR 匹配(非 K8s 管理的 IP) └─ 示例: from: - ipBlock: cidr: 10.0.0.0/8 except: - 10.96.0.0/12 # 排除 Service CIDR

2.3 ports —— 端口与协议

ports 规则:

  ports:
    - protocol: TCP        # TCP/UDP/SCTP(默认 TCP)
      port: 80              # 单个端口
    - protocol: TCP
      port: 8080
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 3000-4000       # 端口范围(K8s 1.7+)

  注意:
    ┌─ 不指定 ports → 匹配所有端口
    ├─ 指定 ports → 只匹配指定端口
    └─ 多个 port 条目 → 任一匹配即放行

三、典型策略示例

3.1 默认拒绝所有

# 默认拒绝入站
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
    - Ingress

# 默认拒绝出站
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes:
    - Egress

3.2 三层架构访问控制

# web 层:仅允许 Ingress 访问 80 端口
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-policy
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 80
        - protocol: TCP
          port: 443
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: api
      ports:
        - protocol: TCP
          port: 8080

# api 层:仅允许 web 访问 8080,允许访问 db 3306
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-policy
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: db
      ports:
        - protocol: TCP
          port: 3306

# db 层:仅允许 api 访问 3306
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
spec:
  podSelector:
    matchLabels:
      app: db
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api
      ports:
        - protocol: TCP
          port: 3306

3.3 DNS 出口放行

# 所有 Pod 允许出站 DNS 查询
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

四、不同 CNI 的 NetworkPolicy 实现

CNI 方案 实现方式 性能 增强特性
Calico iptables/IPVS + Felix 中(策略多时 iptables 规则膨胀) 全局策略(GlobalNetworkPolicy)、HTTP 方法过滤
Cilium eBPF TC/XDP 高(策略匹配 O(1)) L7 策略、DNS 策略、Kafka/gRPC 策略
Antrea OVS OpenFlow 中高 ClusterNetworkPolicy、流量镜像
Weave Net iptables 基本 NettworkPolicy
Kube-router iptables/IPVS 基于 iptables 的 NetworkPolicy

4.1 Calico 增强策略

# Calico 全局网络策略(跨 Namespace)
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: deny-all-external
spec:
  selector: all()           # 匹配所有 Namespace 所有 Pod
  ingress:
    - action: Deny
      source:
        notSelector: "projectcalico.org/namespace == 'default'"
  egress:
    - action: Allow

# Calico 支持 HTTP 方法过滤
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: web-http-restrict
spec:
  selector: app == 'web'
  ingress:
    - action: Allow
      protocol: TCP
      destination:
        ports:
          - 80
      http:
        methods:
          - GET
          - POST
        paths:
          - "/api/v1/*"

4.2 Cilium 增强策略(L7)

# Cilium L7 HTTP 策略
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-http-policy
spec:
  endpointSelector:
    matchLabels:
      app: api
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: web
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
          rules:
            http:
              - method: GET
                path: "/api/v1/users/.*"
              - method: POST
                path: "/api/v1/orders"
              - method: "GET"
                path: "/healthz"

# Cilium DNS 策略
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: dns-egress-allow
spec:
  endpointSelector:
    matchLabels:
      app: web
  egress:
    - toEndpoints:
        - matchLabels:
            "k8s:io.kubernetes.pod.namespace": kube-system
            "k8s:k8s-app": kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
          rules:
            dns:
              - matchName: "*.example.com"

# Cilium 支持 Kafka/gRPC 等协议过滤
# Kafka 示例:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: kafka-policy
spec:
  endpointSelector:
    matchLabels:
      app: kafka-broker
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: producer
      toPorts:
        - ports:
            - port: "9092"
              protocol: TCP
          rules:
            kafka:
              - apiKey: "produce"
                topic: "orders"
              - apiKey: "fetch"
                topic: "orders"

五、策略管理最佳实践

5.1 策略设计原则

NetworkPolicy 设计原则:

1. 默认拒绝原则
   ┌─ 每个 Namespace 先部署默认拒绝策略
   ├─ 然后按需添加放行策略
   └─ 确保无策略的 Pod 默认隔离

2. 最小权限原则
   ┌─ 只放行业务所需的最小流量
   ├─ 精确到端口和协议
   ├─ 限制出口范围(仅允许必要的 CIDR)
   └─ 定期审计和收紧策略

3. 分层管理
   ┌─ 基础策略:DNS、监控、日志等公共策略
   ├─ 应用策略:业务 Pod 间访问
   └─ 安全策略:跨租户、外部访问

4. 命名规范
   ┌─ 策略命名:<app>-<direction>-<purpose>
   ├─ 标签命名统一(app/tier/tenant)
   └─ 使用注释描述策略用途

5.2 策略验证与故障排查

策略排查常用命令:

# 查看策略是否应用到 Pod
kubectl get networkpolicy -n <namespace>
kubectl describe networkpolicy <name> -n <namespace>

# 测试连通性(临时 Pod)
kubectl run test-pod --image=busybox -it --rm -- sh
  wget -qO- http://<target-svc>:8080

# Calico 策略审计
calicoctl get networkpolicy -n <namespace> -o yaml
calicoctl get workloadendpoints -n <namespace>

# Cilium 策略验证
cilium endpoint list
cilium endpoint get <id>
cilium policy trace -n <ns> -s <src-pod> -d <dst-pod>
cilium monitor -v           # 实时查看策略命中

# 常见的策略不通原因:
  1. 缺少默认拒绝 → 检查是否有策略生效
  2. DNS 不通 → 确保 egress 允许 DNS 53
  3. 跨 Namespace 缺漏 → 检查 namespaceSelector
  4. 端口不匹配 → 确认目标端口是否正确
  5. 策略顺序 → 多条策略是并集,不会互相覆盖

5.3 大规模策略优化

大规模集群策略优化:

1. 减少策略数量
   ┌─ 使用标签组合代替每条策略一个选择器
   ├─ 使用全局策略(GlobalNetworkPolicy)
   └─ 使用 Cilium 的 Clusterwide 策略

2. 预计算策略
   ┌─ Calico Felix 预计算策略 → iptables
   ├─ Cilium Identity 预计算 → eBPF Map
   └─ 避免运行时实时评估

3. 监控策略性能
   ┌─ 监控策略同步延迟
   ├─ 监控数据面规则数量
   ├─ 监控策略变更频率
   └─ 设置策略数量告警阈值

4. 策略即代码
   ┌─ 策略存储在 Git 仓库
   ├─ CI/CD 自动部署策略
   ├─ 变更前预检策略影响
   └─ 自动化策略合规检查

总结

关键点 说明
模型核心 podSelector 选择目标 + ingress/egress 规则
默认行为 未匹配策略 → 允许;匹配到策略 → 白名单模式
选择器类型 podSelector、namespaceSelector、ipBlock
CNI 差异 Cilium eBPF 最高效,Calico iptables 成熟稳定
增强策略 Cilium L7 HTTP/DNS/Kafka,Calico HTTP 方法过滤
最佳实践 默认拒绝 + 最小权限 + 策略即代码

思考

  1. NetworkPolicy 的默认行为是什么?为什么说它是白名单模式?
  2. 如何实现"只允许同 Namespace 的 Pod 互相访问"?
  3. 如何放行特定 Namespace 的所有 Pod 访问本 Namespace 的某个 Pod?
  4. ipBlock 的 except 字段有什么用途?
  5. Cilium L7 策略与 K8s 原生 NetworkPolicy 有什么区别?
  6. 如何验证一条 NetworkPolicy 是否生效?有哪些常用排错命令?

下篇预告:第281篇 - 华为 CloudFabric 数据中心方案简介,介绍华为数据中心网络方案的整体架构、核心组件和典型部署模型。