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/README.md
T

110 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# workload-sts
> **项目已停止开发。** 本方案已由 SPIRE 的 workload attestation、SPIFFE Workload API、
> JWT-SVID/X.509-SVID 和 OIDC Discovery Provider 替代。仓库仅保留设计与 PoC 历史,
> 不应部署或继续扩展。详见 [`docs/superseded-by-spire.md`](docs/superseded-by-spire.md)。
面向 workload identity 的 OAuth 2.0 Security Token Service。它验证 Kubernetes
ServiceAccount JWT 等上游身份,执行签发授权,并生成短期、限定 audience 的 JWT
assertion。
项目只负责“验证身份后签发 assertion”。OpenBao 等下游资源服务器自行验证 JWT、
映射本地权限并管理自己的 token、lease 和凭据生命周期。
项目在 PoC 阶段停止,未提供可运行服务或稳定 API。仓库中的 RFC 8693 与 OpenBao
Transit 代码只用于保存当时的技术验证,不构成受支持的软件。
## 目标
- 按 OAuth 2.0 Authorization Server 和 Token Exchange 标准语义提供接口,优先复用
成熟协议库。
- 第一阶段验证 Kubernetes projected ServiceAccount JWT,并为其他 credential issuer
保留独立 verifier 扩展点。
- 将已验证的上游身份映射为稳定的 workload principal。
- 根据 principal、audience、scope 和请求上下文判断是否允许签发,由服务端选择唯一的
token profile。
- 要求每个请求显式提交 `client_id`;v1 不认证该字段,只以 `client_id_claimed` 记录,
为以后注册 public/confidential client 保持稳定请求形状。
- `client_id` 长度为 3–63,只允许小写字母、数字和中横线,且必须以字母或数字开头和
结尾。
- 使用短期 JWT 隔离上游证明与下游访问凭据;一个 token 只面向明确的 audience。
- 让 OpenBao 保持机密、PKI、动态凭据和自身 token 生命周期的权威后端。
- 让 Kubernetes、OpenBao 和普通 OAuth2 Resource Server 使用各自的原生 JWT 验证
能力,而不要求业务系统理解上游身份来源。
- 提供结构化且不泄露 bearer token 的交换审计。
- 使用 OpenTelemetry trace/metric SDK 与标准 HTTP instrumentation,且不采集 token、
请求体或高基数身份字段。
## 非目标
- 不提供用户目录、密码登录、MFA 或交互式 OIDC 登录;人工身份由现有 IdP 提供。
- 不读取、缓存或代理 OpenBao 中的机密。
- 不替调用方登录 OpenBao,也不签发、续期或撤销调用方的 OpenBao client token;服务
自身可以使用独立的 Kubernetes identity 获取访问 Transit 所需的最小权限运行凭据。
- 不定义或同步 OpenBao policy、Kubernetes RBAC 或下游应用权限。
- 不管理 Gitea Actions job、runner、Kubernetes Pod、PVE VM 或 microVM 生命周期。
- 不实现 PVE/microVM vsock metadata service 或平台 attestation。
- 不自创策略表达式语言、workload identity 格式或私有 token exchange 协议。
- 第一阶段不直接返回 OpenBao token、SSH certificate、数据库密码或云凭据;以后增加
credential materializer 必须通过新的规格和安全评审。
## 核心流程
以 Kubernetes 中的 CI workload 登录 OpenBao 为例:
```text
CI Pod
|
| projected ServiceAccount JWT
| aud = https://identity.ad.ddupan.top
v
workload-sts
| 1. 验证 Kubernetes issuer、signature、audience 和时效
| 2. 映射 workload principal
| 3. 检查 OpenBao audience 的签发策略
| 4. 签发短期 JWT assertion
v
OpenBao JWT auth
| 验证 iss、sub、aud 和 bound claims
| 映射本地 role/policy
v
OpenBao client token
```
`workload-sts` 的职责在签发 JWT assertion 后结束。Bao token 的 TTL、renewal、
revocation、lease 以及 CI job 结束后的清理由 OpenBao 和调用方负责。
## 协议身份
当前设计使用:
```text
OAuth issuer: https://identity.ad.ddupan.top
```
OAuth issuer 是稳定的网络协议身份,不与进程部署位置绑定。SPIFFE 可以作为未来的上游
身份协议,但第一阶段不建立 SPIFFE trust domain,也不把内部 principal 伪装成 SPIFFE
ID。
## 文档
- SPIRE 替代决策:[`docs/superseded-by-spire.md`](docs/superseded-by-spire.md)
- 系统边界与数据流:[`docs/architecture.md`](docs/architecture.md)
- 规范行为与待决策项:[`docs/specification.md`](docs/specification.md)
- 威胁模型与安全要求:[`docs/security.md`](docs/security.md)
- 首轮库与签名 PoC 结论:[`docs/poc.md`](docs/poc.md)
其余文档均为替代决策前的历史材料,不再代表实施计划。
## 计划中的最小纵向切片
1. 发布 Authorization Server metadata 和 JWKS。
2. 验证一个 Kubernetes projected ServiceAccount JWT。
3. 按 RFC 8693 处理一次 token exchange。
4. 根据 SA binding 中的 issuance rule、请求 scope 和 CEL 条件决定是否签发。
5. 签发 `aud` 指向 OpenBao 的短期 JWT。
6. 由 OpenBao JWT auth 验证该 JWT 并返回受限 Bao token。
代码与发布物托管在
`git.ddupan.top/panxiao81/workload-sts`。