Linux tetragon 的 k8s pod label 过滤与多租户策略隔离

13次阅读

tetragon 的 podselector 不生效因 label 匹配逻辑与 kubernetes 不一致:仅在 pod 创建时读取 metadata.labels,不支持 matchexpressions、动态更新或大写 / 下划线 key;需用 matchlabels、全小写中划线 key,并结合 namespaceselector 双层过滤,显式设置 priority 避免冲突,且须显式声明 containerruntime。

Linux tetragon 的 k8s pod label 过滤与多租户策略隔离

为什么 tetragonpodSelector 不生效?label 匹配逻辑和 Kubernetes 不一致

因为 tetragon 的 label 过滤不是直接复用 kube-apiserver 的 selector 解析器,而是通过 eBPF 程序在内核态做匹配——它只认 Pod 启动时注入的 labels(即 metadata.labels),不感知 label selector 的动态计算、不支持 matchExpressions,也不处理 label 被 runtime 修改后的更新。

  • tetragon 只在 Pod 创建时读取一次 labels,后续 patch 或 annotate 不触发策略重载
  • 必须用 matchLabels,写成 matchExpressions: [{key: "env", operator: "In", values: ["prod"]}] 会静默忽略
  • label key 必须全小写、中划线分隔(如 tenant-id),带下划线或大写字母的 key(如 tenant_id)在 eBPF map 中会被截断或哈希错位
  • 多租户场景下,建议用固定前缀隔离,比如统一加 tenant.k8s.io/ 前缀,避免不同租户误用同名 label

如何让 TetragonPolicy 精确作用于某租户的所有 Pod?用 namespace + label 双层过滤

单靠 label 容易跨 namespace 漏匹配(比如 dev 和 prod namespace 都有 app: api),tetragon 支持在 podSelector 外叠加 namespaceSelector,但注意:两者是 AND 关系,且 namespace selector 只支持 matchNames,不支持 label 匹配。

  • 正确写法:
    podSelector:   matchLabels:     tenant.k8s.io/id: "acme" namespaceSelector:   matchNames: ["acme-prod", "acme-staging"]
  • 错误写法:namespaceSelector 里写 matchLabels: {name: acme-prod} —— tetragon 会直接跳过整个策略
  • 如果租户 namespace 命名无规律,只能靠 label 标识 namespace 层级,此时需在所有 Pod 注入冗余 label,例如 tenant.k8s.io/ns: acme-prod,再统一用 podSelector 匹配
  • 验证是否生效:用 kubectl get tetracapsule -o wide 查看策略绑定的 Pod 数量;若为 0,大概率是 label 键名拼写或 namespace 名不匹配

tetragon 多租户策略冲突时谁优先?策略顺序不决定优先级,靠 priority 字段

tetragon 不按 YAML 文件创建顺序或名字字母序执行策略,所有策略默认 priority=0。当两个策略对同一 Pod 的同一事件(如 exec)定义了不同动作(allow vs deny),结果取决于 priority 值:数值越小,优先级越高;相同 priority 时,行为未定义(实际常为 deny 优先,但不可依赖)。

  • 必须显式设置 priority,例如租户白名单策略设为 priority: 10,平台级禁止策略设为 priority: 5
  • priority 是 int32,范围 -2147483648 到 2147483647,但建议控制在 1–100 内,避免维护混乱
  • 不要用 priority: 0 做业务策略——它常被 Tetragon 自身的 default-deny 策略占用
  • 调试时用 tetra get events --output json | jq '.policy_name' 看事件最终匹配的策略名,再比对其 priority

为什么租户 Pod 的 syscall 事件没上报?检查 processArgscontainerRuntime 兼容性

多租户场景下常启用 processArgs: true 来审计命令行参数,但这会显著增加 eBPF map 占用和 event 体积;更关键的是,tetragon 对 containerd 和 CRI-O 的进程上下文提取逻辑不同,某些 runtime 下 podSelector 匹配成功,但因无法关联到容器 ID,导致事件丢失。

  • 确认 runtime 类型:kubectl get node -o wideCONTAINER-RUNTIME 列,containerd v1.7+ 推荐用 containerRuntime: "containerd",旧版或 CRI-O 需显式指定 "crio"
  • processArgs: true 在高并发 exec 场景可能触发 eBPF map full(错误日志含 map insert failed: -12),此时要调大 --bpf-map-size-process-args 启动参数
  • 租户 Pod 若用了 distroless 或 scratch 镜像,/proc/[pid]/cmdline 可能为空,processArgs 报告空字符串——这不是 bug,是 kernel 行为
  • 最简验证法:先关掉 processArgs,用 eventType: "exec" + processName: "sh" 测试基础事件是否上报,再逐步开功能
租户 label 的 key 命名、priority 设置、runtime 显式声明,这三处最容易在灰度上线后才发现问题——尤其是 priority 默认值和 runtime 自动探测,线上跑几天才暴露策略“看似加载成功却没效果”。

text=ZqhQzanResources