This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
workload-sts/docs/architecture.md
T

7.8 KiB
Raw Blame History

系统架构

历史文档: 本架构已由 SPIRE 方案替代,不再作为实施目标。参见 superseded-by-spire.md

本文是 specification.md 的架构视图。规范定义外部行为,本文解释 组件边界;二者冲突时以规范为准。当前 v0.1 设计已经批准。

组件与数据流

                  Kubernetes SA JWT
                              |
                              v
                    Credential Verifiers
                              |
                              v
                    Principal Normalization
                              |
                              v
              Issuance Policy + CEL Conditions
                              |
                              v
                   OAuth 2.0 Token Endpoint
                              |
                              v
                   Audience-bound JWT Issuer
                              |
             +----------------+----------------+
             |                                 |
             v                                 v
     OpenBao JWT auth                Kubernetes/API service
             |                                 |
             v                                 v
      OpenBao client token             Native authorization

服务验证上游 credential,但不把它直接转发给下游。签发决策成功后生成新的 JWT, 其 issuer、audience、TTL 和 claims 由本服务控制。

下游资源服务器负责最终授权。OpenBao 根据 JWT auth role 和 policy 签发自己的 client tokenKubernetes 根据外部 JWT authenticator 和 RBAC 授权。本服务不复制这些权限模型。

组件边界

OAuth 2.0 协议层

协议层负责 Authorization Server metadata、token endpoint、标准 OAuth2 错误和响应。 第一阶段只实现 RFC 8693 Token Exchange 所需子集,不实现交互式用户登录。

协议层只实现已批准的 RFC 8693 子集。HTTP 路由和 middleware 使用与 net/http 兼容的 chi/v5,OAuth 表单仍由 Go 标准库显式解析,不使用框架自动 bindingJOSE 与 OpenBao 调用使用成熟库。首轮 PoC 发现现有 OAuth2 框架仍需自定义 token exchange、client store 适配和 Transit signer,不能减少本项目的核心安全逻辑,因此 v0.1 不引入完整 Authorization Server 框架。业务代码仍将 credential verification、授权和 token materialization 保持为独立边界。详见 poc.md

启用 OpenTelemetry 时,启动层可以在纯 chi router 外使用 otelhttp 生成 server span 和 标准 HTTP metrics;未启用时不安装该 wrapper。span 与 metric 只使用 固定路由模板及受控低基数字段,不捕获请求/响应 body、Authorization header、 subject_token、输出 token、client_id、principal 或 jti。trace 与 metric provider 通过启动依赖注入;未配置 exporter 时保持 no-op,不把 telemetry 输出到标准输出。

Credential Verifier

每种 verifier 把特定上游凭据转换为不可伪造的内部事实:

issuer
source subject
source credential type
source audiences
issued-at / expiry
verified attributes
verification method

verifier 不能直接决定目标 audience 或输出 claims。未经验证的请求字段不能进入 verified attributes

第一阶段支持:

  • Kubernetes projected ServiceAccount JWT。

OIDC、SPIFFE、云 workload identity 和外部 metadata 系统以后以 verifier 扩展,不改变 token endpoint 合同。不同 credential issuer 可以使用不同验证逻辑,但 upstream issuer 不是 OAuth client。

所有 token request 都必须携带 client_id。v1 的 client authentication method 为 none,因此该值只以 client_id_claimed 进入审计,不参与身份映射或授权。以后可以为 同一字段增加 public client registration、mTLS 或 private_key_jwt 认证,无需改变请求 是否包含 client_id 的合同。

client_id 使用 363 字符的 DNS-label-like 语法,只允许小写字母、数字和中横线,且 中横线不能位于首尾。

Principal Normalization

trust binding 把上游 verifier 与 source subject 映射为稳定、不可变的内部 principal:

sub = 01993f4d-5e1a-7000-8000-000000000001
principal_name = ci/homelab-infra-plan

可读名称允许受控改名,JWT sub 使用的 ID 不随名称变化。映射规则由管理员配置; 客户端不能在 token 请求中选择或覆盖 sub。一个上游身份可以没有任何映射,此时认证 成功但 token exchange 被拒绝。

Issuance Policy

授权层只回答:

某个已验证 principal 是否可以为指定 audience 和 scope 获取 JWT

trust binding 中的 issuance rule 先限制 principal、audience 和 scope,并直接绑定唯一 token profile;CEL 只表达需要结合已验证上下文的条件。客户端不能请求 profile。CEL 不能调用网络、读取机密或修改状态。

授权层不决定 OpenBao secret path、Bao token TTL 或 Kubernetes RBAC。

JWT Issuer

JWT issuer 根据批准的 token profile 生成 claims 并请求签名后端签名。客户端只能请求 允许缩小权限的参数,不能直接提交输出 sub、任意 claim、签名算法或 TTL。

生产签名密钥保存在 OpenBao Transit 中;数据库和服务实例不保存私钥。 workload-sts 使用自己的 Kubernetes ServiceAccount JWT 登录 OpenBao,取得只允许访问 指定 Transit key 的短期运行凭据。它不替客户端登录 OpenBao,也不接触客户端随后取得 的 Bao token。第一阶段使用 RS256;签名后端保留接口边界,以便单元测试使用内存 signer。密钥轮换的具体运维合同在部署设计中补充。

Database

HTTP 实例无本地持久状态。数据库保存配置及需要一致性的控制面状态,例如:

  • upstream issuer 与 verifier 配置;
  • trust binding
  • principal、audience、scope 与 token profile
  • CEL policy 及版本;
  • 调用方自报 client_id 的有界审计值;
  • 审计索引和配置变更记录。

数据库不得保存 bearer token、原始 subject token、OpenBao client token 或签名私钥。 自包含 JWT 的普通验证不依赖数据库在线 introspection。

Kubernetes 信任方向

系统明确区分两条方向相反的链:

Kubernetes SA JWT -> workload-sts

projected ServiceAccount JWT 的 audience 是 workload-sts,用于证明 Pod 的上游身份。

workload-sts JWT -> kube-apiserver

目标 audience 是特定 Kubernetes cluster。kube-apiserver 通过外部 JWT authenticator 验证 issuer 和 claims,再交由 RBAC 授权。workload-sts 不签发 Kubernetes ServiceAccount token。

外部 workload attestation

PVE、microVM、vsock metadata、Gitea runner 调度和云 metadata 不属于本仓库。对应系统 以后可以输出本服务可验证的标准身份载体,例如 JWT-SVID 或已登记 issuer 的 JWT。

本服务不依赖或理解 VMID、vsock CID、Gitea job 环境变量、runner registration token 或虚拟机生命周期。外部系统负责防重放、实例代际和 attestation,本服务负责验证其最终 credential 并执行签发策略。

部署边界

系统是无状态 HTTP 服务加数据库,可以部署在 Kubernetes、VM 或其他运行环境。部署位置 不是信任语义的一部分;OAuth issuer 必须保持为稳定的 https://identity.ad.ddupan.top

workload-sts 依赖 OpenBao Transit 完成生产签名,但只使用自己的最小权限运行身份; OpenBao 的人工管理与 break-glass 路径不得反向依赖 workload-sts。

文档入口