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 |
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
# 不定义任何规则,拒绝所有入站和出站流量
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 工具访问集群内服务 |
ipBlock 直接暴露 Pod 到外部网络,除非有明确的业务需求。
4.4 NetworkPolicy 流量控制流程
下图展示了 NetworkPolicy 在 Pod 流量控制中的完整工作流程,从流量发起、策略匹配到最终放行或拒绝的决策路径。
4.5 多租户场景下的 NetworkPolicy 设计模式
在多租户集群中,NetworkPolicy 的设计需要兼顾隔离性和可用性。以下是三种常见的设计模式:
- 完全隔离模式:每个租户命名空间应用默认拒绝所有策略,然后通过命名空间选择器开放必要的跨租户通信。适用于金融、医疗等强合规场景。
- 共享服务模式:为共享服务命名空间(如监控、日志、DNS)创建允许策略,使所有租户可以访问这些基础服务,但租户之间保持隔离。
- 分层访问模式:根据租户等级(如免费、付费、企业)设置不同的网络策略,高级别租户拥有更灵活的通信权限。
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 会合并所有策略,只要有一个策略允许则放行;建议使用标签统一管理 |