必须用Calico或Cilium替换Flannel以启用NetworkPolicy;为租户命名空间打标后,先部署default-deny-all策略,再配置允许同租户通信和必要出站(如DNS),最后通过namespaceSelector严格限制跨租户访问。

在多租户Kubernetes集群中,必须阻止不同租户命名空间下的Pod互相访问,否则一个租户的漏洞可能直接导致其他租户数据库被横向扫描或接管,这种内网无防护状态已在多个生产事故中验证为高危风险。
确认CNI插件已启用NetworkPolicy支持
执行 kubectl get crd networkpolicies.networking.k8s.io,若返回资源定义则API可用;但真正生效依赖底层CNI。Calico、Cilium、Weave Net等支持该功能,Flannel默认不支持且无法开启——【若当前使用Flannel,必须先替换为Calico或Cilium,否则所有NetworkPolicy配置均无效】。
验证Calico是否就绪:运行 kubectl get pods -n kube-system | grep calico,确保calico-node与calico-kube-controllers均为Running状态。
为租户命名空间打标并创建基础隔离策略
给每个租户命名空间添加唯一标签,例如:kubectl label namespace tenant-a tenant-id=a。这一步不可跳过,后续所有跨命名空间规则都依赖此标签匹配。
在tenant-a命名空间下创建default-deny-all.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
应用后,该命名空间内所有Pod将无法收发任何流量,包括DNS解析和自身健康检查探针——【此时服务会立即中断,必须紧接着配置最小必要放行规则】。
允许租户内部通信与必要出站
第一步:放行同一命名空间内Pod互访(Intra-namespace)
创建 intra-tenant.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-intra-tenant
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
tenant-id: a
podSelector: {}
第二步:允许访问共享DNS与核心服务(如kube-dns、shared-db)
假设共享服务部署在shared-services命名空间,且打了label service-type: dns,则追加一条Egress规则:
egress:
- to:
- namespaceSelector:
matchLabels:
name: shared-services
podSelector:
matchLabels:
service-type: dns
ports:
- protocol: UDP
port: 53
严格限制跨租户访问
方法一:显式禁止特定租户间通信
在tenant-a的NetworkPolicy中加入Ingress拒绝规则(注意:NetworkPolicy本身无deny语义,需用“不匹配+default deny”实现):
仅允许来自tenant-b中带allowed-role: api-consumer标签的Pod访问tenant-a的80端口,其余全部阻断:
ingress:
- from:
- namespaceSelector:
matchLabels:
tenant-id: b
podSelector:
matchLabels:
allowed-role: api-consumer
ports:
- protocol: TCP
port: 80
方法二:全局禁止所有跨租户Ingress(推荐用于金融/政企场景)
在每个租户命名空间单独部署一条策略,只允许本namespace内流量进入:
ingress:
- from:
- namespaceSelector:
matchLabels:
tenant-id: a
podSelector: {}
这条规则配合开头的default-deny-all策略,即可彻底封死租户a接收来自tenant-b、tenant-c等任何外部命名空间的请求。
验证隔离效果
① 进入tenant-b中的busybox Pod:kubectl exec -it -n tenant-b busybox -- sh
② 尝试telnet tenant-a中nginx Service的ClusterIP:telnet 192.168.3.141 80
③ 若连接超时或拒绝,说明隔离生效;若成功建立连接,则检查tenant-a的NetworkPolicy是否遗漏了namespaceSelector或podSelector为空导致未匹配到任何Pod。
④ 同时验证tenant-a内Pod能否正常解析DNS:nslookup kubernetes.default.svc.cluster.local,失败则检查Egress规则中DNS端口与协议是否写错。


















