天天看點

Fabric CA環境的內建

我們前面關于Fabric的所有文章中用到的例子都沒有CA Server,都是由cryptogen這個工具根據crypto-config.yaml而生成的。但是在實際生産環境中,我們肯定不能這麼做,我們應該為每個Org建立一個CA,由CA來管理其中的使用者。下面我們就試着講Fabric CA內建到整個Fabric網絡中,并用CA Client生成新使用者,最終使用新使用者調用ChainCode,驗證新使用者的合法性。我們仍然以官方的e2e_cli為例,關于這個例子的環境搭建,可以參考我的上一篇部落格: http://www.cnblogs.com/studyzy/p/7437157.html

1.修改docker-compose檔案,增加CA容器

我們就以給org1這個組織增加CA容器為例,打開e2e_cli檔案夾中的docker-compose-cli.yaml ,增加以下内容:

ca0: 
  image: hyperledger/fabric-ca 
  environment: 
    - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server 
    - FABRIC_CA_SERVER_CA_NAME=ca0 
    - FABRIC_CA_SERVER_TLS_ENABLED=false 
  ports: 
    - "7054:7054" 
  command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/${PRIVATE_KEY} -b admin:adminpw -d' 
  volumes: 
    - ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config 
  container_name: ca0      

這裡我們注意到,Fabric CA Server啟動的時候,帶了3個重要的參數:ca.certfile 指定了CA的根證書,ca.keyfile 指定了接下來給新使用者簽發證書時的私鑰,這裡我們使用變量${PRIVATE_KEY}代替,這是因為每次network_setup的時候,私鑰的名字是不一樣的,是以需要從啟動腳本中傳入。另外就是-b參數,指定了CA Client連接配接CA Server時使用的使用者名密碼。

2.修改network_setup.sh啟動腳本,将CA容器啟動的參數帶入

接下來我們需要修改network_setup.sh檔案,因為前面我們使用了變量${PRIVATE_KEY},是以這裡我們需要讀取變量并帶入docker-compose 啟動的時候。具體修改如下:

function networkUp () { 
    if [ -f "./crypto-config" ]; then 
       echo "crypto-config directory already exists." 
    else 
       #Generate all the artifacts that includes org certs, orderer genesis block, 
      # channel configuration transaction 
       source generateArtifacts.sh $CH_NAME 
    fi 
folder="crypto-config/peerOrganizations/org1.example.com/ca" 
privName="" 
for file_a in ${folder}/* 
do 
    temp_file=`basename $file_a`

    if [ ${temp_file##*.} != "pem" ];then 
       privName=$temp_file 
    fi 
done 
    echo $privName 
    if [ "${IF_COUCHDB}" == "couchdb" ]; then 
      CHANNEL_NAME=$CH_NAME TIMEOUT=$CLI_TIMEOUT docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH up -d 2>&1 
    else 
      CHANNEL_NAME=$CH_NAME TIMEOUT=$CLI_TIMEOUT PRIVATE_KEY=$privName docker-compose -f $COMPOSE_FILE up -d 2>&1 
    fi 
    if [ $? -ne 0 ]; then 
        echo "ERROR !!!! Unable to pull the images " 
        exit 1 
     fi 
    docker logs -f cli 
}      

這裡腳本的邏輯很簡單,就是去crypto-config/peerOrganizations/org1.example.com/ca這個檔案夾中去周遊檔案,找到私鑰檔案的檔案名,并把檔案名指派給privName,然後在docker-compse的啟動時,指定到PRIVATE_KEY即可。

3.使用CA Client生成新使用者

隻需要經過前面2步,我們給Org1設定的CA Server就算完成了。

3.1啟動Fabric網絡

運作

./network_setup.sh up      

啟動整個Fabric網絡。接下來需要使用CA Client來生成新使用者。我們需要以下幾步:

3.2下載下傳并安裝Fabric CA Client

官方提供的CA Client需要依賴于libtool這個庫,是以需要先安裝這個庫,運作指令:

sudo apt install libtool libltdl-dev      
然後執行以下指令安裝Fabric CA Client:      
go get -u github.com/hyperledger/fabric-ca/cmd/...      
該指令執行完畢後,我們應該在~/go/bin下面看到生成的2個檔案:      
fabric-ca-client  fabric-ca-server      

3.3注冊認證管理者

我們首先需要以管理者身份使用CA Client連接配接到CA Server,并生成相應的檔案。      
export FABRIC_CA_CLIENT_HOME=$HOME/ca
fabric-ca-client enroll -u http://admin:adminpw@localhost:7054      
這個時候我們可以去$HOME/ca目錄,看到CA Client建立了一個fabric-ca-client-config.yaml檔案和一個msp檔案夾。config可以去修改一些組織資訊之類的。      

3.4注冊新使用者

接下來我們想建立一個叫devin的使用者,那麼需要先執行這個指令:      
fabric-ca-client register --id.name devin --id.type user --id.affiliation org1.department1 --id.attrs 'hf.Revoker=true,foo=bar'      
系統會傳回一個該使用者的密碼:      
2017/09/05 22:20:41 [INFO] User provided config file: /home/studyzy/ca/fabric-ca-client-config.yaml 
2017/09/05 22:20:41 [INFO] Configuration file location: /home/studyzy/ca/fabric-ca-client-config.yaml 
Password: GOuMzkcGgGzq      

我們拿到這個密碼以後就可以再次使用enroll指令,給devin這個使用者生成msp的私鑰和證書:

fabric-ca-client enroll -u http://devin:GOuMzkcGgGzq@localhost:7054 -M $FABRIC_CA_CLIENT_HOME/devinmsp      
現在新使用者devin的私鑰和證書就在$HOME/ca/devinmsp目錄下,我們可以使用tree指令檢視一下:      
devinmsp/ 
├── cacerts 
│   └── localhost-7054.pem 
├── keystore 
│   └── a044e43ad1fd7cdfd1fd995abaef53895534bd70e8cdfdb665430d12665f2041_sk 
└── signcerts 
    └── cert.pem      

4.編寫ChainCode驗證目前使用者

由于官方提供的example02并沒有關于目前使用者的資訊的代碼,是以我們需要編寫自己的ChainCode。

這裡我們主要是用到ChainCode接口提供的GetCreator方法,具體完整的ChainCode如下:

package main

import (
   "github.com/hyperledger/fabric/core/chaincode/shim"
   pb "github.com/hyperledger/fabric/protos/peer"
   "fmt"
   "encoding/pem"
   "crypto/x509"
   "bytes"
)

type SimpleChaincode struct {
}

func main() {
   err := shim.Start(new(SimpleChaincode))
   if err != nil {
      fmt.Printf("Error starting Simple chaincode: %s", err)
   }
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
   return shim.Success(nil)
}


func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
   function, args := stub.GetFunctionAndParameters()
   fmt.Println("invoke is running " + function)
   if function == "cert" {//自定義函數名稱
      return t.testCertificate(stub, args)//定義調用的函數
   }
   return shim.Error("Received unknown function invocation")
}
func (t *SimpleChaincode) testCertificate(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   creatorByte,_:= stub.GetCreator()
   certStart := bytes.IndexAny(creatorByte, "-----")// Devin:I don't know why sometimes -----BEGIN is invalid, so I use -----
   if certStart == -1 {
      fmt.Errorf("No certificate found")
   }
   certText := creatorByte[certStart:]
   bl, _ := pem.Decode(certText)
   if bl == nil {
      fmt.Errorf("Could not decode the PEM structure")
   }
   fmt.Println(string(certText))
   cert, err := x509.ParseCertificate(bl.Bytes)
   if err != nil {
      fmt.Errorf("ParseCertificate failed")
   }
   fmt.Println(cert)
   uname:=cert.Subject.CommonName
   fmt.Println("Name:"+uname)
   return shim.Success([]byte("Called testCertificate "+uname))
}      
我們隻需要在~/go/src/github.com/hyperledger/fabric/examples/chaincode/go目錄下建立一個檔案夾,比如test1,然後建立一個檔案test1.go并粘貼上面的代碼進去即可。      

現在ChainCode已經開發完成,我們需要部署并測試該ChainCode的正确性,下面是部署步驟:

首先登陸到cli中:

docker exec -it cli bash      

然後在cli下面執行以下指令:

peer chaincode install -n test1 -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/test1

ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n test1 -v 1.0 -c '{"Args":[]}'

peer chaincode query -C mychannel -n test1 -c '{"Args":["cert"]}'      
系統傳回結果,說明我們目前的使用者是[email protected]      
root@2d1735e72642:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode query -C mychannel -n test1 -c '{"Args":["cert"]}' 
2017-09-05 14:40:23.175 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP 
2017-09-05 14:40:23.176 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity 
2017-09-05 14:40:23.176 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc 
2017-09-05 14:40:23.176 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc 
2017-09-05 14:40:23.176 UTC [msp/identity] Sign -> DEBU 005 Sign: plaintext: 0A95070A6708031A0B08D7EEBACD0510...07120574657374311A060A0463657274 
2017-09-05 14:40:23.176 UTC [msp/identity] Sign -> DEBU 006 Sign: digest: B4BB1EE5E6EBA63E50C85831C8820FB0B4490C55F23C247EDE5529DDAB23C273 
Query Result: Called testCertificate [email protected] 
2017-09-05 14:40:23.195 UTC [main] main -> INFO 007 Exiting.....       

5.設定新使用者的證書和私鑰檔案夾,驗證新使用者的可用性

因為我們是給org1設定的CA,使用者devin也是在org1下,是以需要把~/ca/devinmsp下面的檔案轉移到org1下面。org1的使用者證書和私鑰檔案夾在:

~/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/users

我們需要建立檔案夾devin用于儲存新使用者的證書和私鑰,我們建立一個Ubuntu的指令行視窗,前面已經登入您的cli的視窗保留,我們接下來還會用。

cd ~/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/users

mkdir devin

cp ~/ca/devinmsp/ devin/msp –R      

不知道什麼原因,Fabric在使用的時候需要用到msp檔案夾下的admincerts檔案夾,但是CA Client在生成的時候并沒有這個檔案夾,是以我們需要從signcerts這個檔案夾中拷貝一個過來,運作以下指令:

mkdir devin/msp/admincerts

cp devin/msp/signcerts/cert.pem devin/msp/admincerts/      

好現在我們的新使用者的所有證書準備完畢,tree devin看看結果:

devin/ 
└── msp 
    ├── admincerts 
    │   └── cert.pem 
    ├── cacerts 
    │   └── localhost-7054.pem 
    ├── keystore 
    │   └── a044e43ad1fd7cdfd1fd995abaef53895534bd70e8cdfdb665430d12665f2041_sk 
    └── signcerts 
        └── cert.pem      

接下來切換到cli視窗,我們把目前cli的使用者msp檔案夾切換成devin的檔案夾,具體指令是:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/devin/msp      

現在我們再來運作一下ChainCode:

peer chaincode query -C mychannel -n test1 -c '{"Args":["cert"]}'      

我們可以看到結果已經變化了,使用者已經由Admin變成了devin:

root@2d1735e72642:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode query -C mychannel -n test1 -c '{"Args":["cert"]}' 
2017-09-05 14:53:17.497 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP 
2017-09-05 14:53:17.497 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity 
2017-09-05 14:53:17.497 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc 
2017-09-05 14:53:17.497 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc 
2017-09-05 14:53:17.497 UTC [msp/identity] Sign -> DEBU 005 Sign: plaintext: 0AE3070A6808031A0C08DDF4BACD0510...07120574657374311A060A0463657274 
2017-09-05 14:53:17.497 UTC [msp/identity] Sign -> DEBU 006 Sign: digest: 21EE9B77A231E22ACB5FDD59C668C1A6E300833A820901DF9E896E22C00FC00F 
Query Result: Called testCertificate devin 
2017-09-05 14:53:17.508 UTC [main] main -> INFO 007 Exiting.....      

以上就是關于Fabric CA環境內建的簡單測試。關于CA Server有配置檔案在CA Server容器内部,可以針對不同的org資訊進行修改。而CA Client也有配置檔案,也可以在enroll之前進行修改。關于具體的修改方法,參考官方文檔:

http://hyperledger-fabric-ca.readthedocs.io/en/latest/

【本文章出自

部落格園深藍居

,轉載請注明作者出處,如果您覺得部落客的文章對您有很大幫助,歡迎點選右側打賞按鈕對部落客進行打賞。】

打個招聘廣告,部落客正在主導開發一個跨鍊區塊鍊項目:

PalletOne

,一直在招Go程式員,待遇豐厚,坐标北京酒仙橋,希望有識之士加入!