主题
02 · 信任与身份模型
三件套:fabric-ca + sign-ca + sign-kms
来源:cbdc-biz/.env.example、cbdc-network/.env.example、cbdc-biz/conf/*/core.yaml、相关包 wiki。
每个组件的详情:
- fabric-ca · 概述 — 证书签发(X.509 + Idemix)
- sign-ca · 概述 — fabric-ca + sign-kms 的镜像化封装
- sign-kms · 概述 — KMS gRPC + Web UI + PKCS#11 库
KMS namespace 与 access token
来源:cbdc-biz/.env.example、cbdc-chain/scripts/start-kms-system.sh、sign-kms · 核心流程。
关键事实:
KMS_TOKEN_LABEL(默认值KMS_TK)是 sign-ca / sign-kms 约定的 PKCS#11 token label(cbdc-biz/.env.example、cbdc-biz/conf/bizhub/core.yaml:45)。KMS_USER_PIN是 access token JWT,作为 PKCS#11 pin 使用:CA 容器把它注入为FABRIC_CA_SERVER_BCCSP_PKCS11_PIN(cbdc-biz/docker/compose-local-run-infra.yml:37);各业务应用容器以KMS_USER_PIN透传(compose-local-run.yml)。- KMS 三角色:
readonly/readwrite/admin(sign-kms · API)。
环境变量注入链路
来源:cbdc-biz/.env.example、cbdc-biz/docker/compose-local-run.yml、cbdc-network/.env.example。
cbdc-biz/.env.example 中的关键变量(每条均有 ${...} 形式被 compose 或 yaml 引用):
| 变量 | 用途 | 出现位置 |
|---|---|---|
BIZHUB_ADDR | 下游应用回调 BizHub | cbdc-biz/conf/{endorser1,issuer,auditor,institution-001}/core.yaml biz.bizhub_addr |
UPSTREAM_ISSUER_ADDR | BizHub → Issuer | cbdc-biz/conf/bizhub/core.yaml:75 upstream.issuer.addr |
INSTITUTION_001_ADDR | BizHub → Institution(按 code 路由) | cbdc-biz/conf/bizhub/core.yaml:26 institutions[].endpoint.addr |
FSC_*_ADDR(per role) | FSC endpoint 解析器 | 各 core.yaml fsc.endpoint.resolvers[].addresses.P2P |
SIGN_KMS_ENDPOINT | KMS gRPC 地址 | CA / 业务应用容器 env,被 libkms_pkcs11.so 读取 |
KMS_USER_PIN | PKCS#11 pin(JWT) | CA 容器注入为 FABRIC_CA_SERVER_BCCSP_PKCS11_PIN(compose-local-run-infra.yml:37) |
TLS_ENABLED / TLS_CLIENT_AUTH_REQUIRED | TLS / mTLS 开关 | cbdc-biz/.env.example、cbdc-network/.env.example |
OTLP_ENDPOINT | OpenTelemetry 接收端 | 各 core.yaml observability.tracing.endpoint |
mTLS 与节点身份
来源:cbdc-network/.env.example、cbdc-biz/app/bizhub/internal/server/grpc.go。
| 配置 | 值 | 出处 |
|---|---|---|
TLS_ENABLED | 默认 true | cbdc-network/.env.example |
TLS_CLIENT_AUTH_REQUIRED | 默认 true(mTLS) | 同 |
| 服务端 / 客户端证书 | 由 fabric-ca 签发 | sign-ca 镜像 + cbdc-tool 镜像辅助流程 |
私钥托管原则
业务身份私钥不落盘明文,而是经 PKCS#11 库 libkms_pkcs11.so 由 Sign-KMS 持有:CA 容器与各业务应用容器把 SIGN_KMS_ENDPOINT 注入容器 env,libkms_pkcs11.so 经 gRPC 调用 KMS,私钥不出 KMS(cbdc-biz/conf/issuer/core.yaml、cbdc-biz/conf/bizhub/core.yaml 等 core.yaml 的 PKCS#11 库配置;cbdc-biz/docker/Dockerfile)。
mTLS 入站 / 出站证书分离
Orderer 的本地配置区分入站(作为 server)与出站(作为 client)两段 TLS。字段定义见 fabric-x-orderer/config/local_config.go:106-137:
go
type TLSConfigYaml struct { // 入站角色(General.TLS)
PrivateKey string // 作为 server 出示
Certificate string
RootCAs []string // 出站时验对方 server cert
ClientAuthRequired bool // 要求 mTLS
ClientRootCAs []string // 验证入站客户端 cert
}
type ClusterYaml struct { // 出站角色(General.Cluster)
ClientCertificate string // 作为 client 出示给对端
ClientPrivateKey string
}sample 配置中入站段填相对路径 tls/server.key、tls/server.crt(fabric-x-orderer/config/sample/local_config.yaml:38-40),出站段(ClientCertificate / ClientPrivateKey)默认留空(local_config.yaml:103,106)。注释明确:出站缺省回退到入站证书 —— "If not set, the server General.TLS.Certificate is re-used"(local_config.go:133,136)。
mTLS 的"双向"指互相验证,不是互相身份:TCP 建立后谁 Dial 是 client、谁 Accept 是 server 已定死,每端各出示自己的一张证书。
committer sidecar 支持动态 TLS 热加载:监听 config block 后调 updateDynamicTLS 替换证书(fabric-x-committer/service/sidecar/sidecar.go:451)。
BizHub 服务端启用 RequireClientCert 时,MTLSInstitutionMiddleware 从客户端证书提取 institution_code 写入 context(cbdc-chain/apps/bizhub · service)。
X.509 / Idemix 两种凭证
来源:fabric-ca · 概述、cbdc-biz/conf/*/core.yaml 中的 token.tms.mytms.driver: zkatdlog。
| 凭证 | 用途 | 谁签发 |
|---|---|---|
| X.509 | MSP 身份、mTLS、Token SDK FabToken 驱动 owner | fabric-ca |
| Idemix | 隐私凭证(zkatdlog 选用时叠加 owner 匿名) | fabric-ca Idemix issuer |
cbdc-chain 默认 token 驱动:zkatdlog(cbdc-biz/conf/endorser1/core.yaml 中 token.tms.mytms.driver,详见 endorser app · configs)。
失效与撤销
| 机制 | 实现位置 |
|---|---|
| KMS access token 即时禁用 | sign-kms 端:DB access_token.status 置 disabled(sign-kms/internal/data/ent/schema/access_token.go:40-43),auth 中间件拒绝该 JWT(sign-kms/pkg/auth/grpc_auth.go:70) |
| X.509 吊销 | fabric-ca · revoke 端点 |
| 撤销列表内存缓存 | cbdc-biz/pkg/common/revocation/cache.go(refreshInterval = 30s,auditor · 包引用) |
一键启动中的 KMS 初始化
来源:cbdc-chain/scripts/start-kms-system.sh(cbdc-chain · 03 快速开始)。
脚本主要 flag(parse_args):
--skip-build— 跳过镜像构建--quick— 快速重启:仅 teardown biz + network,跳过 setup,复用现有证书--local-kms— 本地启 KMS + CA 容器(用cbdc-biz/docker/compose-local-run-infra.yml),默认走远程cbdc-dev.sign.global--skip-rtgs— 跳过 RTGS Mock 启动--help/-h— 帮助
在 --local-kms 模式下,脚本会(apply_local_env + init_hsm_token):
- 覆写
cbdc-biz/.env与cbdc-network/.env中的SIGN_KMS_ENDPOINT/CA_URL/CA_HOST为host.docker.internal(供容器消费) - 启本地 KMS + CA 容器
- 用
admin/adminpw调POST /api/v1/signin拿 JWT(以 cookieaccess_token携带),再调/api/v1/create-ns(命名空间cbdcns_<时间戳>)与/api/v1/access-token(role: admin) - 把 access token 写回两份
.env的KMS_USER_PIN
Fabric-X 链上权限:5 道关卡
来源:以下各关卡的 :line 引用指向 fabric-x-orderer / fabric-x-committer 代码。
一句话现状:默认配置下,连得上 Router 的人就能往里灌业务交易;业务合法性的真正闸门在 Committer 的 namespace 背书策略;ConfigUpdate 强制走策略校验,但底层 MSP role 不被严格区分。
关卡 ①:mTLS 传输层
| 链路 | 状态 | 出处(fabric-x-orderer) |
|---|---|---|
| Router ↔ Batcher | mTLS 强制 | node/router/shard_router.go:97 RequireClientCert: true |
| Router ↔ Consenter | mTLS 强制 | node/router/config_submitter.go:216 RequireClientCert: true |
| Client ↔ Router | 可选 | — |
只证明"证书在受信 CA 内",没有把证书身份提取出来做业务鉴权。
关卡 ②:Router 业务交易过滤(默认裸奔)
出处:fabric-x-orderer/common/requestfilter/sigfilter.go:35-53。
go
if sf.clientSignatureVerificationRequired || reqType == HeaderType_CONFIG_UPDATE {
policy.EvaluateSignedData([]*protoutil.SignedData{signedData})
}clientSignatureVerificationRequired 默认 false(fabric-x-orderer/test/utils/utils.go:147, 267, 354)。打开方式(router/batcher 的 local_config.yaml,config/local_config.go:103):
yaml
General:
ClientSignatureVerificationRequired: true或 armageddon generate ... --clientSignatureVerificationRequired。
未开启时,Router 只做大小 / 结构过滤(SizeFilter),仅网络层 mTLS + 防火墙 + Committer 端背书三道防线。
关卡 ③:ConfigUpdate 强制校验
来源:fabric-x-orderer/node/router/stream.go:91-94 + node/router/config_submitter.go:114-157。
ConfigUpdate 强制路由到 ConfigSubmitter,做三步:
go
configRequest, _ := cs.configUpdateProposer.ProposeConfigUpdate(
tr.request, cs.bundle, cs.signer, cs.verifier) // 签名 + 通道策略
cs.configRulesVerifier.ValidateNewConfig(env, bccsp, partyID)
cs.configRulesVerifier.ValidateTransition(bundle, env, bccsp)ProposeConfigUpdate(接口声明 common/policy/policy.go:28)经 AuthorizeAndVerifyConfigUpdate 调经典 Fabric bundle.ConfigtxValidator().ProposeConfigUpdate()(policy.go:100)按通道配置树评估:
/Channel/Admins ImplicitMeta MAJORITY Admins
/Channel/Orderer/Admins ImplicitMeta MAJORITY Admins
/Channel/Application/Admins ImplicitMeta MAJORITY Admins缺陷
configtx 中 OR('Org1MSP.admin') 这种 role 语法当前 fabric-x 实现里 role 不强制 —— 全代码搜不到 MSPRoleType_ADMIN 的使用,组织私钥就能满足策略,无论是 endorser cert 还是 admin cert。
关卡 ④:Committer namespace 背书校验(业务合法性的真正闸门)
来源:fabric-x-committer/service/verifier/verify.go:125-167。
go
nsVerifier, ok := verifiers[ns.NsId] // 按 namespace ID 查策略
if !ok {
response.Status = ABORTED_SIGNATURE_INVALID
return
}
nsVerifier.VerifyNs(tx.Ref.TxId, tx.Content, nsIndex)
└─ p.EvaluateSignedData(signedData) // utils/signature/verify.go:186策略类型分派见 NewNsVerifier 的 switch(fabric-x-committer/utils/signature/verify.go:64-68);ThresholdRule / MspRule 是 applicationpb.NamespacePolicy 的 oneof 成员,ChannelPolicy 经 NewNsVerifierFromChannelPolicy(verify.go:86)构造:
| 类型 | 含义 | 适用 |
|---|---|---|
ThresholdRule | 单公钥(ECDSA / BLS / EdDSA),1 签即过 | 简单、高性能 |
MspRule | Fabric DSL:OR('Org1MSP.member', ...) / AND / OutOf(n, ...) | 多组织 |
ChannelPolicy | 走 /Channel/Application/LifecycleEndorsement | meta-namespace / 配置变更 |
特点:
- 每个 namespace 一套策略,不是通道级一刀切
- 创建 namespace 时必须显式指定策略,否则整个 namespace 写不进去
- 跨 namespace 交易:每个 namespace 的签名集合独立满足自身策略
关卡 ⑤:策略热加载(meta-namespace + VerifierUpdates)
更新策略本身是一笔写入 meta-namespace(committerpb.MetaNamespaceID)的交易:
fxconfig namespace create ns1 \
--policy="OR('Org1MSP.member', 'Org2MSP.member')" \
--endorse --submit --waitCommitter 落账后通过 VerifierUpdates proto(servicepb/verifier.proto:28)广播给 Verifier,Verifier 用 atomic pointer 替换 verifiers map,无锁热加载。
ConfigUpdate 完整鉴权链路
已知缺陷与生产化加固
缺陷清单
| # | 问题 | 影响 | 出处 |
|---|---|---|---|
| 1 | ClientSignatureVerificationRequired 默认 false | Router 不挡身份,DoS 面 + 攻击面扩大 | fabric-x-orderer/test/utils/utils.go:147 |
| 2 | MSP role 不强制 | endorser 私钥可冒充 admin 签 ConfigUpdate | 全代码无 MSPRoleType_ADMIN 使用 |
| 3 | TLS 证书未做身份提取 | mTLS 仅做连通性证明,不做调用方授权 | node/router/shard_router.go:76-118 |
| 4 | 无 gRPC 拦截器 RBAC | SubmitConfig / Broadcast 任何 mTLS 客户端可调 | 各 service 注册处 |
| 5 | 缺操作审计日志 | 配置变更事后追责困难 | node/router/config_submitter.go |
| 6 | 签名证书轮换需重启 | 不能完全热更 | fabric-x-orderer/config/reconfig.go:96 TODO |
生产化加固(按优先级)
| 优先级 | 动作 | 改动量 | 收益 |
|---|---|---|---|
| P0 | 配置开启 ClientSignatureVerificationRequired: true | 1 行 | Router 层挡住非授权身份 |
| P0 | 部署层网络隔离(Router 端口仅 SDK 网段;管控面仅堡垒机) | 网络配置 | 减少 mTLS 证书泄露后的攻击面 |
| P1 | 在 verify.go / signer.go 强制 MSP role:admin 操作必须 admincert | ~50 行 Go | endorser 与 admin 权限隔离 |
| P1 | gRPC 拦截器:从 mTLS 证书提取 mspid,针对管控接口做白名单 | ~100 行 Go | 限制谁能调 SubmitConfig |
| P2 | 操作审计:ConfigSubmitter 记录 (who, what, when, signature_set) | ~30 行 Go | 满足合规审计 |
| P2 | Admin 私钥 HSM / KMS 化(流程层) | 部署 + 流程 | 私钥防泄露 |
| P3 | 跟进上游补 sign cert 热轮换 | 上游协作 | 完全无重启 reconfig |
安全姿态对比
| 配置 | Router | Committer | ConfigUpdate | 适用 |
|---|---|---|---|---|
| 默认 | 不挡 | 严格按 namespace 策略 | 强制(role 不严) | 开发 / 测试 |
| 半开 | ClientSig=true | 严格 | 强制 | 准生产 / 单组织 |
[未核]
- 远程 / 生产部署中每个业务应用使用的 KMS namespace 精确名(运维侧配置;本地
--local-kms模式由脚本生成cbdcns_<时间戳>)。 - 多银行场景下每家 institution 的 namespace 命名规范。
- Idemix issuer key 的轮换 / 公开参数热升级协议(fabric-ca Idemix issuer 提供基础,但 cbdc-chain 侧编排 [未核])。
- 缺陷 #2 / #3 在 fabric-x 最新主干是否已修(基于 2026-04-21 调研)。