题干与适用场景
这是身份基础设施与后端可靠性题。Kubernetes ServiceAccount 使用签名 JWT 访问 API Server 或其他信任该身份的系统;v1.36 将 external ServiceAccount token signer 能力提升到 stable,可通过本地 Unix domain socket 把签名请求交给外部系统。题目考察如何减少 API Server 上的私钥暴露面,同时保持 TokenRequest、验证公钥、轮换与高可用语义。
面试官考察点
- 能否分清签名、签发、验证和授权边界,而不是只说“接一个 KMS”。
- 能否设计 UDS/gRPC 连接、超时、并发、重试和密钥不可用时的 fail closed 行为。
- 能否处理新旧公钥重叠、JWT
kid、缓存和验证方刷新。 - 能否在不撤销有效短期 token 的前提下完成轮换与回滚。
- 能否给出审计、延迟、错误率和密钥使用指标。
回答前需要澄清的问题
- token 的 TTL、受众、签发 QPS 和 API Server 副本数量是多少?
- 外部 signer 是否提供 HSM 保证、健康探针、版本化密钥和幂等请求 ID?
- 验证方如何获得 JWKS,刷新延迟和缓存 TTL 是多少?
- signer 不可用时,允许暂时拒绝新 token,还是存在受控的旧密钥回退?
- 轮换期间是否有离线任务或集群外系统依赖这些 JWT?
30 秒回答框架
“我把链路拆成 TokenRequest、API Server 调用外部 signer、验证方获取公钥和 RBAC 授权。API Server 通过受保护的 Unix socket 调用 signer,带超时、请求 ID 和有限重试;私钥只在 KMS/HSM 内使用。轮换时先发布新公钥并让验证方缓存重叠,再用新 kid 签发,等待旧 token 的 TTL 过期后撤下旧钥。signer 不可用时拒绝新签发并告警,不静默生成未保护的 token;回滚保留旧公钥和旧 signer 版本。观测签名延迟、拒绝率、socket 错误、kid 分布和 JWKS 刷新延迟。”
分步骤深入解答
第一步:定义信任与数据流
TokenRequest 的授权决定谁能为哪个 ServiceAccount 请求什么 audience 的 token。API Server 校验请求后,把待签名的 JWT 载荷交给外部 signer;signer 返回签名,API Server 再返回 token。API Server 仍负责 issuer、audience、过期时间与 RBAC 语义,外部系统只负责受控签名,不应自行扩大权限。
第二步:设计本地 signer 接口
官方配置使用 --service-account-signing-endpoint 指向 Unix domain socket,外部服务可以在该 socket 上提供版本化的签名协议。socket 文件权限、目录、进程身份和 SELinux/AppArmor 策略要限制为 API Server 可访问。请求包含 key version、算法、摘要或待签名字节、请求 ID 与 deadline;响应包含签名、kid 和审计关联 ID。禁止把私钥或完整 token 写入普通日志。
第三步:处理超时、重试与幂等
签名调用是低延迟路径,应设置短 deadline 和有界并发。网络或 HSM 短暂失败可有限重试,但不能无限重试放大 API Server 请求队列。请求 ID 让 signer 和 API Server 关联审计;若协议支持幂等缓存,可避免同一请求重复计数。超时后返回明确错误并拒绝新 token,已有 token 是否继续验证由公钥和过期策略决定。
第四步:设计密钥轮换与 JWKS 重叠
先生成新密钥并让 signer 能用新 kid 签名,同时把新公钥发布到 JWKS。等待所有验证方完成刷新后,再让新 token 使用新 key;旧公钥至少保留到最长 token TTL 加缓存和时钟偏差窗口。撤下旧 key 前验证旧 token 已自然过期,不能仅依据签发端已切换。轮换操作应可暂停、审计和回滚。
第五步:保证多副本和灾备
每个 API Server 副本都要能访问本地或高可用 signer,且密钥版本和时钟一致。若 signer 是集中服务,评估跨节点网络、隔离域和故障半径;若使用每节点 sidecar,必须确认 HSM 连接和版本分发不会分叉。演练 signer 重启、socket 文件丢失、HSM 限流、JWKS 服务不可达和 API Server 滚动升级。
第六步:验证、审计与回滚
在 canary API Server 上先启用配置,验证 TokenRequest 的 issuer、audience、kid、过期时间和 RBAC 行为。对新旧 key、不同验证方和时钟偏差执行集成测试。指标包括签名 p50/p95、失败原因、socket 延迟、HSM 计数、JWKS 刷新年龄和 token 拒绝率。回滚时恢复旧 signer/key 配置并保留旧公钥;不要删除旧 key,直到所有旧 token 和审计窗口结束。
高质量示范回答
“我会把外部 signer 定位为只做签名的受控边界:API Server 继续验证 TokenRequest、issuer、audience、过期时间和 RBAC,通过受保护的 Unix socket 调用 signer,私钥只在 KMS/HSM 中使用。请求有版本、kid、ID、deadline 和有限重试;signer 不可用时拒绝新 token并告警。轮换先发布新 JWKS 并等待验证方刷新,再切换新 kid,保留旧公钥至少覆盖最长 TTL、缓存和时钟偏差。多副本要验证本地 socket、密钥版本和时钟一致,演练 HSM 限流、socket 丢失和 JWKS 不可达。canary 重点检查签名延迟、拒绝率、kid 分布、JWKS 年龄和 RBAC 集成,回滚保留旧 signer 与旧公钥。”
常见错误
- 让外部 signer 直接决定 RBAC 或 audience,扩大签名服务职责。
- 把私钥复制到 sidecar 或日志,失去移出 API Server 的安全收益。
- 轮换后立即删除旧公钥,导致仍在 TTL 内的 token 无法验证。
- signer 超时无限重试,拖垮 API Server 的请求队列。
- 只测签名成功,不测验证方 JWKS 缓存、时钟偏差和多副本一致性。
- 把 signer 不可用时的静默旧密钥签发当作可靠回退,却没有审计边界。
追问及应对
signer 不可用时能否继续用本地旧私钥?
只有在明确的威胁模型、审计和回滚方案允许时才能考虑;默认应拒绝新签发,避免秘密重新散落到 API Server。已有 token 仍可由验证方按旧公钥验证,直到 TTL 结束。
如何确定旧公钥可以删除?
使用最长 token TTL、验证方 JWKS 缓存 TTL、最大时钟偏差和离线消费者保留期计算安全窗口,并用指标确认旧 kid 使用量归零。窗口结束后再删除,且先保留可恢复备份。
为什么使用 Unix socket 而不是 HTTP?
本地 socket 可缩小监听面,减少网络暴露,并利用文件权限和主机策略控制访问。它不能自动解决协议认证、进程隔离或可用性问题,仍需版本化接口、审计、超时和故障演练。