Hyperledger Fabric 權限策略和訪問控制
訪問控制是區塊鏈網絡十分重要的功能,負責控制某個身份在某個場景下是否允許採取某個操作(如讀寫某個資源)。
常見的訪問控制模型包括強制訪問控制(Mandatory Access Control)、自主訪問控制(Discretionary Access Control)、基於角色的訪問控制(Role BasedAccess Control)和基於屬性的訪問控制(Attribute Based Access Control)。功能越強大的模型,實現起來往往越複雜。
Fabric通過權限策略和訪問控制列表(ACL)機制實現了基於角色的訪問控制模型,可以滿足通道內資源訪問、背書控制或鏈碼調用控制等多個場景下的需求。
應用場景
訪問場景包括採用不同策略(如通道策略、節點策略、背書策略等),按照訪問控制列表(如要求身份爲Admins、Writers等)對某資源的特定操作進行限制。
身份證書
實現權限策略的基礎是身份,身份的實現依賴證書機制。通過基於PKI的成員身份管理,Fabric網絡可以對網絡內的資源和接入用戶的各種能力進行限制。
Fabric最初設計中考慮了三種類型的證書:登記證書(Enrollment Certificate)、交易證書(Transaction Certif icate),以及保障通信鏈路安全的TLS證書。證書的默認簽名算法爲ECDSA,Hash算法爲SHA-256。
●登記證書(ECert):頒發給提供了註冊憑證的用戶或節點等實體,代表網絡中身份。可以長期有效。
●交易證書(TCert):頒發給用戶,控制每個交易的權限,不同交易可以不同,實現匿名性,短期有效。暫未實現。
●通信證書(TLSCert):控制對網絡層的接入訪問,可以對遠端實體身份進行校驗,防止竊聽。可以長期有效。
目前,在實現上,主要通過ECert來對實體身份進行檢驗,通過檢查簽名來實現權限管理。TCert功能暫未實現,用戶可以使用idemix機制來實現部分匿名性。
身份集合
基於證書機制,Fabric設計了身份集合(MSPPrincipal)來靈活標記一組擁有特定身份的個體.
對應的MSPPrincipal的數據結構:
身份集合支持從以下不同維度對身份進行分類。
●Role:根據證書角色來區分,如Member、Admin、Client、Peer、Orderer等。
●OrganizationUnit:根據身份證書中指定的OU信息來區分。
●Identity:具體指定某個個體的證書,只有完全匹配才認爲合法。
●Anonymity:證書是否是匿名的,用於idemix類型的MSP。
●Combined:由其他多個子身份集合組成,需要符合所有的子集合才認爲合法。
基於不同維度可以靈活指定符合某個身份的個體,例如,某個MSP的特定角色(如成員或管理員),或某個MSP的特定單位(OrganizationUnit),當然也可以指定爲某個特定個體。
注意,目前對不同角色的認可採取不同方法。對於管理員角色,會認可本地msp/admincerts路徑下的證書列表或證書帶有代表管理員角色的OU信息;Client、Peer、Orderer等角色則需要查看證書是否帶有對應的OU域;對於成員角色,則需要證書是由對應組織根證書籤發。
權限策略的實現
權限策略指定了可以執行某項操作的身份集合。以通道相關的策略爲例,一般包括對讀操作(例如獲取通道的交易、區塊等數據)、寫操作(例如向通道發起交易)、管理操作(例如加入通道、修改通道的配置信息)等進行權限限制。對策略配置自身的修改是通過額外指定的修改策略(mod_policy)來實現的。
操作者在發起操作時,其請求中籤名組合只有滿足策略指定的身份規則,才允許執行。實現上,每種策略結構都要實現Policy接口。對於給定的一組簽名數據或身份,按照給定規則進行檢驗,看是否符合約定的條件。符合則說明滿足了該策略;反之則拒絕。
數據結構
策略相關的數據結構定義在fabric-protos-go項目的common/policies.pb.go文件中,其中主要包括Policy、SignaturePolicyEnvelope(內嵌SignaturePolicy結構)和ImplicitMetaPolicy三種數據結構,如圖14-20所示。
其中,Type的數值代表策略的類型,具體含義爲:
●UNKNOWN,保留值,用於初始化。
●SIGNATURE,通過匹配基於簽名的組合,如某個MSP中至少有三個簽名。
●MSP,代表策略必須匹配某MSP下的指定身份,如MSP的管理員身份。
●IMPLICIT_META,隱式類型,包括若干子策略,並通過Rule來指定具體的規則,包括ANY、ALL、MAJORITY三種,僅用於通道配置內標記通道規則。
目前已經實現支持的策略類型主要包括SIGNATURE策略和IMPLICIT_META策略兩種。
SIGNATURE策略
SIGNATURE策略指定通過簽名來對數據進行認證,例如,必須滿足給定身份的簽名組合
其中,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] // 身份集合列表
}
// github.com/hyperledger/fabric-protos-go/common/policies.pb.go
type ImplicitMetaPolicy struct {
SubPolicy string // 子策略類型名稱,如 Readers、Writers、Admins
Rule ImplicitMetaPolicy_Rule // 子策略的匹配條件,可以爲 ANY、ALL、MAJORITY
}
ImplicitMetaPolicy{
sub_policy: "Readers",
rule: ANY,
}
需要注意,對簽名策略的匹配過程是順序敏感的(參考FAB-4749)。進行策略檢查時,給定的多個簽名會按照策略順序依次與身份集合進行匹配,簽名一旦匹配則會被消耗掉,再檢查下一個簽名。例如上述例子中,假如MP1代表組織A的管理員,MP2代表組織B的成員,MP3代表組織B的管理員,那麼對於簽名組合[S1={組織B的管理員},S2={組織B的成員}],並不會匹配成功。因爲,S1在匹配MP2後會被消耗掉,剩下的S2在匹配MP3時會失敗。爲了避免這種情況,進行簽名時要將優先級較低的簽名放到前面,比如代表成員身份的簽名應當放到管理員身份前。同時,對於策略的身份集合列表,則應該將高優先級的放到前面。
IMPLICIT_META策略
IMPLICIT_META策略用於通道配置,它並不直接進行簽名檢查,而是通過引用其他子策略(最終還是通過SIGNATURE策略)來實現。檢查結果通過策略規則進行約束。
通道策略
權限策略的主要應用場景之一便是通道策略。通道策略採用了層級化樹形結構,最上層爲/Channel組,下面是各級子組。在每一級別都可以指定策略,作爲本層級的默認策略。
通道配置可以包括聯盟組(僅當系統通道,包括聯盟組織信息)、應用組(一般僅當應用通道,包含使用通道的組織信息)和排序組(包括排序組織信息)等不同的元素。
一個典型的應用通道的例子如圖14-23所示,包括一個排序組和一個應用組。
默認情況下,通道內的策略使用的角色定義如下:
# 通道全局策略
/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
其中,通道內的元素,默認對其進行修改的策略(mod_policy)爲Admins;與排序相關的配置的修改策略則指定爲/Channel/Orderer/Admins,主要包括系統通道內相關配置,如Orderer-Addresses、Consortiums和具體的聯盟配置。
另外,應用通道的策略會考慮最新配置中的Orderer組和Application組;系統通道的策略會考慮最新配置中的Orderer組和Consortiums組。新建應用通道時,用戶需要指定Application組配置,如果不指定Orderer組配置,會自動從系統通道中繼承過來。
通道訪問控制
目前,Fabric中大多數的訪問權限通過通道訪問控制列表來指定。訪問控制列表位於通道配置中,被通道內所有成員認可。可以在新建通道時利用conf igtx.yaml指定,也可以後期通過配置更新進行變更。訪問控制列表配置示例如下,包括訪問控制列表和其引用的策略:
Application: &ApplicationDefaults
ACLs: &ACLsDefault
# Lifecycle 方法調用權限:CheckCommitReadiness()、CommitChaincodeDefinition()、
QueryChaincodeDefinition()、QueryChaincodeDefinitions()
_lifecycle/CheckCommitReadiness: /Channel/Application/Writers
_lifecycle/CommitChaincodeDefinition: /Channel/Application/Writers
_lifecycle/QueryChaincodeDefinition: /Channel/Application/Readers
_lifecycle/QueryChaincodeDefinitions: /Channel/Application/Readers
# LSCC 方法調用權限:getid()、getdepspec()、getccdata()、getchaincodes()
lscc/ChaincodeExists: /Channel/Application/Readers
lscc/GetDeploymentSpec: /Channel/Application/Readers
lscc/GetChaincodeData: /Channel/Application/Readers
lscc/GetInstantiatedChaincodes: /Channel/Application/Readers
# QSCC 方法調用權限:GetChainInfo()、GetBlockByNumber()、GetBlockByHash()、
GetTransactionByID()、GetBlockByTxID()
qscc/GetChainInfo: /Channel/Application/Readers
qscc/GetBlockByNumber: /Channel/Application/Readers
qscc/GetBlockByHash: /Channel/Application/Readers
qscc/GetTransactionByID: /Channel/Application/Readers
qscc/GetBlockByTxID: /Channel/Application/Readers
# CSCC 方法調用權限:GetConfigBlock()
cscc/GetConfigBlock: /Channel/Application/Readers
# 通道內鏈碼調用權限(向 Peer 發送背書請求)
peer/Propose: /Channel/Application/Writers
# 通道內跨鏈碼調用權限
peer/ChaincodeToChaincode: /Channel/Application/Readers
# 接收區塊事件權限
event/Block: /Channel/Application/Readers
# 接收過濾區塊事件權限
event/FilteredBlock: /Channel/Application/Readers
# 默認應用通道內組織成員爲空
Organizations:
# 通道內相關的策略,可被 ACL 中引用,用戶也可以自定義全局策略
Policies: &ApplicationDefaultPolicies
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
# 引用應用通道默認的能力集合
Capabilities:
<<: *ApplicationCapabilities
目前通道配置支持的資源訪問權限總結如表:
資源訪問 | 權限 | 功能 |
---|---|---|
Lifecycle/InstallChaincode | 本 MSP Admins | 安裝鏈碼 |
Lifecycle/QueryInstalledChaincode | 本 MSP Admins | 查詢已安裝的鏈碼信息 |
Lifecycle/GetInstalledChaincodePackage | 本 MSP Admins | 獲取鏈碼安裝包 |
Lifecycle/QueryInstalledChaincodes | 本 MSP Admins | 查詢所有已安裝鏈碼列表 |
Lifecycle/ApproveChaincodeDefinitionForMyOrg | 本 MSP Admins | 本 MSP Admins |
Lifecycle/CommitChaincodeDefinition | 通道 Writers | 提交鏈碼定義 |
Lifecycle/QueryChaincodeDefinition | 通道 Writers | 查詢指定的已提交鏈碼定義 |
Lifecycle/CheckCommitReadiness | 通道 Writers | 檢查鏈碼定義提交狀態 |
Lscc/Install | 本 MSP Admins | 傳統安裝鏈碼 |
Lscc/GetInstalledChaincodes | 本 MSP Admins | 傳統獲取安裝鏈碼列表 |
Lscc/Deploy | 通道 Writers | 傳統實例化鏈碼 |
Lscc/Upgrade | 通道 Writers | 傳統升級鏈碼 |
Lscc/ChaincodeExists | 通道 Readers | 檢查鏈碼是否安裝 |
Lscc/GetDeploymentSpec | 通道 Readers | 獲取安裝包 |
Lscc/GetChaincodeData | 通道 Readers | 獲取鏈碼完整數據包 |
Lscc/GetInstantiatedChaincodes | 通道 Readers | 獲取已實例化鏈碼列表 |
Lscc/GetCollectionsConfig | 通道 Readers | 獲取私有數據集合配置 |
Qscc/GetChainInfo | 通道 Readers | 查詢通道信息 |
Qscc/GetBlockByNumber | 通道 Readers | 獲取指定序號區塊 |
Qscc/GetBlockByHash | 通道 Readers | 獲取指定 hash 區塊 |
Qscc/GetTransactionByID | 通道 Readers | 獲取指定 ID 交易 |
Qscc/GetBlockByTxID | 通道 Readers | 獲取包括指定交易的區塊 |
Qscc/JoinChain | 通道 Readers | 加入通道 |
Qscc/GetChannels | 通道 Readers | 獲取已加入的通道列表 |
Qscc/GetConfigBlock | 通道 Readers | 獲取配置區塊 |
Peer/Propose | 通道 Writers | 調用鏈碼 |
Peer/ChaincodeToChaincode | 通道 Writers | 跨鏈碼調用 |
Event/Block | 通道 Readers | 監聽完整區塊事件 |
Event/FilteredBlock | 通道 Readers | 監聽過濾區塊事件 |
背書策略
鏈碼背書策略
用戶在批准執行鏈碼(2.0版本之前爲實例化鏈碼)時,可以指定調用該鏈碼需要滿足的背書策略(Endorsement Policy)並存放到鏈碼定義中。當對鏈碼的調用交易被提交時,Peer會檢查是否交易攜帶了符合指定背書策略的簽名信息。
背書策略可以採用SignaturePolicy或ChannelConf igPolicy兩種方式進行指定,構建十分靈活的策略組合。SignaturePolicy方式指定使用特定身份簽名組合來進行背書。例如,指定某幾個組織內的任意成員身份進行背書,或者至少有一個管理員身份進行背書等。
語法上,背書策略通過-P指定需要哪些SignaturePolicy;通過-T指定所需要的Signature-Policy個數。目前,客戶端已經實現了對背書策略的初步支持,通過-P來指定通過AND、OR、OutOf組合的身份角色(包括admin、member、peer、client)集合。
下面的策略指定要麼Org1的管理員進行背書,要麼Org2和Org3的peer節點同時進行背書:
OR('Org1.admin', AND('Org2.peer', 'Org3.peer'))
下面的策略指定三個組織中至少兩個組織的成員進行背書:
OutOf(2, 'Org1.member', 'Org2.member', 'Org3.member')
ChannelConf igPolicy方式則引用通道配置內的已有策略名,使用對應的身份進行背書。
例如,如果不顯式指定背書策略,則會使用通道配置中的Channel/Application/Endorsement策略,其默認爲通道內的大多數成員。
鍵值背書策略
除了面向鏈碼(該鏈碼的所有狀態)的背書策略外,自1.3.0版本開始,Fabric支持基於特定狀態(鍵值)的更細粒度的背書策略。用戶可以指定要修改某個指定狀態時所需的背書策略。
包括如下的shim層API,可以在鏈碼內使用。
●GetStateValidationParameter(collection,key string)([]byte,error):獲取指定集合對指定鍵值的背書策略。
●SetStateValidationParameter(collection,key string,ep[]byte)error:指定某個鍵值所綁定的背書策略。
●GetPrivateDataValidationParameter(collection,key string)([]byte,error):獲取指定集合對指定私密鍵值的背書策略。
●SetPrivateDataValidationParameter(collection,key string,ep[]byte)error:指定某個私密鍵值對應的背書策略。
Peer在提交區塊階段會對背書策略進行檢查.
私有數據集合背書策略
自2.0版本起,用戶也可以爲每個私密數據集合指定對應的背書策略。當用戶對私密數據集合內的鍵值進行寫或修改操作時,需要滿足指定的背書策略。此時,鏈碼的整體背書策略會被忽略。發起寫請求的用戶不必爲私密數據集合的成員。使用私密數據集合背書策略,可以限制對私密數據的寫操作,實現更爲安全的鏈碼訪問保護。
類似於鏈碼背書策略,私密數據集合背書策略支持SignaturePolicy或ChannelConf igPolicy兩種方式。例如,可以在集合配置文件collection.json中指定signaturePolicy或channelConf ig-Policy背書策略,示例代碼如下:
[
{
"name": "collection1", // 集合名稱
"policy": "OR('Org1MSP.member', 'Org2MSP.member')", // 集合成員
"requiredPeerCount": 1, // 背書之前至少擴散私密數據到的節點數
"maxPeerCount": 3, // 背書之前嘗試擴散最多節點個數,不能小於 requiredPeerCount
"blockToLive":99999, // 私密數據保存時長。0 意味着永不過期
"memberOnlyRead": true, // 是否只允許集合成員(如客戶端)來讀取私密數據,v1.4 開始支持
"memberOnlyWrite": true,// 是否只允許集合成員(如客戶端)來發起對私密數據的寫交易,v2.0
// 開始支持
"endorsementPolicy": { // 指定對私密數據進行寫操作時的背書策略,會取代鏈碼的背書策略
"signaturePolicy": "OR('Org1MSP.member')" // 指定使用簽名策略
}
},
{
"name": "collection2",
"policy": "OR('Org1MSP.member')",
"requiredPeerCount": 1,
"maxPeerCount": 3,
"blockToLive":3,
"memberOnlyRead": true,
"memberOnlyWrite": true,
"endorsementPolicy": {
"channelConfigPolicy": "Channel/Application/Writers" // 指定使用通道配置內已
// 有策略
}
}
]
基於證書屬性的鏈碼訪問控制
另外,用戶也可以在自己的鏈碼內通過基於證書屬性的鏈碼訪問控制,實現自定義的控制邏輯。例如,可在方法入口處先檢測調用者身份證書,過濾某些特定身份調用者,以實現基於鍵值或其他條件的細粒度的控制。
// github.com/hyperledger/fabric-chaincode-go/pkg/cid/cid.go
// 獲取根據證書主題生成的唯一標識
func GetID() (string, error)
// 獲取 MSP ID
func GetMSPID() (string, error)
// 獲取證書某個屬性的值
func GetAttributeValue(attrName string) (value string, found bool, err error)
// 檢查證書中某個屬性是給定值
func AssertAttributeValue(attrName, attrValue string) error
// 獲取調用者的 X509 證書
func GetX509Certificate() (*x509.Certificate, error)
// 判斷調用者是否屬於給定 OU
func HasOUValue(stub ChaincodeStubInterface, OUValue string) (bool, error)
用戶可以使用這些方法在鏈碼方法中對調用者身份進行訪問控制。
例如,在證書的extension域中設置自定義的屬性"abac."+role,並在鏈碼方法中判斷只有證書帶有該屬性的用戶纔可以調用該方法,示例代碼如下:
import "github.com/hyperledger/fabric-chaincode-go/pkg/cid"
func (t *TestChaincode) Access(stub shim.ChaincodeStubInterface, role string)
pb.Response {
// 根據屬性值來判斷是否允許訪問方法
err := cid.AssertAttributeValue(stub, "abac."+role, "true")
if err != nil {
return shim.Error("Not allowed with missed attribution"+err.Error())
}
...
}
實例化策略
實例化策略(Instantiation Policy)僅在2.0版本之前生效,負責對鏈碼的實例化情況進行控制。Committer在確認階段利用VSCC對網絡中進行鏈碼部署的操作進行權限檢查。
目前,實例化策略同樣採用了SignaturePolicy結構進行指定,可以基於身份集合結構構建複雜的簽名校驗組合。
默認情況下,會以當前MSP的管理員身份作爲默認策略,即只有當前MSP管理員可以進行鏈碼實例化操作。這可以避免鏈碼被通道中其他組織成員私自在其他通道內進行實例化。
實例化策略的檢查發生在Peer的背書階段。