踩了两天的坑记录下:在fabric2.0.0,运行外部链码,并且通过tls加密传输
fabric2.0.0,运行外部链码的教程可见官方文档
https://hyperledger-fabric.readthedocs.io/zh_CN/latest/cc_service.html
https://hyperledger-fabric.readthedocs.io/zh_CN/latest/cc_launcher.html
在搭建完外部启动链码后,需要从ca生成tls-clinet证书和tls证书,不作为本章重点,略过
开启tls认证需要在chaoncode端开启,也需要在peer端connection文件开启
1.chaoncode
为了通用性,直接从环境变量读取chaoncode端的tls证书
1.1配置环境变量
#TLS
- name: CORE_PEER_TLS_CERT_FILE
value: /hyperledger/chaincode-container/tls-msp/signcerts/cert.pem
- name: CORE_PEER_TLS_KEY_FILE
value: /hyperledger/chaincode-container/tls-msp/keystore/key.pem
- name: CORE_PEER_TLS_ROOTCERT_FILE
value: /hyperledger/chaincode-container/tls-msp/tlscacerts/tls-ca-tls-7052.pem
本人是在k8s上跑的,需要自行改成docker或其他,总之就是导入以上环境变量即可
1.2chaoncode链码端
在原链码中添加以下
func loadTLSFile(filePth string) ([]byte, error) {
f, err := os.Open(filePth)
if err != nil {
return nil, err
}
return ioutil.ReadAll(f)
}
// main function starts up the chaincode in the container during instantiate
func main() {
CORE_PEER_TLS_KEY_FILE, err := loadTLSFile(os.Getenv("CORE_PEER_TLS_KEY_FILE"))
if err != nil {
fmt.Printf("Error loadTLSFile : %s", err)
}
CORE_PEER_TLS_CERT_FILE, err := loadTLSFile(os.Getenv("CORE_PEER_TLS_CERT_FILE"))
if err != nil {
fmt.Printf("Error loadTLSFile : %s", err)
}
CORE_PEER_TLS_ROOTCERT_FILE, err := loadTLSFile(os.Getenv("CORE_PEER_TLS_ROOTCERT_FILE"))
if err != nil {
fmt.Printf("Error loadTLSFile : %s", err)
}
fmt.Println("Running chaincode...")
server := &shim.ChaincodeServer{
CCID: os.Getenv("CHAINCODE_CCID"),
Address: os.Getenv("CHAINCODE_ADDRESS"),
CC: new(SimpleAsset),
TLSProps: shim.TLSProperties{
Disabled: false,
Key: CORE_PEER_TLS_KEY_FILE,
Cert: CORE_PEER_TLS_CERT_FILE,
ClientCACerts: CORE_PEER_TLS_ROOTCERT_FILE,
},
}
// Start the chaincode external server
err = server.Start()
if err != nil {
fmt.Printf("Error starting chaincode: %s", err)
}
}
要配置的关键地方就是 TLSProps: shim.TLSProperties以下的参数,直接从环境变量读取
2.peer端
1.1修改connection.json文件
坑的地方来了,根据官方构建的脚本,从中写入以下逻辑:从环境变量的CORE_PEER_TLS_CLIENTROOTCAS_FILES,CORE_PEER_TLS_CLIENTCERT_FILE,CORE_PEER_TLS_CLIENTKEY_FILE中读取文件,写入到连接信息中,其中连接信息在connection.json中通过tls_required,client_auth_required来控制
connection.json文件如下配置
{
"address": "chaincode-container:9999",
"dial_timeout": "10s",
"tls_required": true,
"client_auth_required": true,
"client_key": "CORE_PEER_TLS_CLIENTKEY_FILE",
"client_cert": "CORE_PEER_TLS_CLIENTCERT_FILE",
"root_cert": "CORE_PEER_TLS_CLIENTROOTCAS_FILES"
}
在release的构建脚本中,读取环境变量CORE_PEER_TLS_CLIENTROOTCAS_FILES,CORE_PEER_TLS_CLIENTCERT_FILE,CORE_PEER_TLS_CLIENTKEY_FILE均不能读取,排查了半天,终于在官方文档中找出问题(一定一定一定一定一定一定一定一定要好好阅读官方文档)
2.2 修改core.yaml
原来在构建脚本中,读取环境变量需要设置白名单,这下就好办了,在core.yaml中添加以下:
externalBuilders:
- path: /opt/gopath/src/github.com/hyperledger/fabric/peer/external
name: builder
environmentWhitelist:
- CORE_PEER_TLS_CLIENTROOTCAS_FILES
- CORE_PEER_TLS_CLIENTCERT_FILE
- CORE_PEER_TLS_CLIENTKEY_FILE
这样在构建脚本中就可以读取到环境变量的值了
2.3 修改release脚本
#!/bin/sh
# The bin/release script is responsible for providing chaincode metadata to the peer.
# bin/release is optional. If it is not provided, this step is skipped.
#
# The peer invokes release with two arguments:
# bin/release BUILD_OUTPUT_DIR RELEASE_OUTPUT_DIR
#
# When release is invoked, BUILD_OUTPUT_DIR contains the artifacts
# populated by the build program and should be treated as read only input.
# RELEASE_OUTPUT_DIR is the directory where release must place artifacts to be consumed by the peer.
function one_line_pem {
echo "`awk 'NF {sub(/\\n/, ""); printf "%s\\\\\\\n",$0;}' $1`"
}
set -euo pipefail
BUILD_OUTPUT_DIR="$1"
RELEASE_OUTPUT_DIR="$2"
# copy indexes from metadata/* to the output directory
if [ -d "$BUILD_OUTPUT_DIR/META-INF" ] ; then
cp -a "$BUILD_OUTPUT_DIR/META-INF/"* "$RELEASE_OUTPUT_DIR/"
fi
#external chaincodes expect artifacts to be placed under "$RELEASE_OUTPUT_DIR"/chaincode/server
if [ -f $BUILD_OUTPUT_DIR/connection.json ]; then
mkdir -p "$RELEASE_OUTPUT_DIR"/chaincode/server
cp $BUILD_OUTPUT_DIR/connection.json "$RELEASE_OUTPUT_DIR"/chaincode/server
#替换连接chaincode的tls-client证书
CORE_PEER_TLS_CLIENTKEY_FILE=$(one_line_pem $CORE_PEER_TLS_CLIENTKEY_FILE)
CORE_PEER_TLS_CLIENTCERT_FILE=$(one_line_pem $CORE_PEER_TLS_CLIENTCERT_FILE)
CORE_PEER_TLS_CLIENTROOTCAS_FILES=$(one_line_pem $CORE_PEER_TLS_CLIENTROOTCAS_FILES)
sed -i "s|CORE_PEER_TLS_CLIENTKEY_FILE|$CORE_PEER_TLS_CLIENTKEY_FILE|g" "$RELEASE_OUTPUT_DIR"/chaincode/server/connection.json
sed -i "s|CORE_PEER_TLS_CLIENTCERT_FILE|$CORE_PEER_TLS_CLIENTCERT_FILE|g" "$RELEASE_OUTPUT_DIR"/chaincode/server/connection.json
sed -i "s|CORE_PEER_TLS_CLIENTROOTCAS_FILES|$CORE_PEER_TLS_CLIENTROOTCAS_FILES|g" "$RELEASE_OUTPUT_DIR"/chaincode/server/connection.json
exit 0
fi
exit 1
以上,就可以完成peer端向外部链码通讯时采用tls加密,历时两天,终于从坑里爬出....
以上经验告诉我们,实践前,请仔细阅读官方文档...