4. 租户隔离蓝图设计:基于Cilium的NetworkPolicy与基于eBPF的租户标识(Security ID)映射

在灰度批次与多租户共存的网络观测场景中,隔离策略的落地依赖于两层核心机制:Cilium NetworkPolicy 提供声明式的准入控制规则,而 eBPF Security ID 则在数据平面为每个网络包打上不可篡改的租户身份标签。本章详细阐述两者的映射关系与蓝图设计。

4.1 双层隔离模型:策略层与标识层

租户隔离不能仅依赖单一维度。Cilium 将 Kubernetes NetworkPolicy 的能力下沉到 eBPF 层,同时引入 Security Identity (SecID) 作为内核级的租户标识。其核心架构分为两层:

  • 策略层(Cilium NetworkPolicy):基于标签选择器(Label Selector)定义允许/拒绝的通信规则,支持 L3/L4/L7 策略。
  • 标识层(eBPF Security ID):每个 Kubernetes 端点(Pod)在 Cilium Agent 启动时被分配一个 24-bit 的 Security ID,该 ID 与端点的标签集合(Label Set)进行哈希绑定,并注入到 eBPF Map 中。
关键设计原则: 策略规则中引用的标签选择器,在 eBPF 数据路径中被转换为对 Security ID 的匹配。这意味着策略的生效不依赖 IP 地址,而是依赖身份标识,从而避免 IP 漂移导致的策略失效。

4.2 Security ID 的生成与映射机制

Security ID 的生成遵循确定性哈希算法,确保相同标签集合的端点获得相同的 ID。映射关系存储在 Cilium 的全局 Identity Map 中,该 Map 由 Cilium Operator 维护,并通过 BPF Map 同步到每个节点。

组件 职责 数据存储
Cilium Operator 全局 Identity 分配与冲突检测 etcd / CRD (ciliumidentities)
Cilium Agent (本地) 本地 Identity 缓存与 BPF Map 更新 BPF_MAP_TYPE_HASH (cilium_identity)
eBPF 程序 (TC/XDP) 运行时根据源/目的 IP 查找 Identity BPF_MAP_TYPE_LPM_TRIE (cilium_ipcache)

映射流程如下:

  1. Pod 创建时,Kubernetes API Server 将 Pod 标签推送至 Cilium Operator。
  2. Operator 计算标签哈希,分配或复用 Security ID,并写入 CRD。
  3. Agent 监听 CRD 变化,将 Pod IP → Security ID 的映射写入本地的 cilium_ipcache BPF Map。
  4. eBPF 程序在数据包处理时,通过 bpf_map_lookup_elem 获取源/目的 Security ID,并与策略规则中的 ID 列表进行比对。

4.3 NetworkPolicy 到 Security ID 的编译过程

Cilium Agent 在接收到 NetworkPolicy 资源后,会执行一次策略编译(Policy Compilation),将基于标签的规则转换为基于 Security ID 的规则集合。

// 伪代码:策略编译核心逻辑
func compilePolicy(rule NetworkPolicyRule, identityCache map[LabelSet]uint32) []PolicyEntry {
    var entries []PolicyEntry
    for _, selector := range rule.ToEndpoints {
        // 将标签选择器匹配到的所有 Security ID 展开
        matchedIDs := identityCache.Match(selector)
        for _, id := range matchedIDs {
            entries = append(entries, PolicyEntry{
                RemoteIdentity: id,
                Ports:          rule.ToPorts,
                Action:         rule.Action,
            })
        }
    }
    return entries
}

编译后的策略条目被写入 BPF Map(cilium_policy),eBPF 程序在运行时直接查询该 Map,无需再次进行标签匹配,极大提升了数据路径的性能。

4.4 租户隔离蓝图中的映射关系

在灰度批次场景中,每个租户(Tenant)可能对应多个命名空间(Namespace)或一组特定的标签。蓝图设计需要建立 Tenant → Label Set → Security ID 的映射链。

实践建议: 为每个租户定义一个唯一的租户标签,例如 tenant=alpha、tenant=beta。Cilium 会自动为每个标签组合生成独立的 Security ID。在 NetworkPolicy 中,直接引用该标签即可实现租户级别的隔离。

以下是一个典型的租户隔离策略示例:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: tenant-isolation
spec:
  endpointSelector:
    matchLabels:
      tenant: alpha
  ingress:
  - fromEndpoints:
    - matchLabels:
        tenant: alpha
  egress:
  - toEndpoints:
    - matchLabels:
        tenant: alpha

该策略编译后,eBPF 程序只会允许源 Security ID 属于 tenant=alpha 的流量进入,其他租户的流量即使 IP 可达,也会被直接丢弃。

4.5 映射关系可视化:从标签到 Security ID 的转换

下图展示了从 Pod 标签到 Security ID,再到策略匹配的完整映射链路。

标签 → Security ID → 策略匹配映射流程 Pod A tenant=alpha env=gray Pod B tenant=alpha env=stable Identity Map 标签哈希 → Security ID {tenant=alpha,env=gray} → ID: 1001 {tenant=alpha,env=stable} → ID: 1002 策略 BPF Map 允许 ID: 1001 允许 ID: 1002 (tenant=alpha) 拒绝其他 ID 映射说明: 1. Pod 标签组合决定 Security ID,相同标签组合共享同一 ID。 2. NetworkPolicy 编译后,标签选择器被展开为具体的 Security ID 列表。 3. eBPF 程序在数据路径直接匹配 ID,无需运行时解析标签。

4.6 灰度批次中的租户标识冲突与规避

在灰度批次场景中,同一租户的不同批次(如 stable 与 gray)可能拥有不同的标签组合,导致生成不同的 Security ID。这要求策略设计必须考虑批次的包容性。

常见陷阱: 如果灰度批次使用了独立的标签(如 batch=gray-v2),而 NetworkPolicy 只引用了 tenant=alpha,则灰度批次与稳定批次之间的流量会被策略允许,因为两者都属于同一租户。但如果策略同时要求 env=stable,则灰度批次将被隔离。务必根据实际隔离粒度设计标签选择器。

下表总结了不同标签设计下的隔离效果:

标签设计 Security ID 数量 隔离粒度 灰度批次影响
仅使用 tenant 标签 1 个 ID / 租户 租户级 灰度与稳定批次互通
使用 tenant + env 标签 N 个 ID / 租户 环境级 灰度与稳定批次隔离
使用 tenant + batch 标签 M 个 ID / 租户 批次级 每个批次完全隔离

4.7 蓝图设计总结

租户隔离蓝图的成功实施依赖于对 Security ID 映射机制的深入理解。核心要点包括:

  • 标签即身份:Security ID 是标签集合的哈希摘要,标签设计直接决定隔离边界。
  • 策略编译:NetworkPolicy 在控制平面被编译为基于 ID 的规则,数据平面只做整数匹配。
  • 灰度兼容:在灰度批次中,通过调整标签选择器的范围,可以实现从完全隔离到部分互通的灵活控制。

下一层设计将聚焦于如何利用 eBPF 的观测能力,实时捕获这些 Security ID 的匹配情况,并生成可视化的拓扑留痕数据。