NGINX Plus の R29 リリースを発表した際に、 MQTTメッセージの解析に対する新しいネイティブ サポートについて簡単に説明しました。 この投稿では、それを基に、エンタープライズ環境での MQTT 展開を最適化するために NGINX Plus を構成する方法について説明します。
MQTT はMessage Queuing Telemetry Transportの略です。 これは非常に人気のある軽量のパブリッシュ/サブスクライブ メッセージング プロトコルであり、インターネット経由でモノのインターネット (IoT) またはマシン間 (M2M) デバイスとアプリケーションを接続するのに最適です。 MQTT は、低帯域幅または低電力環境で効率的に動作するように設計されているため、多数のリモート クライアントを持つアプリケーションに最適です。 家電、自動車、輸送、製造、医療など、さまざまな業界で使用されています。
NGINX Plus R29 はMQTT 3.1.1とMQTT 5.0をサポートしています。 これはクライアントとブローカー間のプロキシとして機能し、コアシステムからタスクをオフロードし、スケーラビリティを簡素化し、コンピューティング コストを削減します。 具体的には、NGINX Plus は MQTT CONNECTメッセージの一部を解析して書き換え、次のような機能を有効にします。
MQTTメッセージ処理ディレクティブは、NGINX構成ファイルのストリーム
コンテキストで定義する必要があり、 ngx_stream_mqtt_preread_module
によって提供されます。
およびngx_stream_mqtt_filter_module
。
事前読み取り
モジュールは、NGINX の内部プロキシの前に MQTT データを処理し、解析されたメッセージ データに基づいて負荷分散とアップストリーム ルーティングの決定を行うことができます。
フィルター
モジュールを使用すると、受信した CONNECT メッセージ内のclientid
、 username
、およびpassword
フィールドの書き換えが可能になります。 これらのフィールドを変数や複雑な値に設定できるため、構成オプションが大幅に拡張され、NGINX Plus で機密性の高いデバイス情報をマスクしたり、TLS 証明書の識別名などのデータを挿入したりできるようになります。
MQTT デプロイメントを最適化し、特定のニーズを満たすために NGINX 構成を調整するためのいくつかの新しいディレクティブと埋め込み変数が利用できるようになりました。
mqtt_preread
– MQTT 解析を有効にし、クライアント デバイスから送信された CONNECT メッセージからclientid フィールド
とusername
フィールドを抽出します。 これらの値は埋め込み変数を介して利用可能になり、ハッシュセッションが上流サーバーの負荷分散を行うのに役立ちます (以下の例を参照)。$mqtt_preread_clientid
– デバイスから送信された MQTT クライアント識別子を表します。$mqtt_preread_username
– 認証目的でクライアントから送信されたユーザー名を表します。mqtt
– MQTT 書き換えが有効かどうかを定義します。mqtt_buffers
– 接続ごとに割り当てることができる MQTT 処理バッファの最大数と各バッファのサイズをオーバーライドします。 デフォルトでは、NGINX は接続ごとに 100 バッファ (それぞれの長さは 1k) の制限を課します。 通常、これはパフォーマンスには最適ですが、特殊な状況では調整が必要になる場合があります。 たとえば、MQTT メッセージが長い場合は、より大きなバッファ サイズが必要になります。 短時間内に特定の接続に対して大量の MQTT メッセージを処理するシステムでは、バッファーの数を増やすことでメリットが得られる可能性があります。 ほとんどの場合、NGINX は内部メモリ プールからバッファを構築するため、バッファ パラメータを調整しても、基盤となるシステムのパフォーマンスにはほとんど影響しません。mqtt_rewrite_buffer_size
– MQTT メッセージの構築に使用されるバッファのサイズを指定します。 このディレクティブは非推奨となり、NGINX Plus R30 以降では廃止されています。mqtt_set_connect
– クライアントから送信された CONNECT メッセージのパラメータを書き換えます。 サポートされているパラメータには、 clientid
、 username
、 password など
があります。NGINX Plus を使用して MQTT メッセージを処理する利点と、関連するベスト プラクティスを詳しく見てみましょう。 以下の例ではポート 1883 と 8883 を使用していることに注意してください。 ポート 1883 はデフォルトのセキュリティ保護されていない MQTT ポートであり、8883 はデフォルトの SSL/TLS 暗号化ポートです。
MQTT デバイスの一時的な性質により、クライアント IP が予期せず変更される可能性があります。 これにより、デバイス接続を正しいアップストリーム ブローカーにルーティングするときに問題が発生する可能性があります。 その後、デバイス接続をある上流ブローカーから別の上流ブローカーに移動すると、ブローカー間の同期操作にコストがかかり、遅延とコストが増加する可能性があります。
MQTT CONNECT メッセージのclientid
フィールドを解析することにより、NGINX はアップストリーム サービス ブローカーへのスティッキー セッションを確立できます。 これは、バックエンドのブローカー サービスへの接続を維持するためのハッシュ キーとしてクライアント ID
を使用することで実現されます。
この例では、3 つの上流ブローカーへのスティッキー セッションを確立するためのトークンとしてクライアント ID
を使用して、MQTT デバイス データをプロキシします。 上流サーバーに障害が発生した場合、そのサーバーで既に確立されているセッションに影響を与えることなく、そのサーバーのトラフィックのシェアが残りのサーバー間で均等に分散されるように、consistent パラメータを使用します。
ストリーム { mqtt_preread on;
アップストリーム バックエンド {
zone tcp_mem 64k;
hash $mqtt_preread_clientid 一貫性あり;
server 10.0.0.7:1883; # アップストリーム MQTT ブローカー 1
server 10.0.0.8:1883; # アップストリーム MQTT ブローカー 2
server 10.0.0.9:1883; # アップストリーム MQTT ブローカー 3
}
server {
listen 1883;
proxy_pass backend;
proxy_connect_timeout 1s;
}
}
NGINX Plus は、MQTT CONNECT メッセージのユーザー名フィールドを解析することもできます。 詳細については、 ngx_stream_mqtt_preread_module
仕様を参照してください。
デバイス通信を暗号化することは、データの機密性を確保し、中間者攻撃から保護するための鍵となります。 ただし、TLS ハンドシェイク、暗号化、復号化は MQTT ブローカーのリソースに負担をかける可能性があります。 この問題を解決するために、NGINX Plus はブローカー (またはブローカーのクラスター) からデータ暗号化をオフロードし、セキュリティ ルールを簡素化して、ブローカーがデバイス メッセージの処理に集中できるようにします。
この例では、NGINX を使用して、デバイスからバックエンド ブローカーへの TLS 暗号化された MQTT トラフィックをプロキシする方法を示します。 ssl_session_cache
ディレクティブは 5 MB のキャッシュを定義します。これは約 20,000 の SSL セッションを保存するのに十分です。 NGINX は、 proxy_connect_timeout
ディレクティブで定義されているように、タイムアウトする前に 5 秒間プロキシされたブローカーにアクセスしようとします。
ストリーム { server {
listen 8883 ssl;
ssl_certificate /etc/nginx/certs/tls-cert.crt;
ssl_certificate_key /etc/nginx/certs/tls-key.key;
ssl_session_cache shared:SSL:5m;
proxy_pass 10.0.0.8:1883;
proxy_connect_timeout 5s;
}
}
セキュリティ上の理由から、クライアントを識別できる情報を MQTT ブローカーのデータベースに保存しないことを選択できます。 たとえば、デバイスは MQTT CONNECT メッセージの一部としてシリアル番号やその他の機密データを送信する場合があります。 デバイスの識別子をクライアントから受信した他の既知の静的値に置き換えることで、NGINX Plus プロキシ ブローカーにアクセスしようとするすべてのデバイスに対して代替の一意のキーを確立できます。
この例では、デバイスのクライアント SSL 証明書から一意の識別子を抽出し、それを使用して MQTT クライアント ID をマスクします。クライアント証明書認証 (相互 TLS) は、 ssl_verify_client
ディレクティブで制御されます。 on パラメータに設定すると、NGINX はクライアント証明書が信頼できる証明機関 (CA) によって署名されていることを確認します。 信頼できる CA 証明書のリストは、 ssl_client_certificate
ディレクティブによって定義されます。
ストリーム { mqtt オン;
server {
listen 8883 ssl;
ssl_certificate /etc/nginx/certs/tls-cert.crt;
ssl_certificate_key /etc/nginx/certs/tls-key.key;
ssl_client_certificate /etc/nginx/certs/client-ca.crt;
ssl_session_cache shared:SSL:10m;
ssl_verify_client オン;
proxy_pass 10.0.0.8:1883;
proxy_connect_timeout 1s;
mqtt_set_connect クライアント ID $ssl_client_serial;
}
}
MQTT クライアントを認証する一般的な方法の 1 つは、クライアント証明書に保存されているデータをユーザー名として使用することです。 NGINX Plus はクライアント証明書を解析し、MQTT ユーザー名フィールドを書き換えて、このタスクをバックエンド ブローカーからオフロードできます。 次の例では、クライアント証明書のサブジェクト識別名 (サブジェクト DN) を抽出し、それを MQTT CONNECT メッセージのユーザー名部分にコピーします。
ストリーム { mqtt オン;
server {
listen 8883 ssl;
ssl_certificate /etc/nginx/certs/tls-cert.crt;
ssl_certificate_key /etc/nginx/certs/tls-key.key;
ssl_client_certificate /etc/nginx/certs/client-ca.crt;
ssl_session_cache shared:SSL:10m;
ssl_verify_client オン;
proxy_pass 10.0.0.8:1883;
proxy_connect_timeout 1s;
mqtt_set_connect ユーザー名 $ssl_client_s_dn;
}
}
NGINX Plus MQTT CONNECT メッセージの書き換えに関する完全な仕様については、 ngx_stream_mqtt_filter_module
仕様を参照してください。
NGINX Plus の MQTT の今後の開発には、他の MQTT メッセージ タイプの解析や、次のような機能を実現するための CONNECT メッセージのより深い解析が含まれる可能性があります。
NGINX Plus を初めてご利用になる場合は、 30 日間の無料トライアルにサインアップして MQTT を使い始めてください。 お客様にとって最も重要な機能についてのフィードバックもぜひお聞かせください。 コメント欄であなたの考えをお聞かせください。
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"