4. 多租户隔离模型:基于命名空间的租户隔离、基于标签的租户隔离、签名密钥的租户绑定策略
在多租户签名链路中,租户隔离是保障数据安全与操作审计的基石。Kubernetes 原生提供了两种隔离维度——命名空间(Namespace)与标签(Label),而签名链路在此基础上引入了密钥绑定策略,将加密身份与租户边界强关联。本节从三个层次拆解隔离模型的设计与实现。
4.1 基于命名空间的租户隔离
命名空间是 Kubernetes 最基础的租户边界。每个租户独占一个 Namespace,所有签名 Pod、ConfigMap、Secret 均部署在各自 Namespace 内,通过 RBAC 与 NetworkPolicy 实现网络与权限隔离。
| 隔离维度 | 实现方式 | 优势 | 局限 |
|---|---|---|---|
| 资源命名 | 每个租户一个 Namespace,资源名可重复 | 天然隔离,kube-apiserver 原生支持 | Namespace 数量过多时增加 etcd 压力 |
| 网络策略 | Namespace 级 NetworkPolicy 拒绝跨 Namespace 流量 | 零信任网络,默认拒绝 | 需手动维护策略规则 |
| RBAC | RoleBinding 绑定到 Namespace 内的 ServiceAccount | 细粒度权限控制 | 跨 Namespace 访问需额外 ClusterRole |
| 资源配额 | ResourceQuota 限制每个 Namespace 的 CPU/内存/Pod 数 | 防止租户资源抢占 | 不适用于存储类资源隔离 |
实践要点:签名链路的 Secret(签名密钥)必须与签名 Pod 部署在同一 Namespace,避免跨 Namespace 挂载 Secret 带来的安全风险。建议为每个租户创建独立的 ServiceAccount,并将签名 Pod 的
automountServiceAccountToken 设置为 false,减少 泄露面。
4.2 基于标签的租户隔离
当租户数量超过 Namespace 管理上限(通常建议 < 1000),或需要跨 Namespace 的逻辑分组时,标签选择器成为更灵活的隔离手段。通过为 Pod、Node、Secret 打上 tenant-id、env、tier 等标签,NetworkPolicy 和 Pod 反亲和性可以实现动态隔离。
标签隔离 vs 命名空间隔离:命名空间是物理边界,标签是逻辑边界。生产环境推荐组合使用:命名空间做粗粒度租户隔离,标签做细粒度签名链路角色隔离(如
role: signer、role: verifier)。
# 基于标签的 NetworkPolicy:只允许同标签的签名 Pod 互相通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant-signer-isolation
namespace: tenant-a
spec:
podSelector:
matchLabels:
tenant: a
role: signer
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
tenant: a
role: signer
egress:
- to:
- podSelector:
matchLabels:
tenant: a
role: signer
避坑:标签隔离依赖 NetworkPolicy 的
podSelector,但 NetworkPolicy 默认是允许所有,必须显式声明 policyTypes: [Ingress, Egress] 并添加拒绝规则,否则隔离失效。建议在集群层面部署默认拒绝的全局 NetworkPolicy。
4.3 签名密钥的租户绑定策略
签名密钥是租户身份的加密锚点。密钥绑定策略确保:一个租户的签名密钥不能被其他租户读取或使用。绑定策略分为三个层级:
- Namespace 绑定:密钥 Secret 与签名 Pod 同 Namespace,RBAC 限制跨 Namespace 读取。
- 标签绑定:密钥 Secret 打上
tenant-id标签,通过fieldRef或envFrom注入 Pod 时校验标签一致性。 - 签名链路绑定:在签名请求(SigningRequest)中嵌入租户 ID,签名服务验证请求中的租户 ID 与密钥的
tenant注解是否匹配。
4.4 隔离模型对比与选型
| 隔离模型 | 粒度 | 管理成本 | 安全强度 | 适用场景 |
|---|---|---|---|---|
| 命名空间隔离 | 粗粒度 | 低 | 中 | 租户数量 < 500,资源边界清晰 |
| 标签隔离 | 细粒度 | 中 | 中高 | 跨 Namespace 逻辑分组,动态扩缩 |
| 签名密钥绑定 | 加密级 | 高 | 高 | 签名链路核心密钥,防内部泄露 |
最佳实践:在签名链路中,始终采用命名空间 + 签名密钥绑定的组合策略。命名空间提供资源级隔离,密钥绑定提供加密级身份校验。标签隔离作为补充,用于签名 Pod 的灰度发布或金丝雀部署场景。
4.5 签名密钥绑定策略的代码实现
以下是一个签名密钥绑定策略的校验逻辑示例,在签名服务启动时加载:
# 签名密钥绑定校验伪代码
def validate_key_binding(signing_request, secret):
# 1. 提取请求中的租户 ID
request_tenant = signing_request.metadata.annotations.get("tenant-id")
if not request_tenant:
raise ValidationError("SigningRequest 缺少 tenant-id 注解")
# 2. 提取 Secret 中的租户 ID
secret_tenant = secret.metadata.annotations.get("tenant-id")
if not secret_tenant:
raise ValidationError("Secret 缺少 tenant-id 注解")
# 3. 校验租户 ID 是否匹配
if request_tenant != secret_tenant:
raise ValidationError(
f"租户绑定失败: 请求租户 {request_tenant} != 密钥租户 {secret_tenant}"
)
# 4. 校验 Namespace 是否一致(可选增强)
if signing_request.metadata.namespace != secret.metadata.namespace:
raise ValidationError("跨 Namespace 签名请求被拒绝")
return True
增强建议:在签名服务的 Admission Webhook 中注入上述校验逻辑,确保所有签名请求在进入控制器前完成租户绑定校验。同时,将校验日志输出到租户独立的审计日志流,便于事后追溯。