この投稿は、弊社が提供するWESEEK TECH通信の一環です。
WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。
はじめに
こんにちは。システムエンジニアの佐藤です。
この記事では WESEEK社内通過であるWESEEK DOLLER(WSD)の流通が開始して約1年経ち、その中で発生したHyplerledgerFabricにおける証明書の有効期限切れトラブルと振り返って分かったことを物語風に紹介します。
WESEEK DOLLER(WSD)とはWESEEK社内で流通する貨幣のことです。詳細についてはWESEEK BlogのWESEEK DOLLORや社内通過WSD、リスタートをご覧ください。
WSDはブロックチェーンフレームワークHyperledgerFabricを使っています。HyperledgerFabricについての概要やアプリケーション開発方法については、Qiitaの記事をご覧ください。
- Hyperledger fabric で始めるブロックチェーンアプリケーション (1/3)
- Hyperledger fabric で始めるブロックチェーンアプリケーション (2/3)
- Hyperledger fabric で始めるブロックチェーンアプリケーション (3/3)
HLFコンポーネント証明書の有効期限切れ
HyperledgerFabric(HLF)におけるデータや通信の信頼には証明書が用いられます。
証明書には当然有効期限がありますので、この有効期限が切れた場合にはシステムに影響が出ます。
ある日、それは起こった
ある日のこと、
「WSD を流通するアプリケーション(colllet)にログインすると、ずっとローディングアイコンが表示されたままになってしまいました。。。 🙁 」
という連絡を受けました。
collletではログインすると所持するWSDの金額と、その他の操作画面へのリンクが表示されます。(次の画像参照)
この画面の中にある"16"は、自身が所持するWSDの金額です。
自身が所持するWSDの金額はHyperledgerFabricにトランザクションを送った結果が表示されます。
colllet frontがHyperledgerFabricにトランザクションを送る通信経路は次のようになっています。
# colllet front
# ↑
# |(REST APIアクセス)
# ↓
# colllet back
# ↑
# |(HLFトランザクション)
# ↓
# HyperledgerFabric(Orderer)
# ↑
# |(HLFコンポーネント間通信)
# ↓
# HyperledgerFabric(Peer)
# ↑
# ↓
# Chaincode(WSD)
ログを確認すると、frontからbackへのアクセスが行われた後にHLFトランザクションが応答しておらず、また client identity expired の文字がありました。
どうやら証明書の有効期限が切れてしまったようです。
[comm.grpc.server] 1 -> INFO 1922 streaming call completed grpc.service=orderer.AtomicBroadcast grpc.method=Deliver grpc.peer_address=***:33312 grpc.code=OK grpc.call_duration=928.91µs
[common.deliver] deliverBlocks -> WARN 1923 [channel: ***] Client authorization revoked for deliver request from ***:33330: client identity expired 74h41m17.76951635s before
HLFシステムで用いる証明書は複数あります。
- ユーザー証明書
- HLF CA証明書
- HLF Orderer証明書
- HLF Peer証明書
各証明書を確認すると、HLF CA証明書、HLF Orderer証明書、HLF Peer証明書が切れていることが分かりました。
(WSDシステムを導入する時点で発行し、その際に有効期限が1年であったために同時期に切れましたが当然発行した時期と有効期限によっては状況が変わると思います)
HLFコンポーネントの証明書が切れるとトランザクション処理ができなくなります。
その結果、collletにログインしてもその後の画面が表示できなくなっていたようでした。
(このような場合、画面上でエラーを表示するべきですが作りこみの甘さは社内利用限定ということで温かい目で見てください 😉 )
お時間いただきますと回答
とりあえず証明書の更新が必要であることは分かりました。WSDスタート時からいずれこの日が来るとは分かってましたがそこはご愛敬です。
証明書を再発行するにしても検証する時間も欲しかったので利用者にはしばらく待ってもらい週末に対応することにしました。
HLFコンポーネント証明書の再発行
HLFでは証明書を発行する方法として、enrollとreenrollがあります。
enrollは証明書の発行であり、reenrollは証明書の再発行です。
fabric-ca-clientというツールを使うとこれらの処理ができますが、システム構築時に証明書切れが起こった場合を想定してreenrollを実行したことがあり、今回もそれで解消できるだろうと思ってましたが証明書の有効期限が切れたときはreenroll出来ないことが分かりました。 😥
よく考えるとそれもそうかと思いましたがenrollするときにパスワードを指定することから、このパスワードが残っていれば再発行できるものだと勘違いをしていました。
さて、reenroll出来ないとなるとenrollするしかありません。
ここで、HLFでは同一IDにおける証明書の発行回数が制限されています。
fabric-ca-client identity list
で表示される"Max Enrollments"がこれに当たります。
$ fabric-ca-client identity list
Name: admin, Type: client, Affiliation: , Max Enrollments: -1, Attributes: [{Name:hf.IntermediateCA Value:1 ECert:false} {Name:hf.GenCRL Value:1 ECert:false} {Name:hf.Registrar.Attributes Value:* ECert:false} {Name:hf.AffiliationMgr Value:1 ECert:false} {Name:hf.Registrar.Roles Value:* ECert:false} {Name:hf.Registrar.DelegateRoles Value:* ECert:false} {Name:hf.Revoker Value:1 ECert:false}]
HLFコンポーネントの証明書を発行する際はfabric-ca-client register
コマンドを使いました。
この際に"Max Enrollments"は指定していなかったのでCAに設定された最大発行回数がdefault値になり、幸いにも"-1"(無限)でした。
ひとまずenrollすれば証明書の発行ができます。
後はひたすら証明書を発行してシステムで利用する証明書と置き換えれば作業は完了です。時間はかかりますが単調な作業ですね。
振り返って分かったこと
地味な証明書の発行と置き換えを繰り返して無事にcollletが復旧してトランザクション処理を行えるようになりました。
振り返って分かったことは次のとおりです。
- HLFコンポーネントの証明書有効期限が切れると全ユーザーがトランザクション処理ができなくなる
- 証明書の有効期限が切れるとreenroll出来なくなる
- 証明書の発行回数期限は"Max Enrollments"により発行時に設定される
fabric-ca-client
コマンドでregister時に最大発行回数が指定できるfabric-ca-client
コマンドで最大発行回数を指定せずにregisterした場合はCAの最大発行回数がdefault値になる
ユーザー証明書の有効期限切れ
HLF コンポーネントの他にユーザーにも証明書が発行されます。
再び、それは起こった
ある日が起こってからそう間もない日、再びそれは起こりました。
「あるユーザーで colllet にログイン出来なくなりました。他のユーザーではログインできるのですが何か分かりますか・・・? 🙁 」
という連絡を受けました。
そうです、ユーザー証明書の有効期限が切れてしまったようです。
ユーザー証明書が切れた場合もHLFにおいてトランザクション処理ができなくなります。但し、HLF コンポーネントの証明書が切れた場合と異なり、期限が切れたユーザーだけがトランザクション処理ができなくなります。
有効期限はユーザーが登録された日から1年間だったため、ユーザーによってはログインできる・できないが違いました。
この時は先日のHLFコンポーネントの証明書有効期限が切れたときに期限一覧を見て気が付いていましたが、fabric-ca-client
コマンドを非エンジニアに実行してもらって再発行するのは現実的ではないのでアプリケーション側で機能実装する必要があると考えていました。
ユーザー証明書の再発行
HyperledgerFabricにおいて、hf.Type
という証明書の拡張属性を使うことで分類することは可能ですが、基本的にユーザー証明書もHLFコンポーネントの証明書も同じです。
そのため、ユーザー証明書の発行・再発行もHLFコンポーネントの証明書発行とやり方は同じです。
しかし、発行した方法の違いで"Max Enrollments"が違ったのです。。。
collletではアプリケーションでユーザー登録ができます。
colllet backはNode.jsで実装されており、Hyperledger Fabric SDK for Node.jsを使っています。
ここで、registerをする際の証明書の発行回数期限がデフォルトでは1だったのです。(該当するコードは次のリンク先を参照)
つまり証明書の有効期限が切れた場合はreenroll出来ず、更にはenrollは既に行われているので再びenrollすることもできません。 😥
ではどうすればよいのかを調べていたところ、この"Max Enrollments"はfabric-ca-client identity modify
を使って変更出来ることが分かりました。
そこで、以下の対応をすることにしました。
- 既存ユーザーの"Max Enrollments"を"-1"へ変更する
- アプリケーション側でユーザー登録時に"Max Enrollments"を"-1"にする
- ユーザーログイン時に証明書の有効期限に応じて、証明書を再度発行(enrollでありreenrollではない)する
振り返って分かったこと
- HLFユーザーの証明書有効期限が切れると該当ユーザーはトランザクション処理ができなくなる
- Hyperledger Fabric SDK for Node.jsのFabricCAServices#registerはdefaultで"Max Enrollments"が"1"になる
fabric-ca-client identity modify
により"Max Enrollments"は変更できる
$ fabric-ca-client identity modify --maxenrollments -1 [USER]
さいごに
HyperledgerFabricにおいて証明書の有効期限が切れたときの影響と対応方法について紹介しました。
また機会がありましたらブロックチェーンのデータ構造などを紹介しようと思います。