权限管理是区块链网络十分重要的功能,负责控制某个身份在某个场景下是否允许采取某个操作(如读写某个资源)。
超级账本 Fabric 项目通过策略(Policy)来灵活指定各场景下的操作权限。
策略应用场景
具体来看,常见的策略场景包括如下表所示。其中,大部分都与系统配置链码相关,可以在通道配置中进行指定;部分为代码中的规定。
对于存储在通道配置中的策略,可以利用 configtx.yaml 指定,在生成新建通道交易时初始化到通道配置内。
操作场景 | 相策略检查 | 相关实现文件 |
---|---|---|
调用 Broadcast() 接口向 Orderer 发送交易信息 | Orderer 会检查是否满足通道的 Writers 策略 | orderer/multichain/chainsupport.go |
调用 Deliver() 接口从 Orderer 获取区块结构 | Orderer 会检查是否满足通道的 Readers 策略 | orderer/common/deliver/deliver.go |
新建应用通道 | Orderer 会检查是否申请者满足系统通道的 Writers 策略 | orderer/multichain/chainsupport.go |
修改通道配置 | Orderer 会检查所有的修改项需满足对应的 modPolicy 策略,默认为 Admins | common/configtx/update.go |
Peer 加入应用通道 | 配置管理系统链码(CSCC)会检查申请者是否为某个 MSP 的管理员身份 | core/scc/cscc/configure.go |
Peer 获取所加入通道列表 | 配置管理系统链码(CSCC)会检查申请者是否为某个 MSP 的成员身份 | core/scc/cscc/configure.go |
获取某应用通道的区块 | 配置管理系统链码会检查是否满足应用通道的 Readers 策略 | core/scc/cscc/configure.go |
安装链码 | 链码生命周期管理系统链码(LSCC)会检查安装提案中签名者是否为本地 MSP 的 Admin 身份 | core/scc/lscc/lscc.go |
实例化部署链码 | 链码生命周期管理系统链码(LSCC)默认会检查提案者是否是通道内成员 | core/scc/lscc/lscc.go 和 core/committer/txvalidator/v20/plugindispatcher/dispatcher.go |
调用链码 | 背书节点在背书过程中会检查链码是否满足应用通道的 Writers 策略和 Readers 策略;确认节点也会检查交易是否满足背书策略 | core/endorser/endorser.go 和 core/scc/lscc/lscc.go |
Peer 通过 Gossip 协议获取到区块 | 对区块进行校验,检查需要满足 BlockValidation 策略 | peer/gossip/mcs.go |
监听事件 | Peer 会检查是否满足应用通道的 Readers 策略 | core/peer/deliverevents.go |
注:Readers、Writers、Admins、管理员、成员等都代表了一组事先定义的身份。
身份证书
实现权限管理的基础是身份证书机制。
通过基于 PKI 的成员身份管理,Fabric 网络可以对接入的节点和用户的各种能力进行限制。
Fabric 设计中考虑了三种类型的证书:登记证书(Enrollment Certificate)、交易证书(Transaction Certificate),以及保障通信链路安全的 TLS 证书。证书的默认签名算法为 ECDSA,Hash 算法为 SHA-256。
登记证书(ECert):颁发给提供了注册凭证的用户或节点等实体,代表网络中身份。一般长期有效。
交易证书(TCert):颁发给用户,控制每个交易的权限,不同交易可以不同,实现匿名性。短期有效。
通信证书(TLSCert):控制对网络层的接入访问,可以对远端实体身份进行校验,防止窃听。
目前,在实现上,主要通过 ECert 来对实体身份进行检验,通过检查签名来实现权限管理。TCert 功能暂未实现,用户可以使用 idemix 机制来实现部分匿名性。
身份集合
基于证书机制,Fabric 设计了身份集合(MSP Principal)来灵活标记一组拥有特定身份的个体,如下图所示。
对应的 MSP Principal 的数据结构如下图所示。
身份集合支持从不同维度上对身份进行分类:
Role:根据证书角色来区分,如 Admin、Member、Client、Peer 等;
OrganizationUnit:根据身份中的 OU 信息来区分,如某个特定部门。实际上 Client 和 Peer 角色也是通过证书中的 OU 域来指定的;
Identity:具体指定某个个体的证书,只有完全匹配才认为合法;
Anonymity:证书是否是匿名的,用于 idemix 类型的 MSP;
Combined:由其他多个子身份集合组成,需要符合所有的子集合才认为合法。
基于不同维度可以灵活指定符合某个身份的个体,例如某个 MSP 的特定角色(如成员或管理员),或某个 MSP 特定单位(OrganizationUnit),当然也可以指定为某个特定个体。
需要注意目前角色定义是在代码中实现。对于管理员角色,除安装链码操作是将签名的证书跟节点 msp/admincerts 路径下的证书列表进行查找匹配,其它操作依赖于通道配置中对应组织 MSP 结构中 MSP.value.admins 中定义;对于成员角色,则需要所签名证书是被节点同一 MSP 根签发即可。具体实现可参考 msp/mspimpl.go 文件中 satisfiesPrincipalInternal 相关方法。Client 和 Peer 角色认定则通过检查证书中 OU 域信息。
权限策略的实现
权限策略会具体指定可以执行某项操作的身份集合。
以通道相关的策略为例,一般包括对读操作(例如获取通道的交易、区块等数据)、写操作(例如向通道发起交易)、管理操作(例如加入通道、修改通道的配置信息)等进行权限限制。对策略自身的修改通过额外指定的修改策略(mod_policy)来进行管理。
操作者在发起操作时,其签名组合需要满足策略指定的身份结合规则,才可以被允许执行相应的操作。
实现上,每种策略结构都要实现 Evaluate(signatureSet []*cb.SignedData) error 方法。该方法中会对于给定的一组签名数据,按照给定规则进行检验,看是否符合约定的条件。符合则说明满足了该策略;反之则拒绝。
策略相关数据结构
策略相关的数据结构定义在 protos/common/policies.proto 文件中,其中主要包括 Policy、SignaturePolicyEnvelope(内嵌 SignaturePolicy 结构)和 ImplicitMetaPolicy 三种数据结构,如下图所示。
Policy 消息的定义如下。
message Policy {
enum PolicyType {
UNKNOWN = 0; // 初始化保留类型
SIGNATURE = 1; // 简单基于签名的规则
MSP = 2; // 基于 MSP
IMPLICIT_META = 3; // 隐式规则
}
int32 type = 1; //类型
bytes value = 2; //规则}
其中,PolicyType 的数值代表策略的类型,具体含义为:
1.UNKNOWN:保留值,用于初始化;
2.SIGNATURE:通过匹配基于签名的组合,如某个 MSP 中至少三个签名;
3.MSP:代表策略必须要匹配某 MSP 下的指定身份身份,如 MSP 的管理员身份;
4.IMPLICIT_META:隐式类型,包括若干子策略,并通过 Rule 来指定具体的规则,包括 ANY、ALL、MAJORITY 三种。
ANY:满足任意子组的对应策略。
ALL:满足所有子组的对应策略。
MAJORITY:满足大多数(过半)子组的对应策略。
目前已经实现支持的策略类型主要包括 SignaturePolicy 和 ImplicitMetaPolicy 两种。
SIGNATURE 策略
SIGNATURE 策略指定通过签名来对数据进行认证,例如必须满足给定身份的签名组合,结构如下图所示。
相关数据结构主要包括 SignaturePolicy 消息体和封装后使用的 SignaturePolicyEnvelope,两者定义如下所示。
message SignaturePolicy {
message NOutOf {
int32 n = 1;
repeated SignaturePolicy rules = 2;
}
oneof Type {
int32 signed_by = 1; // 指定所需签名者在身份集合列表中的序号
NOutOf n_out_of = 2;
}
}
type SignaturePolicyEnvelope struct {
Version int32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"`
Rule *SignaturePolicy `protobuf:"bytes,2,opt,name=policy" json:"policy,omitempty"`
Identities []*common1.MSPPrincipal `protobuf:"bytes,3,rep,name=identities" json:"identities,omitempty"`
}
其中,SignaturePolicy 结构体代表了一个策略的规则(Rule)。支持指定某个特定签名,或者满足给定策略集合中的若干个(NOutOf)即可。NOutOf 用法十分灵活,基于它可以递归地构建任意复杂的策略语义,指定多个签名规则的与、或组合关系。
SignaturePolicyEnvelope 结构体代表了一个完整的策略,包括版本号(Version)、策略规则(Rule)和策略关联的身份集合(Identities)。
例如,某个策略要求满足 MP1 身份集合中签名,或者 MP2 集合和 MP3 集合同时签名,则可以表达为 MP1 || (MP2 && MP3))。对应的策略结构如下所示。
SignaturePolicyEnvelope{
version: 0,
rule: SignaturePolicy{
n_out_of: NOutOf{
N: 1,
rules: [
SignaturePolicy{ signed_by: 0 },
SignaturePolicy{
n_out_of: NOutOf{
N: 2,
rules: [
SignaturePolicy{ signed_by: 1 },
SignaturePolicy{ signed_by: 2 },
],
},
},
],
},
},
identities: [MP1, MP2, MP3] // 身份集合列表
}
需要注意,对签名策略的匹配过程是顺序敏感的(参考 FAB-4749)。进行策略检查时,给定的多个签名会依次按照策略顺序依次跟身份集合进行匹配,签名一旦匹配则会被消耗掉,再检查下一个签名。例如上述例子中,假如 MP1 代表组织 A 的管理员,MP2 代表组织 B 的成员,MP3 代表组织 B 的管理员,那么对于签名组合 [S1={组织 B 的管理员},S2={组织 B 的成员}],并不会匹配成功。因为,S1 在匹配 MP2 后会被消耗掉,剩下的 S2 在匹配 MP3 时会失败。为了避免这种情况,进行签名时要将优先级较低的签名放到前面,比如代表成员身份的签名应当放到管理员身份前。同时,对于策略的身份集合列表,则应该将高优先级的放到前面。
对于策略的检查主要实现在 msp/mspimpl.go 代码文件的 SatisfiesPrincipal(id Identity, principal *m.MSPPrincipal) error 方法中。
IMPLICIT_META 策略
IMPLICIT_META 策略并不直接进行签名检查,而是通过引用其它子策略(最终还是通过 SIGNATURE 策略)来实现。检查结果通过策略规则来进行约束,如下图所示。
相关的结构体主要为 ImplicitMetaPolicy(位于 protos/common/policies.proto),定义如下。
message ImplicitMetaPolicy {
enum Rule {
ANY = 0; // 任意子策略被满足即可
ALL = 1; // 所有的子策略都必须被满足
MAJORITY = 2; // 超过一半的子策略被满足
}
string sub_policy = 1; // 在子元素中查找的子策略类型名称
Rule rule = 2; //限制规则类型}
其中,sub_policy 限定查找的子策略的类型(Readers、Writers、Admins 或自定义),rule 指定约束的规则类型。
例如,对于应用通道,如果包括两个组织 Org1 和 Org2,那么如下的通道读策略(/Channel/Application/Reader)实际上意味着 Org1 和 Org2 中任意读权限的拥有者都对拥有通道读权限。
ImplicitMetaPolicy{
sub_policy: "Readers",
rule: ANY,
}
Org1 和 Org2 可以在各自结构中具体规定 Readers 策略的具体内容,如默认的为任意合法成员即可。
通道策略
权限策略的主要应用场合之一便是通道策略(Channel Policy)。通道策略采用了层级化树形结构,最上层为 /Channel 组,下面是各级子组。在每一级别都可以指定策略,作为本层级的默认策略。
通道配置可以包括联盟组(仅当系统通道,包括联盟组织信息)、应用组(一般仅当应用通道,包含使用通道的组织信息)和排序组(包括排序组织信息)等不同的元素。
一个典型的例子如下图所示,包括一个排序组织和一个应用组织。
默认情况下,通道内的策略如下所示。
# 通道默认全局策略
/Channel/Readers: ImplicitMetaPolicy-ANY Readers
/Channel/Writers: ImplicitMetaPolicy-ANY Writers
/Channel/Admins : ImplicitMetaPolicy-MAJORITY Admins
# 通道内应用组默认策略(仅当应用通道)
/Channel/Application/Readers: ImplicitMetaPolicy-ANY Readers
/Channel/Application/Writers: ImplicitMetaPolicy-ANY Writers
/Channel/Application/Admins : ImplicitMetaPolicy-MAJORITY Admins
/Channel/Application/Endorsement: ImplicitMetaPolicy-MAJORITY Endorsement
/Channel/Application/LifecycleEndorsement: ImplicitMetaPolicy-MAJORITY LifecycleEndorsement
# 通道内应用组各组织的默认策略(仅当应用通道)
/Channel/Application/Org/Readers: SignaturePolicy for 1 of Org Member
/Channel/Application/Org/Writers: SignaturePolicy for 1 of Org Member
/Channel/Application/Org/Admins : SignaturePolicy for 1 of Org Admin
/Channel/Application/Org/Endorsement: SignaturePolicy for 1 of Org Member
# 通道内排序组的默认策略
/Channel/Orderer/Readers: ImplicitMetaPolicy-ANY Readers
/Channel/Orderer/Writers: ImplicitMetaPolicy-ANY Writers
/Channel/Orderer/Admins : ImplicitMetaPolicy-MAJORITY Admins
/Channel/Orderer/BlockValidation : ImplicitMetaPolicy-ANY Writers
# 通道内排序组中各组织的默认策略
/Channel/Orderer/Org/Readers: SignaturePolicy for 1 of Org Member
/Channel/Orderer/Org/Writers: SignaturePolicy for 1 of Org Member
/Channel/Orderer/Org/Admins : SignaturePolicy for 1 of Org Admin
# 通道内联盟组的默认策略(仅当系统通道)
/Channel/Consortiums/Admins: SignaturePolicy for ANY
# 通道内联盟组中某联盟的默认策略(仅当系统通道)
/Channel/Consortiums/Consortium
/ChannelCreationPolicy: ImplicitMetaPolicy-ANY for Admin
# 通道内联盟组中某联盟组织的默认策略(仅当系统通道)
/Channel/Consortiums/Consortium/Org/Readers: SignaturePolicy for 1 of Org Member: ImplicitMetaPolicy-ANY for Admin
/Channel/Consortiums/Consortium/Org/Writers: SignaturePolicy for 1 of Org Member
/Channel/Consortiums/Consortium/Org/Admins : SignaturePolicy for 1 of Org Admin
背书策略
用户在实例化链码时,可以指定背书策略(Endorsement Policy)。
背书策略采用了 SignaturePolicy 结构进行指定,同样可以利用身份集合结构构建十分灵活的签名校验组合。
例如,指定某几个组织内的任意成员身份进行背书,或者至少有一个管理员身份进行背书等。
语法上,背书策略支持通过 -P 指定哪些 SignaturePolicy 会被需要;通过 -T 指定所需要的 SignaturePolicy 个数。
目前,客户端已经实现了对背书策略的初步支持,通过 -P 来指定通过 AND、OR 组合的成员身份(admin,member)集合。
下面的命令可以指定要么 Org1 的管理员进行背书,或者 Org2 和 Org3 的成员同时进行背书,才满足背书策略。
OR('Org1.admin', AND('Org2.member', 'Org3.member'))
背书策略的检查发生在 Peer 提交区块阶段,位于 core/committer/txvalidator/v20/plugindispatcher/dispatcher.go。
实例化策略
实例化策略(Instantiation Policy)一般用于最终确认阶段,Committer 利用 VSCC 对网络中进行链码部署的操作进行权限检查。
目前,实例化策略同样采用了 SignaturePolicy 结构进行指定,可以基于身份集合结构构建复杂的签名校验组合。
默认情况下,会以当前 MSP 的管理员身份作为默认的策略,即只有当前 MSP 管理员可以进行链码实例化操作。这可以避免链码被通道中其他组织成员私自在其它通道内进行实例化。
实例化策略的检查发生在 Peer 的背书阶段,位于 core/endorser/endorser.go。
————————————————
原文链接:https://blog.csdn.net/yeasy/article/details/88536882