マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

MQTTブローカーのOSS

詳細

ブローカーモデル

Producer

送信する人

Consumer

受信する人

Message

送受信対象のメッセージ

Queue

キュー

Topic

  • トピック
    • / から始まる Unicode UTF-8 文字列
    • 全長 65535 バイト以下
    • ヌル文字を含まない
  • ワイルドカード
    • #:マルチレベル・ワイルドカード(その階層以下の全トピック文字列と一致)
    • +:シングルレベル・ワイルドカード(当該階層以下の全トピック文字列と一致)

Windows

インストール

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
  • ブローカー起動
    不要

Docker on Windows

ミドルウェアなので、コチラの作法で動かせるっぽい。
(ただし、コンフィグ・ファイルの準備は必要)

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

Docker on Raspberry Pi

...

SaaS / PaaS

  • Azure:Azure IoT Hub
  • Azure:AWS IoT Core(ブリッジ機能)
  • GCP:Cloud Pub/Sub?

認証

パスワード

  • Linux
  • Windows

証明書

  • サーバー認証とクライアント認証の両方が可能。
  • 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);
                }
            }
        }
    }

MQTTnet

更新が頻繁で、トータル・ダウンロードがPaho M2Mqttの4倍以上

  • 以下は認証フル実装だが、証明書検証を無効化している。
    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);
            }
        }
    }

チュートリアル

証明書認証(サーバー認証とクライアント認証)+パスワード認証を構成し、Paho M2MqttMQTTnetからアクセスする。

Windows

サーバー認証

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

  • 認証局の証明書を作成する。
    >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:
    -----
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    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
    Generating RSA private key, 2048 bit long modulus (2 primes)
    ..............+++++
    e is 65537 (0x010001)
  • 証明書要求の作成
    >openssl req -out server.csr -key server.key -new
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    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) []:localhost
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
  • サーバー証明書の発行
    >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
  • 送受信
  • 受信
    >cd C:\Program Files\Mosquitto
    >mosquitto_sub -h localhost -t "#" -v -d -p 8883 --cafile <ca.crtのパス>
  • 送信
    >cd C:\Program Files\Mosquitto
    >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」を設定ファイルに追加する。

クライアント認証

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

  • クライアント認証
  • RSA鍵の作成
    >openssl genrsa -out client.key 2048
    Generating RSA private key, 2048 bit long modulus (2 primes)
    ......+++++
    e is 65537 (0x010001)
  • 証明書要求の作成
    >openssl req -out client.csr -key client.key -new
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:
    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) []:hogecli
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
  • クライアント認証の発行
    >openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
    Signature ok
    subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = hogecli
    Getting CA Private Key
    Enter pass phrase for ca.key:
  • 証明書ファイルの配置
    証明書ファイルをインストール・ディレクトリ直下のcertsディレクトリに配置
  • クライアント証明書の設定
    mosquitto.confに以下を追加
    require_certificate true
  • 動作確認を行う。
    • confを指定してブローカー起動
      >cd C:\Program Files\Mosquitto
      >mosquitto -v -c mosquitto.conf
  • ハマりどころ
    ...

パスワード認証

  • パスワードファイルを生成
    >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を指定してブローカー起動
      >cd C:\Program Files\Mosquitto
      >mosquitto -v -c mosquitto.conf
  • ハマりどころ
    パスワードは「-p」ではなく「-P」で指定する。

Paho M2Mqtt からアクセス

  • 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");
  • デバッグ実行で動作確認
    WindowsはPublisherだけ動作確認済み。

MQTTnetからアクセス

コチラの実装で動作すると思う。

Linux

サーバー認証

  • 以下のように表示される場合、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

クライアント認証

  • 以下のように表示される場合、sudoを付ける。
    req: Can't open "ファイル名" for writing, Permission denied
  • keyファイルに権限付与
    mosquittoに読み取り権限が無いらしい。
    sudo chmod 644 client.key
  • ファイル設定
    以下を追記
    require_certificate true
  • 後は、以下で再起動。
    $ sudo systemctl restart mosquitto
  • テストを行う。

パスワード認証

  • 以下のように表示される場合、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 からアクセス

  • 以下のように表示される場合、sudoを付ける。
    Error: Unable to open file pwfile for writing. Permission denied.
  • /dev/msqt_pubとか言うフォルダを作成
  • プロジェクトを作成し
    $ dotnet new console
  • VS Codeでmsqt_pubフォルダを開く
  • 必要に応じてエクステンションをインストール
  • 認証局の証明書(ca.crt)は、証明書ストア
    信頼されたルート証明機関に入れておく必要がある。
  • 証明書やパスワードの追加実装を行う。

MQTTnetからアクセス

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

正規の証明書

正規のCN、場合によっては、
証明書ストアへの登録が必要なのかもしれない。

参考

Qiita

.NETライブラリ


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


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2022-01-30 (日) 15:40:35 (809d)