Hyperledger Fabric Private Chaincodeを動かしてみる #2 ハードウェア

# はじめに

株式会社日立製作所 研究開発グループ サービスコンピューティング研究部の池川です。
Blockchainに関する研究をしており、特にHyperledgerが管理するOSSを使っています。

前回の記事では、Intel SGXが搭載されていないVM上でFabric Private Chaincodeをシミュレーションモードで実行する手順をご紹介しました。

https://qiita.com/ikegawa-koshi/items/39c98779ad8696b78816

本記事では、Intel SGXが搭載されたマシンを準備して、ハードウェアの実機でFabric Private Chaincodeを動作させてみたいと思います。

## Fabric Private Chaincodeとは

Hyperledger Fabric Private Chaincode（FPC）はLinux Foundationのブロックチェーン技術推進コミュニティであるHyperledgerが管理するOSSプロジェクトの1つです。

https://github.com/hyperledger/fabric-private-chaincode

FPCを使用することによって、Hyperledger FabricにおけるChaincodeをTrusted Execution Environment (TEE)上で動作させることができるようになります。
TEEとはIntel Software Guard Extensions (SGX)やARM TrustZone、AMD Secure Encrypted Virtualization (SEV)などCPUベンダ各社が提供しているセキュリティ技術です。
メモリ上に暗号化領域を生成し、そこにプログラムやデータをロードすることでセンシティブなデータを保護しつつプログラムを実行することが可能となるCPUの機能です。

TEEを用いることにより、トランザクションおよびデータの内容を秘匿（暗号化）した状態でChaincodeを実行することが可能となり、プライバシー保護が必要なユースケースに適応可能となります。
2021年10月現在のFPCの実装ではIntel SGXを利用した実装が進められています。

また、FPCの実装はFabric本体のRFCプロセスを管理するhyperledger/fabric-rfcsにて承認されており、将来Fabric本体に統合されるよう開発が進んでいます。

https://github.com/hyperledger/fabric-rfcs

# 環境構築

Microsoft AzureにはIntel SGXが使用できるDCsv2シリーズと呼ばれるVMが提供されています。
なお、DCsv2シリーズは2021年10月現在では(US)米国東部リージョンでのみ利用可能です。

https://docs.microsoft.com/ja-jp/azure/virtual-machines/dcv2-series

本記事では以下の環境のVMを立ち上げて作業を行いました。

- IaaS：Microsoft Azure
- 地域：(US)米国東部
- イメージ：Ubuntu Server 20.04 LTS - Gen2
- サイズ：Standard_DC2s_v2
- ストレージサイズ：200GB

以後、立ち上げたインスタンスにssh接続し構築しました。

## 必要なパッケージのインストール

立ち上げたサーバに以下に記載のコマンドを実行し必要なパッケージをインストールします。
本記事ではshellを複数同時に立ち上げる作業があり、`screen`や`tmux`などもインストールしておくことをおすすめします。

```shell
sudo apt update
sudo apt install -y docker docker-compose golang make
# sudo apt install -y tmux
```

## SGX環境のインストール

Intel SGX関係を扱うリポジトリを追加しパッケージをインストールします。

```shell
echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main' | sudo tee /etc/apt/sources.list.d/intel-sgx.list
wget -qO - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | sudo apt-key add -
sudo apt -y install libssl-dev libsgx-enclave-common libsgx-enclave-common-dev libsgx-ae-qe3 libsgx-ae-qve libsgx-epid libsgx-launch libsgx-pce-logic libsgx-qe3-logic libsgx-quote-ex libsgx-uae-service libsgx-urts

# ここで一旦再起動（設定反映のため）
sudo reboot

# aesmd.serviceの動作確認
sudo systemctl status aesmd.service
# ==> Active: active (running) と表示されればOK
```

## その他設定

パッケージのインストール後、以下のコマンドを実行し各パッケージの設定や環境変数の設定をします。

```shell
# sudoなしでdockerコマンドを使えるようにする
sudo usermod -aG docker $(whoami)

# GO111MODULEの設定を自動にする
go env -w GO111MODULE=auto

# 環境変数の追加（GOPATH・GOBIN・PATHの設定）
echo 'export GOPATH=$HOME/go' >> .bashrc
echo 'export GOBIN=$GOPATH/bin' >> .bashrc
echo 'export PATH=$PATH:$GOBIN' >> .bashrc

# ここで一旦再起動（設定反映のため）
sudo reboot
```

## Fabric Private Chaincodeのソースをダウンロード

`go get`を用いてFPCのソースをダウンロードします。
なお、`git clone`を用いてダウンロードしても大丈夫です。
GOPATH以下のディレクトリにcloneしてあることが重要になります。

なお、本記事執筆時にリリースされていたv1.0-rc2にバグが有ることが発覚しました。
よって執筆時最新のmainブランチのソース（コミットID：22f32d814e2b3663df544cf3b06a1ead33e76bf9）を使用しています。

```shell
go get github.com/hyperledger/fabric-private-chaincode
echo 'export FPC_PATH=$GOPATH/src/github.com/hyperledger/fabric-private-chaincode' >> .bashrc
```

## Intel® SGX Attestation Service Utilizing Enhanced Privacy ID (EPID)の登録をする

以下のリンク先より、Intelの開発者アカウント作成（サインアップ）をしてください。

https://api.portal.trustedservices.intel.com/EPID-attestation

アカウント作成が済み、ログイン状態になると以下のような表示になります。
ここから、Development AccessのSubscribe (unlinkable)を選択し、EPIDの発行を進めてください。

![スクリーンショット 2021-09-27 21.17.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190447/e647adeb-975e-5142-5d16-f000b728c5e1.png)

登録が済むと、SPIDとPrimary keyが発行されますので、その値を以下の手順で各ファイルに書き込んでください。

```shell
## epid setting
echo '[YOUR_SPID]' > ${FPC_PATH}/config/ias/spid.txt
echo '[YOUR_PRIMARY_KEY]' > ${FPC_PATH}/config/ias/api_key.txt
echo 'epid-linkable' > ${FPC_PATH}/config/ias/spid_type.txt

# [YOUR_SPID]と[YOUR_PRIMARY_KEY]はそれぞれ書き換えてください。
```


## FPCをビルドするたの環境を構築

FPCの設定ファイルを書き換えます。
`SGX_MODE=HW`とすることによって、Intel SGX実機を使って動作させることができるようになります。

```shell
cat >> ${FPC_PATH}/config.override.mk << "EOF"
export SGX_MODE=HW
export DOCKER_BUILDKIT=1
EOF
```

以下のコマンドを実行してDockerイメージのビルドと立ち上げを行います。
マシンのスペックにもよりますが15分弱かかるので気長に待ちましょう。

```shell
cd ${FPC_PATH}/utils/docker
make pull-dev
make run-dev
# ==> fpc-development-mainというコンテナが立ち上がります。

# 一旦コンテナから出ましょう
exit
```
ここまでの手順を終えることで、FPCをビルドするための環境が揃ったコンテナイメージを作成することができます。


# FPCのビルドおよび実行

続いて、FPCをビルドするためのコンテナ上のbashを実行しFPC本体をビルドする作業に入ります。

## fpc-development-mainのスタートおよびbashの実行

```shell
# 一旦コンテナから出たことにより、fpc-development-mainコンテナがストップしているので再度スタートする
docker start fpc-development-main

# ビルド環境に入る
docker exec -i -t fpc-development-main bash
```

以降は`fpc-development-main`コンテナ内部のbash上でコマンドを実行します

# FPCのビルドおよびサンプルプログラムの実行

:warning: ここから先はすべてfpc-development-mainコンテナ内のbash上での操作です

## FPCのビルド

以下の手順でfpc-development-mainコンテナ内の`FPC_PATH`に移動して、FPCのコンテナイメージをビルドしましょう。
（結構時間かかります。）

```shell
cd $FPC_PATH
make clean
make
```

## chaincodeのビルド

以下の手順でchaincodeをビルドします。
ここではFPCが準備しているサンプルであるechoというchaincodeを動かす手順を紹介します。

なお、通常のFabricではChaincodeの実装にgolangやnodejsを用いますが、FPCではIntel SGX上で動作させるためにもC/C++でのChaincode実装が必要となります。

```shell
make -C $FPC_PATH/utils/docker pull
make -C $FPC_PATH/utils/docker build

export CC_ID=echo

cd $FPC_PATH/samples/deployment/test-network
export CC_PATH=${FPC_PATH}/samples/chaincode/$CC_ID
make build
```

## fabric-samplesの取得

本記事の手順ではfabric-samplesを元にネットワークの起動を試します。
以下の手順によりfabric-samplesのソースと必要なバイナリを取得しましょう。

```shell
cd $FPC_PATH/samples/deployment/test-network
git clone https://github.com/hyperledger/fabric-samples -b v2.3.0
cd $FPC_PATH/samples/deployment/test-network/fabric-samples
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.3.0 1.4.9 -s
```

## core.yamlの書き換え

Fabricのネットワーク起動に必要となる設定ファイルである`core.yaml`を書き換えます。
FPC側で書き換えのスクリプトが準備されているので、以下の手順で実行します。

```shell
cd $FPC_PATH/samples/deployment/test-network
./setup.sh
```

## fabric-networkの立ち上げ

以下の手順でネットワークの立ち上げおよびchannelのcreate/joinを実施します。
起動できない場合は`up`をする前に一度`down`を実行しておくことにより、初期化され正しく起動できる可能性が高いです。

```shell
cd $FPC_PATH/samples/deployment/test-network/fabric-samples/test-network
#./network.sh down
./network.sh up
./network.sh createChannel -c mychannel -ca -cai 1.4.9 -i 2.3.0
```

## chaincodeのインストール

以下のコマンドにより、chaincodeのインストールを実行します。
実行結果を読み、以下の手順を必ず実施してください。

```shell
cd $FPC_PATH/samples/deployment/test-network
./installFPC.sh
```

:warning: 以下のような結果が出力されるので必ず環境変数に設定しましょう

```shell:結果（動作環境によって必ず異なりますので、各自実行した結果に基づいて環境変数の設定をしてください）
︙
# define (i.e., copy/paste into shell) following environment-variables
# for docker-compose and then start it by calling 'make ercc-ecc-start'
export \
  ORG1_ECC_PKG_ID=echo_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
  ORG1_ERCC_PKG_ID=ercc_1.0:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\  
  ORG2_ECC_PKG_ID=echo_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
  ORG2_ERCC_PKG_ID=ercc_1.0:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```


## Chaincodeの動作開始

以下のコマンドでchaincodeの動作を開始します。

```shell
cd $FPC_PATH/samples/deployment/test-network
make ercc-ecc-start
```

## networkファイルのアップデート

tmux等を使って新たに並列でbashを立ち上げ、`docker exec -i -t fpc-development-main bash`を実行し`fpc-development-main`のbashに入ってください

```shell
cd $FPC_PATH/samples/deployment/test-network
./update-connection.sh
```

## クライアントアプリケーションを用いた動作確認

```shell
# make fpcclient
cd $FPC_PATH/samples/application/simple-cli-go
make

# export fpcclient settings
export CC_NAME=echo
export CHANNEL_NAME=mychannel
export CORE_PEER_ADDRESS=localhost:7051
export CORE_PEER_ID=peer0.org1.example.com
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_MSPCONFIGPATH=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_TLS_CERT_FILE=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
export CORE_PEER_TLS_ENABLED="true"
export CORE_PEER_TLS_KEY_FILE=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export ORDERER_CA=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export GATEWAY_CONFIG=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/connection-org1.yaml
export SGX_CREDENTIALS_PATH=$FPC_PATH/config/ias

# init our enclave
./fpcclient init $CORE_PEER_ID

# interact with the FPC Chaincode
./fpcclient invoke foo
./fpcclient query foo
```

なお、echoでは実際に台帳に書き込む処理（put_state）を行わず、単純にトランザクションの送信および結果の返却のみを行うものです。
よって、Invokeを実行したとしてもState DBの更新等も発生しません。
実際にLedgerへの書き込みおよびState DBの更新が発生するようなChaincodeに関する記事は別の機会に紹介したいと考えています。

## ネットワークのシャットダウン方法

以下のコマンドを実行することで、chaincodeを終了しfabricネットワークを構成するコンテナをシャットダウンできます。
このコマンド実行後は、ネットワーク起動の手順から順に実行することで再度起動が可能です。

```shell
make -C $FPC_PATH/samples/deployment/test-network ercc-ecc-stop
cd $FPC_PATH/samples/deployment/test-network/fabric-samples/test-network
./network.sh down
```


# さいごに
今回はIntel SGXが搭載されたマシンを準備して、ハードウェアの実機でFabric Private Chaincodeを動作させてみました。
Fabric Private Chaincodeは現在も開発が進んでいますので、引き続きその動向や使い方などを紹介していきたいと思います。