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 | 允许的出站端口与协议 |
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 实现命名空间隔离与跨命名空间通信控制的完整流量路径。
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:策略合规性检查工具,防止配置漂移。