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 可以解析服务名,但无法访问外部网络或集群内其他非授权服务。

租户隔离蓝图核心组件关系图 租户命名空间内部组件与流量路径 租户命名空间 (tenant-alpha) 默认拒绝所有流量 Ingress + Egress 阻断 允许 DNS 流量 UDP/TCP 53 → kube-dns 应用 Pod (app-frontend) 阻断所有入站/出站 仅放行 DNS 查询 kube-system/kube-dns UDP/TCP 53 允许出站 DNS 拒绝策略 允许策略 租户 Pod 集群 DNS

4.5 策略部署顺序与依赖关系

在自动化部署租户命名空间时,策略的创建顺序至关重要。错误的顺序可能导致短暂的流量泄露或服务中断。

  1. 创建命名空间:先创建 Namespace 对象,并打上正确的标签。
  2. 部署默认拒绝策略:立即应用 default-deny-all,确保从这一刻起,所有新 Pod 默认无网络访问权限。
  3. 部署允许 DNS 策略:在拒绝策略之后立即部署,保证 Pod 启动后能正常解析 DNS。
  4. 部署租户特定策略:最后根据租户需求,添加允许特定入站/出站流量的策略(如允许来自 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 日志

通过以上三个核心组件的组合,我们为每个租户构建了一个“默认安全、按需开放”的网络环境。下一层级的策略将在此基础上,进一步实现租户间的服务互访或暴露到集群外部。