4. 蓝图核心组件:租户命名空间模板、默认拒绝所有流量策略、允许 DNS 流量策略
多租户隔离集群的基石在于“先隔离,再放行”。本章聚焦蓝图中的三个核心组件:租户命名空间模板、默认拒绝所有流量策略以及允许 DNS 流量策略。这三者共同构成了租户网络的初始安全边界,确保任何新创建的租户空间在默认情况下都是封闭且安全的。
4.1 租户命名空间模板
为了确保每个租户环境的一致性和可审计性,我们使用 Namespace Template 来标准化租户命名空间的创建过程。该模板不仅定义了命名空间的元数据,还通过 Labels 和 Annotations 为后续的 NetworkPolicy 选择器提供匹配依据。
模板设计原则:
- 标签驱动:每个租户命名空间必须包含
tenant: <tenant-name>和scope: tenant标签,用于策略匹配。 - 资源配额:预置 ResourceQuota 和 LimitRange,防止单个租户耗尽集群资源。
- 不可变基础:模板中的 NetworkPolicy 基线策略(默认拒绝 + 允许 DNS)在命名空间创建时自动部署,且不允许租户自行删除。
以下是一个典型的租户命名空间模板 YAML 示例:
apiVersion: v1
kind: Namespace
metadata:
name: tenant-alpha
labels:
tenant: alpha
scope: tenant
environment: production
annotations:
scheduler.alpha.kubernetes.io/node-selector: "node-type=tenant"
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: tenant-quota
namespace: tenant-alpha
spec:
hard:
requests.cpu: "8"
requests.memory: "16Gi"
limits.cpu: "16"
limits.memory: "32Gi"
persistentvolumeclaims: "10"
services.nodeports: "0" # 禁止 NodePort
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: tenant-alpha
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: tenant-alpha
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
生产建议:使用 GitOps 工具(如 ArgoCD)或 Operator 来管理模板的生命周期。当模板更新时,自动同步到所有已存在的租户命名空间,但需谨慎处理对现有策略的覆盖。
4.2 默认拒绝所有流量策略
该策略是租户隔离的“总闸”。它通过一个空的 podSelector: {} 匹配命名空间内的所有 Pod,并声明 policyTypes: [Ingress, Egress],从而拒绝所有未显式允许的入站和出站流量。
| 策略属性 | 配置值 | 说明 |
|---|---|---|
| podSelector | {} |
匹配命名空间内所有 Pod |
| policyTypes | [Ingress, Egress] |
同时阻断入站和出站流量 |
| Ingress 规则 | 无 | 拒绝所有入站连接 |
| Egress 规则 | 无 | 拒绝所有出站连接 |
关键陷阱:如果只设置
policyTypes: [Ingress],则出站流量不会被阻断。必须显式声明 Egress 才能实现完全隔离。此外,该策略必须优先于其他允许策略部署,否则在策略生效窗口期可能存在流量泄露。
4.3 允许 DNS 流量策略
在默认拒绝所有流量的基础上,我们需要为 Pod 提供最基本的网络能力——DNS 解析。该策略专门放行从租户命名空间内任何 Pod 到集群 DNS 服务(通常位于 kube-system 命名空间)的 UDP/TCP 53 端口流量。
策略关键点解析:
- 目标选择器:使用
namespaceSelector匹配kube-system命名空间,并结合podSelector匹配k8s-app: kube-dns标签的 Pod,确保流量只流向 DNS 服务,而非 kube-system 内的其他组件。 - 端口限制:仅开放 UDP 53 和 TCP 53,防止 DNS 端口被用于隧道攻击。
- 协议指定:明确
protocol: UDP和protocol: TCP,避免因协议不匹配导致解析失败。
# 允许 DNS 策略核心片段
spec:
podSelector: {} # 作用于本命名空间所有 Pod
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
4.4 组件关系与流量路径
下图展示了这三个组件在租户命名空间内的协同工作方式。默认拒绝策略形成“铜墙铁壁”,而 DNS 策略则开了一个“小窗”,确保 Pod 可以解析服务名,但无法访问外部网络或集群内其他非授权服务。
4.5 策略部署顺序与依赖关系
在自动化部署租户命名空间时,策略的创建顺序至关重要。错误的顺序可能导致短暂的流量泄露或服务中断。
- 创建命名空间:先创建 Namespace 对象,并打上正确的标签。
- 部署默认拒绝策略:立即应用
default-deny-all,确保从这一刻起,所有新 Pod 默认无网络访问权限。 - 部署允许 DNS 策略:在拒绝策略之后立即部署,保证 Pod 启动后能正常解析 DNS。
- 部署租户特定策略:最后根据租户需求,添加允许特定入站/出站流量的策略(如允许来自 Ingress Controller 的流量)。
验证命令:
# 查看租户命名空间内的所有 NetworkPolicy
kubectl get networkpolicy -n tenant-alpha
# 模拟测试 Pod 的 DNS 解析能力
kubectl run -n tenant-alpha test-pod --image=busybox --rm -it --restart=Never -- nslookup kubernetes.default.svc.cluster.local
4.6 常见故障模式与排查思路
| 故障现象 | 可能原因 | 排查命令 |
|---|---|---|
| Pod 无法解析 DNS | 允许 DNS 策略未生效;DNS Pod 标签不匹配;策略中 namespaceSelector 错误 | kubectl describe networkpolicy allow-dns -n tenant-alpha |
| Pod 无法访问同命名空间服务 | 默认拒绝策略阻断了所有入站;缺少允许同命名空间流量的策略 | kubectl exec -n tenant-alpha <pod> -- curl -v <service> |
| 策略未生效 | CNI 插件不支持 NetworkPolicy;策略中 podSelector 写错 | kubectl get networkpolicy -A 检查是否存在;查看 CNI 日志 |
通过以上三个核心组件的组合,我们为每个租户构建了一个“默认安全、按需开放”的网络环境。下一层级的策略将在此基础上,进一步实现租户间的服务互访或暴露到集群外部。