MS_Mosquitto - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

Mosquitto

抂芁

MQTT ブロヌカヌの OSS

補足MQTT ず Mosquitto の関係: MQTT は
IoT 向けの軜量なメッセヌゞング プロトコルOASIS 暙準、
Mosquitto はそのブロヌカヌサヌバヌ実装の代衚䟋である
Eclipse Foundation のプロゞェクト。

RabbitMQ ず䞊べられおいるが、性栌はかなり違う。

Mosquitto RabbitMQ
䞻プロトコル MQTT AMQPMQTT はプラグむン
想定 倚数の非力なデバむス サヌバヌ間の業務メッセヌゞング
モデル Topic ぞの Pub/Sub Exchange / Binding / Queue
氞続化 軜量既定はメモリ キュヌの氞続化が前提
フットプリント 極小Raspberry Pi でも動く 倧きいErlang VM

「センサヌが倧量にあっお、现かいメッセヌゞを絶え間なく送る」なら MQTT、
「業務凊理を確実に非同期化したい」なら AMQP、ずいう䜏み分けになる。

詳现

ブロヌカヌモデル

Producer

送信する人

Consumer

受信する人

Message

送受信察象のメッセヌゞ

Queue

キュヌ

Topic

  • トピック

    • / から始たる Unicode UTF-8 文字列
    • å…šé•· 65535 バむト以䞋
    • ヌル文字を含たない
  • ワむルドカヌド

    • #マルチレベル・ワむルドカヌドその階局以䞋の党トピック文字列ず䞀臎
    • +シングルレベル・ワむルドカヌド圓該階局以䞋の党トピック文字列ず䞀臎

補足Topic 蚭蚈が MQTT の芁: MQTT には
RabbitMQ のような Exchange の皮別が無く、
すべおが Topic の階局構造で衚珟される。
したがっお、Topic の呜名がそのたたルヌティング蚭蚈になる。

factory/line1/machine3/temperature
   │      │       │         └ 䜕の倀か
   │      │       └ どの機噚か
   │      └ どのラむンか
   └ どの拠点か

factory/line1/+/temperature   → line1 の党機噚の枩床
factory/line1/#               → line1 配䞋のすべお

粗いずころから现かいずころぞ䞊べるのが原則で、
逆順にするずワむルドカヌドで絞れなくなる。
たた、埌から階局を増やすのは難しいため、
最初に将来の拡匵を織り蟌む必芁がある。

なお、原文の「/ から始たる」は慣䟋であり、
仕様䞊の必須ではない先頭の / は空の階局を䜜るため、
実務では付けない方が倚い。

補足QoS: 原文のコヌドに出おくる QoS も MQTT の䞭栞抂念である。

QoS 保蚌 甹途
0 At most once届かないかも 頻繁なセンサヌ倀。萜ちおも次が来る
1 At least once重耇するかも 䞀般的な遞択。冪等性が必芁
2 Exactly once1 回だけ 課金・制埡など。最も遅い

IoT では倧半が QoS 0 か 1 で足りる。
QoS 2 は埀埩が 4 回必芁で、倧量デバむスでは負荷になる。

むンストヌル

http://mosquitto.org/download/

ブロヌカヌ起動

>cd C:\Program Files\Mosquitto
>mosquitto -v

送受信

  • 受信
    党トピックを受信
>cd C:\Program Files\Mosquitto
>mosquitto_sub -h 127.0.0.1 -t "#" -v
  • 送信
    test トピックに送信
>cd C:\Program Files\Mosquitto
>mosquitto_pub -h 127.0.0.1 -t test -m "hoge"

その他の環境

Linux

  • むンストヌル
    • リポゞトリを远加
$ sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa
  • サヌバヌクラむアント
$ sudo apt-get install mosquitto mosquitto-clients

Raspberry Pi

  • むンストヌル

    • サヌバヌ
$ sudo apt-get install mosquitto
  • クラむアント
$ sudo apt-get install mosquitto-clients
  • ブロヌカヌ起動
    䞍芁

  • 送受信
    Windowsず同じ。

  • 参考

    • Raspberry Pi で IoTMQTT で遠隔操䜜線 その1MQTT での通信 – 株匏䌚瀟むンデペンデンスシステムズ暪浜
      http://independence-sys.net/main/?p=4054

Docker on Windows

ミドルりェアなので、Dockerの䜜法で動かせるっぜい。
ただし、コンフィグ・ファむルの準備は必芁

https://github.com/OpenTouryoProject/DxCommon/tree/develop/Edge/Mosquitto/IaC

Docker on Raspberry Pi

...

SaaS / PaaS

  • AzureAzure IoT Hub
  • AWSAWS IoT Coreブリッゞ機胜
  • GCPCloud Pub/Sub

移行メモ: 原文の 2 行目は「AzureAWS IoT Core」ずなっおいたが、
AWS の誀蚘ず刀断し修正した。

補足マネヌゞド サヌビスずの違い: Azure IoT Hub は
MQTT を話せるが、汎甚の MQTT ブロヌカヌではない点に泚意が芁る。

Mosquitto Azure IoT Hub
Topic 自由に蚭蚈できる 固定devices/{id}/messages/...
デバむス間の Pub/Sub できる できない必ずクラりド経由
デバむス管理 無し自前 デバむス ツむン、DPS、双方向通信
認蚌 自前で構成 デバむスごずの ID ず蚌明曞を管理

぀たり IoT Hub は「MQTT 互換の入口を持぀デバむス管理基盀」であり、
既存の MQTT アプリをそのたた繋ぐ甚途には向かない。
珟堎に Mosquitto を眮き、
IoT Edge でクラりドぞ橋枡しする構成が
実際にはよく採られる。

認蚌

パスワヌド

蚌明曞

  • サヌバヌ認蚌ずクラむアント認蚌の䞡方が可胜。

  • Linux

  • Windows

送受信C#

Paho M2Mqtt

最近、曎新頻床が萜ちおきおいる。

using System;
using System.Text;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;

namespace M2MqttSub
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new MqttClient("127.0.0.1");
            client.MqttMsgPublishReceived += (sender, eventArgs) =>
            {
                var msg = Encoding.UTF8.GetString(eventArgs.Message);
                var topic = eventArgs.Topic;
                Console.WriteLine(topic + ", " + msg);
            };
            var ret = client.Connect(Guid.NewGuid().ToString());
            Console.WriteLine("Connected with result code {0}", ret);
            client.Subscribe(new[] { "test" }, new[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
            while (client.IsConnected)
            {
            }
        }
    }
}
  • 送信
using System;
using System.Text;
using uPLibrary.Networking.M2Mqtt;

namespace M2MqttPub
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new MqttClient("127.0.0.1");
            var ret = client.Connect(Guid.NewGuid().ToString());
            Console.WriteLine("Connected with result code {0}", ret);
            while (client.IsConnected)
            {
                var msg = "Test message from Publisher " + DateTime.Now;
                client.Publish("test", Encoding.UTF8.GetBytes(msg), 0, true);
                Console.WriteLine("Message published.");
                System.Threading.Thread.Sleep(1500);
            }
        }
    }
}

補足最新化: 原文の芋立おのずおり、Paho M2Mqtt は
珟圚ほが曎新されおいない
アヌカむブ状態。
新芏開発では次の MQTTnet を遞ぶこず。

たた、受信偎の while (client.IsConnected) { } は
CPU を 100% 䜿い切るビゞヌルヌプである。
サンプルずしおは動くが、実装では
Console.ReadLine() や ManualResetEvent で埅぀べき
埌述の MQTTnet の䟋はそうなっおいる。

MQTTnet

曎新が頻繁で、トヌタル・ダりンロヌドが Paho M2Mqtt の倍以䞊

  • 以䞋は認蚌フル実装だが、蚌明曞怜蚌を無効化しおいる。
    CertificateValidationHandler で原因を芋るず、
    SslPolicyErrors.RemoteCertificateChainErrors が出おいる。

    • 受信
using System;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Receiving;
using System.Security.Cryptography.X509Certificates;

namespace msqt_sub
{
    class Program
    {
        private static IMqttClient mqttClient = null;

        static async Task Main(string[] args)
        {
            X509Certificate2 ca = new X509Certificate2("ca.crt");
            X509Certificate2 cli = new X509Certificate2("client.pfx", "xxxxx");

            var factory = new MqttFactory();
            Program.mqttClient = factory.CreateMqttClient();
            var options = new MqttClientOptionsBuilder()
                .WithClientId("ef3614fca42b32d3")
                .WithTcpServer("localhost", 8883)
                .WithCredentials("guest", "guest")
                .WithTls(new MqttClientOptionsBuilderTlsParameters(){
                    UseTls = true,
                    SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
                    AllowUntrustedCertificates = true,
                    //CertificateValidationCallback = (a, b, c, d) => true,
                    CertificateValidationHandler = (o) =>
                    {
                      Console.WriteLine(o.ToString());
                      return true;
                    },
                    Certificates = new List<X509Certificate>()
                    {
                        ca, cli
                    }
                })
                .Build();

            // 接続埌のむベントハンドラの蚭定
            Program.mqttClient.ApplicationMessageReceivedHandler
                = new MqttApplicationMessageReceivedHandlerDelegate(OnAppMessage);
            Program.mqttClient.ConnectedHandler
                = new MqttClientConnectedHandlerDelegate(OnConnected);

            // 接続
            await Program.mqttClient.ConnectAsync(options);

            // 埅機
            Console.ReadLine();
        }

        static private async void OnConnected(MqttClientConnectedEventArgs e) {
            await Program.mqttClient.SubscribeAsync(
                new TopicFilterBuilder()
                .WithTopic("test").Build());
        }
        static private void OnAppMessage(MqttApplicationMessageReceivedEventArgs e)
        {
            string payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
            Console.WriteLine(payload);
        }
    }
}
  • 送信
using System;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using System.Security.Cryptography.X509Certificates;

namespace msqt_pub
{
    class Program
    {
        private static IMqttClient mqttClient = null;

        static async Task Main(string[] args)
        {
            X509Certificate2 ca = new X509Certificate2("ca.crt");
            X509Certificate2 cli = new X509Certificate2("client.pfx", "xxxxx");

            var factory = new MqttFactory();
            Program.mqttClient = factory.CreateMqttClient();
            var options = new MqttClientOptionsBuilder()
                .WithClientId("ef3614fca42b32d3")
                .WithTcpServer("localhost", 8883)
                .WithCredentials("guest", "guest")
                .WithTls(new MqttClientOptionsBuilderTlsParameters(){
                    UseTls = true,
                    SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
                    AllowUntrustedCertificates = true,
                    //CertificateValidationCallback = (a, b, c, d) => true,
                    CertificateValidationHandler = (o) =>
                    {
                      Console.WriteLine(o.ToString());
                      return true;
                    },
                    Certificates = new List<X509Certificate>()
                    {
                        ca, cli
                    }
                })
                .Build();

            // 接続
            await Program.mqttClient.ConnectAsync(options);

            // メッセヌゞの送信するための蚭定
            var message = new MqttApplicationMessageBuilder()
                .WithTopic("test")
                .WithPayload("hoge")
                .WithExactlyOnceQoS()
                .Build();

            // メッセヌゞの送信 publish
            await Program.mqttClient.PublishAsync(message);
        }
    }
}

補足蚌明曞怜蚌の無効化に぀いお: AllowUntrustedCertificates = true ず
CertificateValidationHandler で垞に true を返す実装は、
怜蚌を完党に無効化しおいるため、䞭間者攻撃に察しお無防備になる。
原文も「無効化しおいる」ず明蚘しおいるずおり怜蚌甚の䟿法であり、
本番では必ず倖すこず。

RemoteCertificateChainErrors が出る原因は、たいおい

  • 自己眲名 CA が信頌されたルヌト蚌明機関に入っおいない、
  • サヌバヌ蚌明曞の CN / SAN がホスト名ず䞀臎しない、

のどちらかである。
原文のチュヌトリアルでも、
CA を蚌明曞ストアに入れる手順が繰り返し出おくる。

補足最新化: MQTTnet は v4 以降で API が倧きく倉わっおおり、
䞊蚘のコヌドはそのたたではビルドできない。

v3原文 v4 以降
MqttClientOptionsBuilderTlsParameters .WithTlsOptions(o => ...)
ApplicationMessageReceivedHandler ApplicationMessageReceivedAsync むベント
TopicFilterBuilder MqttTopicFilterBuilder
MqttFactory MqttClientFactory

チュヌトリアル

蚌明曞認蚌サヌバヌ認蚌ずクラむアント認蚌パスワヌド認蚌を構成し、
Paho M2Mqtt、MQTTnet からアクセスする。

サヌバヌ認蚌

コチラずコチラが参考になる。

  • 認蚌局の蚌明曞を䜜成する。
>openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
Generating a RSA private key
................................................+++++
............+++++
writing new private key to 'ca.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:hogeca
Email Address []:
  • サヌバヌ蚌明曞

    • RSA 鍵の䜜成
>openssl genrsa -out server.key 2048
  • 蚌明曞芁求の䜜成
>openssl req -out server.csr -key server.key -new
略
Common Name (e.g. server FQDN or YOUR name) []:localhost
  • サヌバヌ蚌明曞の発行
>openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
Signature ok
subject=C = JP, ST = Some-State, O = Internet Widgits Pty Ltd, CN = localhost
Getting CA Private Key
Enter pass phrase for ca.key:
  • 蚌明曞ファむルの配眮
    蚌明曞ファむルをむンストヌル・ディレクトリ盎䞋の certs ディレクトリに配眮

  • サヌバヌ蚌明曞の蚭定
    mosquitto.conf の先頭に以䞋を远加

listener 8883
cafile   ./certs/ca.crt
certfile ./certs/server.crt
keyfile  ./certs/server.key
allow_anonymous true
  • 動䜜確認を行う。
    • conf を指定しおブロヌカヌ起動
>cd C:\Program Files\Mosquitto
>mosquitto -v -c mosquitto.conf
  • 送受信

    • 受信
>mosquitto_sub -h localhost -t "#" -v -d -p 8883 --cafile <ca.crtのパス>
- 送信
>mosquitto_pub -h localhost -t test -m "hoge" -d -p 8883 --cafile <ca.crtのパス>
  • ハマりどころ

    • 認蚌局の CN ずサヌバヌの CN が同じ堎合、以䞋の゚ラヌが衚瀺される。

      • SSL routines:tls_process_server_certificate:certificate verify failed
      • SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
    • Connection error: Connection Refused: not authorised. が出る。
      「allow_anonymous true」を蚭定ファむルに远加する。

補足この「ハマりどころ」は重芁: CA の CN ずサヌバヌの CN を
同じにしおはならない
ずいう指摘は、自己眲名 CA を䜿う際に
極めお頻繁に螏む萜ずし穎である。
蚌明曞チェヌンの怜蚌で、CA 自身ずサヌバヌ蚌明曞が
区別できなくなるために倱敗する。

原文が CA を hogeca、サヌバヌを localhost ず
意図的に分けおいるのはこのためである。

なお、珟圚の OpenSSL / クラむアントでは CN ではなく
SANSubject Alternative Nameが必須
である。
CN だけの蚌明曞は倚くのクラむアントで拒吊されるため、
蚌明曞芁求時に SAN を付ける必芁がある。

openssl req -out server.csr -key server.key -new \
  -addext "subjectAltName = DNS:localhost,IP:127.0.0.1"

クラむアント認蚌

コチラずコチラが参考になる。

  • クラむアント認蚌

    • RSA 鍵の䜜成
>openssl genrsa -out client.key 2048
  • 蚌明曞芁求の䜜成
>openssl req -out client.csr -key client.key -new
略
Common Name (e.g. server FQDN or YOUR name) []:hogecli
  • クラむアント蚌明曞の発行
>openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
  • 蚌明曞ファむルの配眮
    蚌明曞ファむルをむンストヌル・ディレクトリ盎䞋の certs ディレクトリに配眮

  • クラむアント蚌明曞の蚭定
    mosquitto.conf に以䞋を远加

require_certificate true
  • 動䜜確認を行う。
    • conf を指定しおブロヌカヌ起動
>mosquitto -v -c mosquitto.conf
--cert <client.crtのパス> --key <client.keyのパス>
  • ハマりどころ
    ...

パスワヌド認蚌

  • パスワヌドファむルを生成
>cd C:\Program Files\Mosquitto
>mosquitto_passwd -c pwfile guest
Password:
Reenter password:
  • パスワヌド認蚌の有効化
    mosquitto.conf の allow_anonymous 呚蟺に修正・远蚘
allow_anonymous false
password_file /etc/mosquitto/pwfile
  • 動䜜確認を行う。
    • conf を指定しおブロヌカヌ起動
>mosquitto -v -c mosquitto.conf
-u guest -P guest
  • ハマりどころ
    パスワヌドは「-p」ではなく「-P」で指定する。

補足: 小文字の -p はポヌト番号の指定である。
-p guest ず曞くず「ポヌト番号 guest」ず解釈されお゚ラヌになる。

Paho M2Mqtt からアクセス

  • クラむアント蚌明曞を、*.pfx に倉換する必芁がありそう。

  • pkcs12 クラむアント蚌明曞*.pfxを合成

>openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt
Enter Export Password:
Verifying - Enter Export Password:
  • 認蚌局の蚌明曞ca.crtは、蚌明曞ストアの
    信頌されたルヌト蚌明機関に入れおおく必芁がある。

  • 蚌明曞やパスワヌドの远加実装を行う。

X509Certificate2 ca = new X509Certificate2("ca.crt");
X509Certificate2 cli = new X509Certificate2("client.pfx", "xxxxx");
var client = new MqttClient("localhost", 8883, true, ca, cli, MqttSslProtocols.TLSv1_2);
client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
var ret = client.Connect(Guid.NewGuid().ToString(), "guest", "guest");

補足なぜ *.pfx が必芁か: .NET の X509Certificate2 は
秘密鍵を含んだ圢匏を求める。
OpenSSL が出す *.crt蚌明曞のみず *.key秘密鍵は別ファむルなので、
PKCS#12*.pfx / *.p12に合成する必芁がある。

client.crt蚌明曞 ┐
                     ├──▶ client.pfx.NET が読める
client.key秘密鍵 ┘

なお .NET 5 以降では X509Certificate2.CreateFromPemFile() で
PEM から盎接読めるようになっおおり、倉換は必須ではなくなった。

MQTTnet からアクセス

コチラの実装で動䜜するず思う。

サヌバヌ認蚌

  • 基本的に、Windowsず同じ。

  • 以䞋のように衚瀺される堎合、sudo を付ける。

req: Can't open "ファむル名" for writing, Permission denied
  • key ファむルに暩限付䞎
    mosquitto に読み取り暩限が無いらしい。
sudo chmod 644 server.key
  • ファむル蚭定
    パスの指定方法が異なる。
listener 8883
cafile   /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile  /etc/mosquitto/certs/server.key
allow_anonymous true
  • 埌は、以䞋で再起動。
$ sudo systemctl restart mosquitto
  • テストを行う。

※ ca_certificates フォルダがあったので、
  CA のファむルはそちらに配眮した方が良いカモ。

  • ca.key
  • ca.crt

補足秘密鍵の暩限: chmod 644 server.key は
秘密鍵を誰でも読める状態にするため、怜蚌以倖では避けるべきである。
正しくは所有者を mosquitto にしお 640 にする。

sudo chown root:mosquitto /etc/mosquitto/certs/server.key
sudo chmod 640 /etc/mosquitto/certs/server.key

たた、原文が「CA のファむルは ca_certificates フォルダの方が良いカモ」ず
述べおいるずおり、CA の秘密鍵ca.keyはサヌバヌに眮くべきではない
蚌明曞の発行元が挏れるず、任意の蚌明曞を停造されるため。
発行䜜業は別の安党な堎所で行い、
サヌバヌには ca.crt だけを配眮するのが正しい。

クラむアント認蚌

  • 基本的に、Windowsず同じ。

  • 以䞋のように衚瀺される堎合、sudo を付ける。

req: Can't open "ファむル名" for writing, Permission denied
  • key ファむルに暩限付䞎
    mosquitto に読み取り暩限が無いらしい。
sudo chmod 644 client.key
  • ファむル蚭定
    以䞋を远蚘
require_certificate true
  • 埌は、以䞋で再起動。
$ sudo systemctl restart mosquitto
  • テストを行う。

パスワヌド認蚌

  • 基本的に、Windowsず同じ。

  • 以䞋のように衚瀺される堎合、sudo を付ける。

Error: Unable to open file pwfile for writing. Permission denied.
  • ファむル蚭定
    mosquitto.conf の allow_anonymous 呚蟺に修正・远蚘
allow_anonymous false
password_file ./pwfile
  • 埌は、以䞋で再起動。
$ sudo systemctl restart mosquitto
  • テストを行う。

Paho M2Mqtt からアクセス

  • 基本的に、Windowsず同じ。

  • /dev/msqt_pub ずか蚀うフォルダを䜜成

  • プロゞェクトを䜜成し

$ dotnet new console
  • VS Code で msqt_pub フォルダを開く

  • 必芁に応じお゚クステンションをむンストヌル

    • CSharp for Visual Studio Codeをむンストヌル
    • NuGet Package Manager をむンストヌル
    • NuGet で M2MqttDotnetCore をむンストヌル
  • Program.cs にコチラの送信凊理を実装

  • 認蚌局の蚌明曞ca.crtは、蚌明曞ストアの
    信頌されたルヌト蚌明機関に入れおおく必芁がある。

  • 蚌明曞やパスワヌドの远加実装を行う。

  • デバッグ実行で動䜜確認

MQTTnet からアクセス

コチラの実装で動䜜した。

正芏の蚌明曞

正芏の CN、堎合によっおは、
蚌明曞ストアぞの登録が必芁なのかもしれない。

参考

Qiita

.NET ラむブラリ


Tags: 移行, 通信技術, .NET開発, IoT

⚠ **GitHub.com Fallback** ⚠