TLS 与 PKI
AuthNexus 构建了一套完整的 PKI 体系,通过四类独立 CA 实现不同安全域的证书隔离,所有业务通讯均强制 TLS 1.3 + mTLS。
四类 CA 概览
| CA 名称 | 标识 | 保护的通讯 | 签发对象 |
|---|---|---|---|
| CP Server CA | cp_server_ca | CP 南向接口(:9091) | Control Plane 服务端证书 |
| CP Node Client CA | cp_node_client_ca | 节点 → CP 的 mTLS 客户端认证 | 业务节点客户端证书 |
| TCP Server CA | tcp_server_ca | 业务 TCP 连接 | Server App 服务端证书 |
| App Client CA | app_client_ca | SDK → Server 的 mTLS 客户端认证 | 应用级 SDK 客户端证书 |
四类 CA 完全独立,各自有自己的根证书、签名密钥和吊销列表。这种设计确保:
- CP 管控面与业务面的证书互不信任
- 节点证书被吊销不影响管控通道
- 应用级 CA 可独立轮换,不影响其他应用
首次 PKI 初始化
Web 部署向导
首次启动 Control Plane 时,系统进入 setup-only 状态:
- 仅开放
/admin/v1/setup/*端点 - 不开放
/cp/*南向接口 - 不接受任何节点注册
访问 http://localhost:8080 进入部署向导,按顺序初始化四类 CA:
初始化步骤
第一步:CP Server CA
配置 CP 服务端 CA 的根证书参数:
- 密钥算法(RSA 2048/4096、ECDSA P-256/P-384)
- CA 有效期
- 证书主题(Subject)
系统自动生成 CA 根证书和密钥对,并签发 CP 服务端证书。
第二步:CP Node Client CA
配置节点客户端 CA,参数与上一步类似。此 CA 用于签发节点的 mTLS 客户端证书。
第三步:TCP Server CA
配置业务 TCP 服务端 CA。此 CA 签发的证书用于 Server App 的 TLS 监听。
第四步:App Client CA
配置应用客户端 CA。此 CA 签发 SDK 客户端证书,支持按应用隔离。
重要
四类 CA 全部初始化完成后,CP 才退出 setup-only 状态并开放南向接口。中途中断需重新开始。
mTLS 握手验证
业务连接(SDK → Server)
SDK 连接 Server App 时,双向 TLS 握手执行四道约束验证:
┌───────────────┐ ┌───────────────┐
│ SDK 客户端 │ ── TLS 1.3 ──→ │ Server App │
│ │ ← 服务端证书 ── │ │
│ 客户端证书 ──→│ │ │
└───────────────┘ └───────────────┘约束一:CA 信任链
- Server 验证 SDK 客户端证书是否由
app_client_ca签发 - SDK 验证 Server 证书是否由
tcp_server_ca签发
约束二:证书语义
- 客户端证书必须包含
clientAuth扩展密钥用途(EKU) - 客户端证书必须包含格式为
urn:authnexus:app:<id>的 URI SAN(Subject Alternative Name)
约束三:CP 绑定
- Server 从 CP 拉取的
app_mtls_trust_bundle中验证证书绑定关系 app_cert_bindings记录了哪些证书被授权用于哪个应用
约束四:业务握手
- TLS 握手完成后,SDK 在业务协议层声明
app_id - Server 验证
claimed app_id与证书中 URI SAN 的app_id一致
四道约束全部通过后才允许业务通讯。任何一道失败都会拒绝连接。
管控连接(Server → CP)
节点连接 CP 南向接口时:
- Server 使用
cp_node_client_ca签发的客户端证书 - CP 使用
cp_server_ca签发的服务端证书 - 双向验证确保只有合法节点能访问管控接口
App Client CA 热替换
应用级客户端 CA 支持运行时热替换,无需停机。
Generation 机制
每次 CA 替换生成一个新的 generation 编号。Server 维护当前有效的 generation:
- Admin 通过后台发起 CA 替换
- CP 生成新的 CA 根证书,递增 generation
- CP 通过 Channel ② 推送
config.pending事件 - Server 拉取新的
app_client_ca_bundle - Server 构建新的 TLS context,包含新 CA
- 旧 TLS context 上的在途握手会被拒绝
- 后续新连接使用新 CA 验证
注意
CA 热替换后,所有使用旧 CA 签发证书的 SDK 客户端将无法连接。请确保在替换前已完成客户端证书迁移。
CP Node Client CA Reconcile
节点客户端 CA 的 reconcile 是 fail-closed 的:如果 reconcile 失败,节点将无法连接到 CP,直到问题解决。
OCSP Stapling
AuthNexus 实现了完整的 OCSP Stapling 流程,为 SDK 提供证书吊销状态的实时证据。
整体流程
┌──────────┐ ① POST /ocsp/ ┌──────────┐
│ Server │ ───────────────→ │ CP │
│ App │ ←─ OCSP Resp ── │ OCSP │
│ │ │ Responder│
│ ┌──────┐ │ └──────────┘
│ │Staple│ │
│ │Cache │ │
│ └──┬───┘ │
│ │ │
│ ┌──▼───┐ │ TLS Handshake ┌──────────┐
│ │ TLS │ │ ←───────────────→ │ SDK │
│ │Server│ │ + OCSP Staple │ 客户端 │
│ └──────┘ │ └──────────┘
└──────────┘Server 端:OcspStaplingManager
OcspStaplingManager 运行在后台 strand 上,负责:
- 周期获取:约每 15 分钟向 CP 的 OCSP Responder 发送请求
- 自适应刷新:根据 OCSP 响应中的
nextUpdate字段调整刷新周期(取nextUpdate / 2) - 本地缓存:在
nextUpdate有效期内使用缓存响应 - Staple 到握手:将 OCSP 响应附加到 TLS 握手的
CertificateStatus消息中
获取 OCSP 响应的 HTTP 请求通过 cp_io_threads 池执行(blocking httplib POST),与 Channel ① 共用实现模式。
CP 端:OCSP Responder
- 监听独立端口(默认 9092)
- 使用独立线程池(
ocsp_thread_pool_count) - 每个请求现场签发 OCSP 响应(不缓存)
- RSA-SHA256 签名
SDK 端验证
SDK 在 TLS 握手阶段验证 OCSP Staple:
| 验证项 | 说明 |
|---|---|
| 签名验证 | 使用 ocsp_signer_ca.pem(= tcp_server_ca 信任锚)验证签名 |
| 时间窗校验 | thisUpdate 到当前时间不超过 maxsec(1800 秒) |
| 证书状态 | good 放行,revoked 拒绝,unknown 拒绝 |
| must-staple | 若服务端证书带 must-staple 扩展,无 staple 直接拒绝握手 |
吊销场景
当管理员在后台吊销某节点的 TCP Server 证书:
- CP OCSP Responder 对该证书返回
revoked状态 - Server 获取到 revoked 的 OCSP 响应
- Server 继续 staple revoked 响应(不自行关停)
- SDK 在 TLS 握手中验证到
revoked状态,拒绝连接 - 业务流量立即中断
- 管控通道(mTLS
/cp/v2/*)不受影响,因为使用不同的 CA 体系
管理员 re-enable 证书后,下次 OCSP 刷新获取到 good 响应,节点自动恢复。
证书生命周期
节点证书 Enrollment
新节点首次注册的证书获取流程:
- 在管理后台创建节点记录
- 节点生成密钥对和 CSR(Certificate Signing Request)
- 通过管理后台或 API 提交 CSR
- CP 使用对应 CA 签发证书
- 节点获取证书后启动 mTLS 连接
证书续期
节点证书接近到期时需要续期:
- 节点生成新的密钥对和 CSR
- 通过管控通道提交续期请求
- CP 签发新证书
- 节点切换到新证书
Reissue 与恢复
节点证书 reissue 后,必须删除节点旧证书文件才能重新 enroll。节点 enroll 决策只看本地证书文件是否存在——如果旧证书文件仍在,节点会用废弃的证书尝试连接,导致 403 循环。
安全隔离总结
| 通讯路径 | 传输层 | 认证方式 | CA 体系 |
|---|---|---|---|
| SDK → Server | TLS 1.3 TCP | mTLS(双向) | tcp_server_ca + app_client_ca |
| Server → CP | TLS 1.3 HTTP | mTLS(双向) | cp_server_ca + cp_node_client_ca |
| Server → CP OCSP | Plain HTTP | OCSP 签名 | tcp_server_ca(签名验证) |
| Admin → CP | HTTP (loopback) | Session Token | 无(本地 + 反向代理) |