Files
qinglong/docs/adr/ADR-0241-kubernetes-worker-credential-tokenrequest-session.md
T

7.4 KiB
Raw Blame History

ADR-0241Kubernetes Worker Credential TokenRequest Session

  • 状态:Accepted
  • 日期:2026-08-01
  • 关联 RFCQL-RFC-0001 D-23、D-58、D-175、D-224、D-225
  • 关联 ADRADR-0060、ADR-0061、ADR-0124、ADR-0192、ADR-0234、ADR-0240
  • 收窄:ADR-0240 的 TokenRequest 签发与销毁产品接线;不替代其双 namespace、prepared target 或 delivery RBAC 决策

背景

ADR-0240 已把 Kubernetes credential delivery 收窄到短期 ServiceAccount token 与双 namespace 最小 RBAC,但当时的 live fixture 仍直接执行 kubectl create token。该命令会把 bearer token 返回给 shell/caller;若产品入口沿用这种方式,token 可能进入终端滚屏、命令替换、 进程内长期变量或临时 kubeconfig,而且无法在真正写入 Secret 前证明 issuer 与 delivery 身份均没有意外扩权。

同时,TokenRequest issuer 和 delivery ServiceAccount 是两个不同 authority:前者只能为 一个预定 ServiceAccount 签发 token,后者才能访问 stage 与精确 target。把两者合并到 admin kubeconfig、常驻 control 或 Worker 会扩大凭据泄漏后的 blast radius,也让低配设备 承担不必要的 Kubernetes SDK、连接或后台生命周期。

决策

1. Token issuer 是外部、短生命周期管理身份

生产 manifest 将外部认证主体组 qinglong:worker-credential-operators 绑定到 staging namespace 中唯一 Role。该 Role 只允许 对 exact ql3-worker-credential-adminserviceaccounts/token 执行 create;不得读取 Secret、Deployment、Pod、Namespace,也不得为其他 ServiceAccount 签发 token。

issuer kubeconfig 由部署者在受保护的管理工作站或受控管理作业中提供。它不是 Worker/control Pod 的 Secret 或 volume,也不绑定 delivery ServiceAccount、普通 control 身份或广域管理员组。

2. 每次 delivery 创建一个有界 TokenRequest session

cluster-admin 既有 package 增加显式 worker-credential-kubernetes-token-request subpath。每次 withDelivery() 必须按以下顺序执行:

  1. 先以 issuer 身份完成 1 条应允许与 8 条应拒绝的 SelfSubjectAccessReview;任何意外允许、 意外拒绝或 API 不可用均在 TokenRequest 前失败关闭;
  2. 只向 staging namespace 的 exact ServiceAccount 请求 600 秒 token
  3. 对 API 响应施加 16 KiB 上限、canonical JWT 结构、非 none 算法、exact ServiceAccount subject、iat/exp 安全整数、30600 秒 lifetime、API expiration 与 JWT expiration 一致性;
  4. 只在内存中构造 restricted KubeConfig,立即清空 TokenRequest response 中的 token 引用;
  5. 以 delivery 身份完成 8 条应允许与 20 条应拒绝的 SelfSubjectAccessReview,确认与 ADR-0240 的 stage/target/Deployment 权限矩阵精确一致后才调用业务 operation;
  6. callback 只得到既有 delivery adapter 和低敏计数证据,不返回 token、KubeConfig 或原始 Kubernetes clients;成功、业务失败、校验失败都在 finally 清空 token 并使 restricted KubeConfig 失效。销毁失败同样失败关闭,但只暴露稳定、无敏感内容的领域错误。

该 session 不把 JWT payload 当成独立认证来源;Kubernetes API 仍是签发与鉴权事实源。本地 结构检查只用于拒绝错误主体、异常寿命和畸形响应,不能替代 API server 的签名验证。

3. 保持可选依赖与 Profile 边界

实现不新增 workspace package、生产依赖、timer、watcher、listener、sidecar 或数据库对象。 Kubernetes client 由调用方显式注入,只在短生命周期 Cluster Admin 路径加载;Edge、 Standalone、Worker 和未启用 Cluster 路径不导入该 SDK、不创建连接,也没有空闲成本。

4. TokenRequest session 不等于审批产品入口

本 ADR 只关闭“受批执行之后如何安全签发并消费短期 delivery capability”。正式产品命令仍须 先使用既有强 User principal、Project/Policy、separation-of-duty Approved Action、持久审计与 exact replay,再在执行阶段进入 session。测试中的 impersonated User 只是 RBAC fixture,不能 替代 OIDC/client certificate 身份认证、双人审批或 durable execution receipt。

不采用方案

继续调用 kubectl create token

拒绝。命令的正常输出就是 bearer token,调用者必须自行管理 stdout、变量、临时文件和销毁, 也无法把 issuer/delivery 两层权限校验与 adapter 生命周期封装成一个 fail-closed 边界。

将 TokenRequest authority 交给 delivery ServiceAccount

拒绝。这会允许受限 delivery token 自签新 token,并延长或复制 compromise authority。 issuer 必须是外部管理身份,delivery ServiceAccount 明确通过 deny matrix 证明不能自签。

复用 cluster-admin kubeconfig 完成 delivery

拒绝。广域 kubeconfig 绕过 exact-name RBAC,任何 adapter 缺陷都会升级为集群级 mutation。

常驻 controller 自动轮换

拒绝。它会把 issuer credential、Kubernetes SDK、连接、timer/watch 与 leader/retry 状态带入 常驻面,既扩大攻击面,也把路由设备无需承担的成本引入共同架构。

影响

  • credential-admin deployment 资产新增一个 exact TokenRequest issuer Role/RoleBinding
  • cluster-admin 新增一个显式 subpath 和内存 session,不新增 package 或第三方依赖;
  • live Gate 不再读取、打印或返回 delivery token,也不再手工构造 restricted kubeconfig
  • session 是一次性 callback scope,调用方不能缓存 adapter 跨 operation 使用;
  • issuer/delivery 权限漂移会在 Secret/Deployment mutation 前被发现并失败关闭;
  • durable approval 产品命令仍是后续独立切片,不因本 ADR 自动完成。

验证

  1. GitNexus upstream impactsession 为 LOW,仅 1 个直接上游 KubeConfig wrapper0 条已识别 production execution flow
  2. strict TypeScript 与定向 6/6 通过,覆盖成功销毁、issuer/delivery 意外扩权、错误 subject、 畸形/超长/expiry 不一致响应、TokenRequest 错误和销毁错误的无敏感映射;
  3. deployment audit 与 kubectl kustomize 验证 exact serviceaccounts/token + resourceNames=[ql3-worker-credential-admin]production subject 是外部 Group 而非 delivery ServiceAccount
  4. 固定 rancher/k3s:v1.34.3-k3s1 的真实 arm64 Gate 创建 2 个独立 600 秒 session,完成 issuer 1 allow/8 deny、delivery 8 allow/20 deny、credential A→B、Recreate 顺序、PVC 强制 Pod 丢失恢复与 identity A→Btoken 未从 session 返回,每次 restricted client 均销毁, 全部 gate passed=true
  5. PostgreSQL 18.4 arm64 physical HA 随后重跑通过:remote_apply、timeline 1→2、旧主 fencing、未确认分区提交排除、pg_rewind 只读同步重入、两个 fresh control replica 及全部 domain COMMIT-response-loss gate 均为 true
  6. 成功/失败后的 ql3-worker-rollout-live-*ql3-ha-* Docker 容器均无残留。

仍未完成

  • 强 User 登录、双人批准、durable execution receipt 与该 session 的正式产品命令组合;
  • production OIDC/client certificate issuer group 的真实外部 IdP ceremony、撤销与审计;
  • 多节点 Kubernetes API/CSI、API partition、TokenRequest latency/expiry race 与控制面升级矩阵;
  • production Worker image 的真实 360 秒 Session drain,以及固定 x64/arm64 低配设备资源证据。