土法炼钢 · 系统与基础设施

【Cilium / eBPF】Endpoint 与 Identity:数字身份、标签选择与生命周期

文章导航

分类入口
kubernetesnetwork
标签入口
#cilium#ebpf#identity#endpoint#networkpolicy#labels#reserved-identity#v1.20.0

目录

第 1 篇 把排障收束到五轴;本篇钉 Identity 轴。读者常见误区有两个:一是把 Cilium「基于标签的策略」理解成运行时仍在匹配 Pod IP;二是把滚动更新时的偶发拒绝一律写成「NetworkPolicy 写错了」。真正要钉死的是:Endpoint 是节点上的网络实体,Identity 是策略在 BPF 里看到的数字键;标签变更会迫使身份重解析,并可能打开短暂的拒绝或放行窗口。

本篇在系列中的位置

篇目 核心内容
第 1 篇 · 数据面全景 五轴坐标系
第 2 篇 · Endpoint 与 Identity 数字身份、标签选择、生命周期与变更窗口
第 3 篇 · BPF 挂载 TC/XDP/cgroup 角色
系列目录 全部篇目

版本锚定:Cilium v1.20.0docs.cilium.io/en/v1.20/;源码 tag v1.20.0,重点 pkg/identity/)。机制叙述对齐官方 Terminology 与 Identity-Based 文档。无真实集群则不粘贴伪造 cilium endpoint / identity 列表输出。


一、Endpoint:节点上的网络实体,不是「又一个 Pod 别名」

Cilium Terminology(v1.20)把 Endpoint 定义为:共享同一地址、由 Cilium 在网络上代表的一组应用容器。Kubernetes 下典型就是一个 Pod——多容器共享网络命名空间与 IP,因此共享一个 Endpoint。

关键可核对点:

概念 作用域 用途
Endpoint ID 单节点内唯一 agent 本地管理、程序/map 绑定
Pod IP / 地址 集群编址 路由与连接;不是策略的稳定主键
Labels(带 source 前缀) 元数据 导出 Identity;如 k8s:app=frontend

标签带 source 前缀以避免冲突:k8s: 来自 Kubernetes,reserved: 为保留身份,未指定源时选择器可用 any: 匹配任意源(Terminology · Label Source)。策略选择器匹配的是键值对,不是「长得像」的字符串;my.corp.foo 不会匹配到 my.corp.foo=bar 这类带值标签——文档写得很硬。

Endpoint 的生命周期由编排事件驱动:Pod 创建 → Cilium 创建 Endpoint → 解析 Identity → 把身份与策略写入数据面;Pod 删除则回收。Endpoint ID 不会也不应被当成跨节点稳定标识——跨节点协调的是 Identity 与 IP→Identity 缓存(ipcache),不是本地 endpoint id。

相对 k8s-network/13 的产品叙述,本篇收紧一句:产品文解释「为什么用 Identity」;这里解释 Identity 相对 Endpoint / IP 的职责切分,以便后面 map 与包路径有主语。


二、Numeric Identity:策略匹配的稳定键

身份从哪来

官方 Identity-Based 文档把问题钉成:若策略用 IP 列表表达「role=frontendrole=backend」,则每个 backend 所在节点都必须维护全部 frontend IP;frontend 扩缩容会迫使大量节点更新过滤器,且新 Pod 启动可能必须等待规则传播完成,否则误丢包。

Cilium 的回答是:把安全与编址拆开。身份由(安全相关)标签集合导出,并分配集群范围唯一的数字 ID;同标签集合的 Pod 共享同一 Identity。新增同身份 Pod 时,主要工作是解析已有身份并更新本地解析缓存,而不是让所有 backend 节点重写 IP 列表。

数据面后果直接写进第 1 篇的不变量:BPF policy map 的键空间是 identity + port + protocol(及方向),不是「每个源 IP 一条规则」。源码侧 pkg/maps/policymap 把 endpoint 专用 map 命名为 cilium_policy_v3_*,注释写明 v3 对应 policy identity aggregation 的语义变更——版本升级时 map 名变更用于强制重建,避免旧语义条目残留。

安全相关标签

并非 Pod 上每一个标签都进入身份。Terminology 要求配置有意义的标签前缀;历史默认叙事以 id. 前缀为例,Kubernetes 环境中实际还会纳入一组 agent 配置的相关标签(具体前缀以安装配置为准)。时间戳、构建号一类元数据若误入安全相关集合,会造成身份爆炸:每个唯一标签组合一个 Identity,policy map 与分配存储压力上升。

工程判断(与文档一致的方向):把「会改变信任边界的标签」留在安全相关集合,把「仅用于运维检索的标签」排除在外。排障时若看到 Identity 数量远高于「应用角色数」,先查标签基数,再查策略复杂度。

保留身份与 well-known 身份

文档给出的保留身份(节选)是排障高频锚点:

Identity Numeric ID 含义(文档口径)
reserved:unknown 0 未能导出身份
reserved:host 1 本地主机相关流量
reserved:world 2 集群外端点
reserved:unmanaged 3 非 Cilium 管理端点
reserved:health 4 cilium-health
reserved:init 5 身份尚未解析完成的引导阶段
reserved:remote-node 6 远程节点主机集合
reserved:kube-apiserver 7 kube-apiserver 后端所在
reserved:ingress 8 Ingress 代理源地址侧

Well-known 身份(如 kube-dns / CoreDNS / cilium-operator 的固定数字 ID)用于不依赖外部分配存储即可引导关键系统流量——文档明确这是为了在依赖尚未就绪时仍能强制策略连通。源码侧 pkg/identity 将保留常量与 scope 位(全局 / 本地 CIDR / remote-node)编码在 numeric identity 的高位语义中;集群 ID 位宽与 ClusterMesh 相关,展开见后续第 11 篇。

reserved:init 尤其重要:当创建 Endpoint 时元数据尚不齐,文档写明可分配 init 身份。策略若未显式允许 init,引导窗口内流量可能被拒绝——这是设计上的过渡态,不是「随机丢包」。


三、生命周期:分配、共享、变更

Pod start / label sync
  → create Endpoint (node-local id)
  → select security-relevant labels
  → allocate or resolve Numeric Identity (cluster-wide)
  → populate ipcache / policy maps / endpoint programs
  → ready for L3/L4 enforcement

集群内协调:Terminology 描述通过分布式键值存储做「若未见过该标签集合则分配新 ID」的原子操作;现代部署亦常见 CRD 分配模式(以安装时 identity-allocation-mode 等配置为准)。无论存储后端是 kvstore 还是 CRD,语义目标相同:同标签集合 → 同一数字身份;跨节点共享。

共享身份的收益与代价成对出现:

相对 IP 策略,Identity 消除的是「IP churn → 全量规则重写」这条放大路径;它不消除「标签集合变化 → 身份必须重解析」本身。下一节专门钉变更窗口。


四、标签变更:短暂拒绝与放行窗口

每当 Pod / workload 标签变化,Terminology 写明身份会 reconfirm and automatically modified as required。结合 init 身份与 map reconcile,工程上至少要区分三类窗口(机制方向有文档与源码支撑;具体时长依赖控制面与节点负载,本文不下未实测数字):

1. 引导拒绝窗口(init)

新 Endpoint 在标签未齐时可能处于 reserved:init。若策略默认拒绝且未允许 init,连接在身份解析完成前失败。表象:Pod 已 Running、DNS/业务偶发超时,稍后自愈。优先查身份是否仍停在 init,而不是先改应用探针。

2. 变更拒绝窗口(身份已切、策略未齐)

标签变更导致新 Identity 已生效,但各节点 policy map / ipcache 尚未收敛到「允许该新身份」的条目。在默认拒绝模型下,窗口内流量被 drop。表象:一次 kubectl label 或滚动更新伴随短促失败;Hubble 类信号上常接近 policy deny(字段语义见后续 Hubble 篇)。

3. 变更放行窗口(旧身份残留)

相反方向:旧身份对应的允许条目尚未从 map 清除,而工作负载已贴上更严格标签意图。窗口内可能仍按旧允许关系放行。表象:以为已经收紧隔离,短时间内旧客户端仍能连上。这与「策略写错」不同,是收敛顺序问题;第 7 篇策略编译会回到 map 更新原子性。

窗口类型 典型触发 优先检查
init 拒绝 冷启动、元数据延迟 Endpoint 是否仍 init;分配存储是否健康
新身份拒绝 改标签、换 ServiceAccount 相关标签 新 Identity 是否已出现在策略允许集
旧身份放行 收紧标签 / 收紧 CNP 旧 Identity 引用是否仍在 map

排障口诀:把「偶发」翻译成哪一种窗口,再决定是等收敛、扩超时,还是改发布顺序(先扩允许集合、再切标签)。不要把三类窗口都写成「Cilium 不稳定」。

开放问题(系列级,本篇只立靶):标签风暴下身份分配延迟与 map 压力如何被可观测信号及时暴露——第 12–13 篇回收;学术/工程对照见文末研究讨论。


五、学术谱系、争论与开放问题

谱系:经典防火墙与 SDN ACL 以地址集合为策略主语;微服务编排把 churn 推高后,地址集合更新成为规模瓶颈。Cilium 文档中的 Identity-Based 模型是对该瓶颈的工程回答:策略主语改为标签导出的共享身份。可编程执行面则落在 eBPF map 查找(见 第 4 篇),而不是 netfilter 线性链——与 ebpf/ 中 map 作为状态原语的讨论同构。

争论:IP 策略简单性 vs Identity 一致性窗口

主张 代价
IP / CIDR 策略 心智模型贴近传统防火墙;无身份分配依赖 Pod churn 下规则更新放大;易与 IP 复用/迁移纠缠
Identity 策略 扩缩容同角色几乎不改策略键;跨节点共享身份 依赖分配存储与缓存收敛;标签变更引入 deny/allow 窗口

没有文献能宣布某一侧在所有集群规模下绝对更优。可检验的工程命题是:在你的 churn 与标签基数下,窗口故障是否可归因、是否可被发布流程吸收。若团队无法接受任何身份收敛窗口,却又要求秒级标签热修,应把预期改成「变更必须进入允许集合的两阶段发布」,而不是指望数据面消灭窗口。

开放问题

  1. 标签高基数:安全相关标签是否被错误包含构建号 / Pod hash,导致 Identity 接近 Pod 数量——使 Identity 模型退化为「昂贵的 IP」。入口:官方 Terminology · Security Relevant Labels;对照本系列第 4、13 篇 map 压力。
  2. 多集群身份:ClusterMesh 下身份与集群 ID 编码如何避免冲突与陈旧缓存——第 11 篇展开。
  3. 与用户态身份:SPIFFE / 网格工作负载身份与 Cilium numeric Identity 的边界(L3/L4 vs L7)——第 10、14 篇对照 envoy/

六、小结

  1. Endpoint 是节点局部网络实体;Numeric Identity 是集群范围策略键。
  2. 安全相关标签决定身份;保留身份(尤其 init)解释引导期行为。
  3. Identity 消除 IP churn 引发的规则风暴,不消除标签变更的重解析。
  4. 变更期至少区分 init 拒绝、新身份拒绝、旧身份放行 三类窗口。
  5. 下一轴是挂载:身份只有写进 hook 上的程序与 map 才成为数据面事实。

七、参考资料

规范 / 官方文档(A)

源码(A)

站内对照

实验台账


上一篇:数据面全景 · 系列目录 · 下一篇:BPF 挂载

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。

2026-08-16 · kubernetes / network

Cilium / eBPF 数据面内核:从 Identity 到包路径

补齐站内 Cilium 产品单篇与 eBPF 内核实现之上的数据面内核层:Endpoint/Identity、BPF 挂载与 Map、东西向包路径、kube-proxy 替代、策略编译、Hubble、加密与 Mesh/ClusterMesh 边界,并以排障与选型收束。


By .