4. 多租户模型设计:命名空间(Namespace)作为租户边界,RBAC与网络策略的协同
在多租户 Kubernetes 集群中,命名空间(Namespace)是最基础、最自然的租户隔离边界。每个租户独占一个或多个命名空间,所有工作负载、配置和网络资源都在该边界内运行。然而,仅靠命名空间无法实现真正的安全隔离——必须将 RBAC(基于角色的访问控制)与 NetworkPolicy(网络策略)深度协同,才能构建从“管理平面”到“数据平面”的完整租户隔离体系。
4.1 命名空间作为租户边界的核心原则
将命名空间视为租户边界时,需遵循以下设计原则:
| 原则 | 说明 | 实施要点 |
|---|---|---|
| 独占性 | 每个租户至少拥有一个独立命名空间,不允许跨租户共享 | 通过准入控制器(如 OPA/NAC)强制命名空间与租户 ID 绑定 |
| 资源配额 | 为每个命名空间设置 ResourceQuota 和 LimitRange | 防止单个租户耗尽集群资源,保障公平调度 |
| 网络边界 | 默认拒绝跨命名空间流量,仅显式允许的通信可通过 | 配合 NetworkPolicy 实现“白名单”模式 |
| 管理隔离 | 租户管理员只能操作自己命名空间内的资源 | 通过 RBAC Role/ClusterRole 精确授权 |
关键设计决策: 对于大型租户,建议采用“一个租户多个命名空间”模式(如 dev/staging/prod 环境分离),但所有命名空间必须共享统一的租户标签(如
tenant: acme-corp),以便网络策略和审计日志的聚合管理。
4.2 RBAC 与 NetworkPolicy 的协同模型
RBAC 控制“谁能做什么”(管理平面),NetworkPolicy 控制“哪个 Pod 能与哪个 Pod 通信”(数据平面)。两者协同才能形成完整的租户隔离矩阵:
协同口诀: RBAC 管人,NetworkPolicy 管网。人进不去命名空间,网就无需考虑他的流量;网不通,人即使有权限也无法访问服务。
4.2.1 协同层次结构
- 第一层:RBAC 命名空间准入 — 租户管理员只能看到和操作自己命名空间内的 Deployment、Service、Pod 等资源。
- 第二层:NetworkPolicy 默认拒绝 — 在租户命名空间内创建默认拒绝所有入站/出站流量的策略,防止 Pod 被意外暴露。
- 第三层:显式允许策略 — 根据业务需求,通过 NetworkPolicy 开放特定端口和标签选择器,允许跨命名空间通信(如共享数据库服务)。
- 第四层:审计与监控 — 结合 RBAC 审计日志和网络流量日志,验证隔离策略是否被绕过。
4.3 典型多租户网络策略设计模式
以下 SVG 图展示了三个租户(Tenant-A、Tenant-B、Tenant-C)在共享集群中的网络隔离架构,以及 RBAC 与 NetworkPolicy 的协同作用点:
4.4 RBAC 与 NetworkPolicy 协同配置示例
以下是一个完整的 Helm Chart 模板片段,展示如何在部署时同时创建 RBAC 角色和网络策略:
{{- /* templates/tenant-isolation.yaml */ -}}
{{- range .Values.tenants }}
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .name }}
labels:
tenant: {{ .name }}
environment: {{ .environment | default "production" }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .name }}-admin
namespace: {{ .name }}
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ .name }}-admin-binding
namespace: {{ .name }}
subjects:
- kind: User
name: {{ .adminUser }}
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: {{ .name }}-admin
apiGroup: rbac.authorization.k8s.io
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: {{ .name }}
spec:
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-intra-tenant
namespace: {{ .name }}
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
tenant: {{ .name }}
policyTypes:
- Ingress
{{- end }}
常见陷阱: 仅创建
default-deny-ingress 策略而不创建出站策略,可能导致 Pod 无法访问集群 DNS 或监控 Agent。建议同时创建允许出站到 kube-system 命名空间 DNS 服务的策略,或使用 default-deny-egress 配合显式允许。
4.5 多租户网络策略命中与隔离验证矩阵
下表总结了不同场景下 RBAC 与 NetworkPolicy 的协同效果:
| 场景 | RBAC 权限 | NetworkPolicy 规则 | 实际结果 |
|---|---|---|---|
| 租户 A 管理员查看租户 B 的 Pod | 无权限(Role 限定命名空间) | 不相关 | ❌ API 返回 403 Forbidden |
| 租户 A 的 frontend 访问租户 B 的 api | 有权限(Pod 可出站) | 租户 B 默认拒绝入站 | ❌ 网络层丢弃,连接超时 |
| 租户 A 的 backend 访问租户 C 的 cache | 有权限 | 租户 C 显式允许(namespaceSelector) | ✅ 连接成功,端口 6379 |
| 租户 C 的 app 访问集群外部数据库 | 有权限 | 出站策略允许 egress 到特定 CIDR | ✅ 连接成功 |
| 恶意用户尝试创建跨租户 NetworkPolicy | 无权限(ClusterRole 限制) | 不相关 | ❌ API 拒绝,审计日志记录 |
4.6 最佳实践与避坑指南
- 标签标准化: 所有命名空间必须包含统一的租户标签(如
tenant-id),NetworkPolicy 的namespaceSelector依赖此标签进行跨命名空间授权。 - 默认拒绝策略先行: 在创建任何允许策略之前,先部署
default-deny-ingress和default-deny-egress,避免策略生效前的窗口期暴露。 - RBAC 最小权限: 租户管理员角色只授予其命名空间内的 NetworkPolicy 管理权限,禁止修改集群级别的 ClusterNetworkPolicy(如果使用 Cilium 等 CNI)。
- 审计与告警: 开启 Kubernetes 审计日志,监控 NetworkPolicy 的创建/更新/删除操作,并设置告警规则检测非预期的策略变更。
- Helm 模板化: 将租户配置抽象为
values.yaml中的列表,通过range循环生成命名空间、RBAC 和 NetworkPolicy,确保一致性并减少手工错误。
生产级建议: 对于超过 50 个租户的集群,考虑使用 vCluster 或 Kiosk 等虚拟集群方案,将每个租户的 API Server 隔离,从根本上避免 RBAC 配置错误导致的越权风险。此时 NetworkPolicy 仍作为第二层网络隔离防线。