golang
JWT
mqtt
GoogleCloudPlatform

それっぽいMQTTブローカー(サーバー)をGolangで立てる

GCPのCloud IoT Coreの検証をするためだけにCIから外部APIを叩くのが不安だったのでついカッとなってGolangでそれっぽいMQTTブローカーを立てる技能を身に着けましたのを残しておきます。

今回はVolantMQというOSSのMQTTサーバー実装を使いました。

今回の記事を書いた動機はGCPっぽく動かすためのパッチがマージされた記念からです。
MQTTのクライアントIDは規格では英数字しか許容しないようですが、まあ規格は規格なのでけっこう守らないところが多かったりします。
なので、今回 / 文字をClient IDに含めることを求めるGCPの仕様と揃えるためにパッチを書いて、それがめでたくマージされました。
コメントを見ると、他のブローカーとクライアントのために、制限を緩和しているのがわかるかと思います。

コード解説

今回は認証だけをそれっぽく欲しかったので、認証周り中心をカスタマイズしました。
詳しくはgcp-iot-core-glang-sample見てもらった方がはやいと思うのですが、できるだけ解説します。

認証では、基本的に
- パスワードの検証 (Password メソッド)
- アクセス制御リストの検証 (ACL メソッド)

をするインターフェースを要求していてそれをそれっぽく上書きしてあげると、GCPっぽいMQTTサーバーが手に入りました。
パスワードの方は、接続時に実行され、アクセス制御リストは、publishなどの要求時に行われるようです。
(今回の用途は基本的にpublishだけだったのでpublish以外は検証していないです。)

GCPでは、MQTTのパスワードでJWTをやりとりする仕様なので、Password メソッドではJWTの検証をします。
JWTをパースして、所定の公開鍵で復号化できることを確認し、
- Audience
- 期限
- 作成時

を検証します。

ACL メソッドでは、クライアントIDとトピックがGCPっぽいかしか見てません。
いろんな権限制御をしたい場合は、もっと複雑な処理が入るのかもしれませんね。

そして、main 関数でMQTTブローカーをテスト時に起動します。
ローカルホストの空きポートを探すとかはしてますが、基本的にプロトコルを3.1.1に制限する以外は特別なことはしてないです。

雑感

Golangのいいところで、インターフェース設計をしっかりしておくと、疎結合で外部からカスタマイズしやすい設計ができるところを活かしたコーディングができてよかったです。

ただ、VolantMQの開発がとても不安定なので、実装当時はmasterブランチからforkしたら、CIが失敗していた状況のせいかうまくいかず、直近のリリースタグから開発になったりしてました。
テスト用には非常に高機能で使いやすいんですが、製品で利用するとなるとVolantMQはまだ不安定だと感じます。

それでも、MQTT 5の対応を進めているとのことなので、そこはとても期待しています。
時間に余裕があったら、実装のお手伝いをできればと思います。