Skip to content

02 · 信任与身份模型

三件套:fabric-ca + sign-ca + sign-kms

来源:cbdc-biz/.env.examplecbdc-network/.env.examplecbdc-biz/conf/*/core.yaml、相关包 wiki。

每个组件的详情:

KMS namespace 与 access token

来源:cbdc-biz/.env.examplecbdc-chain/scripts/start-kms-system.shsign-kms · 核心流程

关键事实:

  • KMS_TOKEN_LABEL(默认值 KMS_TK)是 sign-ca / sign-kms 约定的 PKCS#11 token label(cbdc-biz/.env.examplecbdc-biz/conf/bizhub/core.yaml:45)。
  • KMS_USER_PIN 是 access token JWT,作为 PKCS#11 pin 使用:CA 容器把它注入为 FABRIC_CA_SERVER_BCCSP_PKCS11_PINcbdc-biz/docker/compose-local-run-infra.yml:37);各业务应用容器以 KMS_USER_PIN 透传(compose-local-run.yml)。
  • KMS 三角色:readonly / readwrite / adminsign-kms · API)。

环境变量注入链路

来源:cbdc-biz/.env.examplecbdc-biz/docker/compose-local-run.ymlcbdc-network/.env.example

cbdc-biz/.env.example 中的关键变量(每条均有 ${...} 形式被 compose 或 yaml 引用):

变量用途出现位置
BIZHUB_ADDR下游应用回调 BizHubcbdc-biz/conf/{endorser1,issuer,auditor,institution-001}/core.yaml biz.bizhub_addr
UPSTREAM_ISSUER_ADDRBizHub → Issuercbdc-biz/conf/bizhub/core.yaml:75 upstream.issuer.addr
INSTITUTION_001_ADDRBizHub → 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_ENDPOINTKMS gRPC 地址CA / 业务应用容器 env,被 libkms_pkcs11.so 读取
KMS_USER_PINPKCS#11 pin(JWT)CA 容器注入为 FABRIC_CA_SERVER_BCCSP_PKCS11_PINcompose-local-run-infra.yml:37
TLS_ENABLED / TLS_CLIENT_AUTH_REQUIREDTLS / mTLS 开关cbdc-biz/.env.examplecbdc-network/.env.example
OTLP_ENDPOINTOpenTelemetry 接收端core.yaml observability.tracing.endpoint

mTLS 与节点身份

来源:cbdc-network/.env.examplecbdc-biz/app/bizhub/internal/server/grpc.go

配置出处
TLS_ENABLED默认 truecbdc-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.yamlcbdc-biz/conf/bizhub/core.yamlcore.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.keytls/server.crtfabric-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.509MSP 身份、mTLS、Token SDK FabToken 驱动 ownerfabric-ca
Idemix隐私凭证(zkatdlog 选用时叠加 owner 匿名)fabric-ca Idemix issuer

cbdc-chain 默认 token 驱动:zkatdlogcbdc-biz/conf/endorser1/core.yamltoken.tms.mytms.driver,详见 endorser app · configs)。

失效与撤销

机制实现位置
KMS access token 即时禁用sign-kms 端:DB access_token.statusdisabledsign-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.gorefreshInterval = 30sauditor · 包引用

一键启动中的 KMS 初始化

来源:cbdc-chain/scripts/start-kms-system.shcbdc-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):

  1. 覆写 cbdc-biz/.envcbdc-network/.env 中的 SIGN_KMS_ENDPOINT / CA_URL / CA_HOSThost.docker.internal(供容器消费)
  2. 启本地 KMS + CA 容器
  3. admin/adminpwPOST /api/v1/signin 拿 JWT(以 cookie access_token 携带),再调 /api/v1/create-ns(命名空间 cbdcns_<时间戳>)与 /api/v1/access-tokenrole: admin
  4. 把 access token 写回两份 .envKMS_USER_PIN

Fabric-X 链上权限:5 道关卡

来源:以下各关卡的 :line 引用指向 fabric-x-orderer / fabric-x-committer 代码。

一句话现状:默认配置下,连得上 Router 的人就能往里灌业务交易;业务合法性的真正闸门在 Committer 的 namespace 背书策略;ConfigUpdate 强制走策略校验,但底层 MSP role 不被严格区分。

关卡 ①:mTLS 传输层

链路状态出处(fabric-x-orderer)
Router ↔ BatchermTLS 强制node/router/shard_router.go:97 RequireClientCert: true
Router ↔ ConsentermTLS 强制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 默认 falsefabric-x-orderer/test/utils/utils.go:147, 267, 354)。打开方式(router/batcher 的 local_config.yamlconfig/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 / MspRuleapplicationpb.NamespacePolicy 的 oneof 成员,ChannelPolicyNewNsVerifierFromChannelPolicyverify.go:86)构造:

类型含义适用
ThresholdRule单公钥(ECDSA / BLS / EdDSA),1 签即过简单、高性能
MspRuleFabric DSL:OR('Org1MSP.member', ...) / AND / OutOf(n, ...)多组织
ChannelPolicy/Channel/Application/LifecycleEndorsementmeta-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 --wait

Committer 落账后通过 VerifierUpdates proto(servicepb/verifier.proto:28)广播给 Verifier,Verifier 用 atomic pointer 替换 verifiers map,无锁热加载

ConfigUpdate 完整鉴权链路

已知缺陷与生产化加固

缺陷清单

#问题影响出处
1ClientSignatureVerificationRequired 默认 falseRouter 不挡身份,DoS 面 + 攻击面扩大fabric-x-orderer/test/utils/utils.go:147
2MSP role 不强制endorser 私钥可冒充 admin 签 ConfigUpdate全代码无 MSPRoleType_ADMIN 使用
3TLS 证书未做身份提取mTLS 仅做连通性证明,不做调用方授权node/router/shard_router.go:76-118
4无 gRPC 拦截器 RBACSubmitConfig / Broadcast 任何 mTLS 客户端可调各 service 注册处
5缺操作审计日志配置变更事后追责困难node/router/config_submitter.go
6签名证书轮换需重启不能完全热更fabric-x-orderer/config/reconfig.go:96 TODO

生产化加固(按优先级)

优先级动作改动量收益
P0配置开启 ClientSignatureVerificationRequired: true1 行Router 层挡住非授权身份
P0部署层网络隔离(Router 端口仅 SDK 网段;管控面仅堡垒机)网络配置减少 mTLS 证书泄露后的攻击面
P1verify.go / signer.go 强制 MSP role:admin 操作必须 admincert~50 行 Goendorser 与 admin 权限隔离
P1gRPC 拦截器:从 mTLS 证书提取 mspid,针对管控接口做白名单~100 行 Go限制谁能调 SubmitConfig
P2操作审计:ConfigSubmitter 记录 (who, what, when, signature_set)~30 行 Go满足合规审计
P2Admin 私钥 HSM / KMS 化(流程层)部署 + 流程私钥防泄露
P3跟进上游补 sign cert 热轮换上游协作完全无重启 reconfig

安全姿态对比

配置RouterCommitterConfigUpdate适用
默认不挡严格按 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 调研)。