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 签名密钥的租户绑定策略

签名密钥是租户身份的加密锚点。密钥绑定策略确保:一个租户的签名密钥不能被其他租户读取或使用。绑定策略分为三个层级:

  1. Namespace 绑定:密钥 Secret 与签名 Pod 同 Namespace,RBAC 限制跨 Namespace 读取。
  2. 标签绑定:密钥 Secret 打上 tenant-id 标签,通过 fieldRef 或 envFrom 注入 Pod 时校验标签一致性。
  3. 签名链路绑定:在签名请求(SigningRequest)中嵌入租户 ID,签名服务验证请求中的租户 ID 与密钥的 tenant 注解是否匹配。
签名密钥租户绑定策略架构 签名密钥租户绑定策略架构 层级1:Namespace 绑定 Secret 与 Pod 同 Namespace RBAC RoleBinding 限制跨 Namespace NetworkPolicy 拒绝跨 Namespace 流量 基础隔离,默认推荐 层级2:标签绑定 Secret 打 tenant-id 标签 Pod 通过 labelSelector 引用 NetworkPolicy 按标签过滤 灵活分组,跨 Namespace 可用 层级3:签名链路绑定 SigningRequest 嵌入 tenantID 签名服务校验 tenant 注解 密钥与请求租户 ID 匹配 加密级绑定,防密钥滥用 绑定策略组合建议 生产环境:层级1(Namespace)+ 层级3(签名链路绑定) 跨集群场景:层级2(标签)+ 层级3(签名链路绑定) 禁止单独使用层级1,必须叠加层级3防止密钥水平扩散

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 中注入上述校验逻辑,确保所有签名请求在进入控制器前完成租户绑定校验。同时,将校验日志输出到租户独立的审计日志流,便于事后追溯。