認可
EMQXにおける認可とは、MQTTクライアントのパブリッシュ/サブスクライブ操作に対する権限管理を指します。クライアントがパブリッシュ/サブスクライブ操作を行う際、EMQXは特定の手順に従うか、ユーザー指定のクエリ文を使用して、設定されたデータソースからクライアントの権限リストを照会します。照会結果に基づき、EMQXは現在の操作を許可または拒否します。
クライアントの単一の権限データは以下の要素で構成されます:
| 権限 | クライアント | 操作 | 操作の詳細 |
|---|---|---|---|
| Allow/Deny | クライアントID/ユーザー名/IP | パブリッシュ/サブスクライブ/パブリッシュ-サブスクライブ | トピック/QoS/保持メッセージ |
TIP
EMQX 5.1.1以降、操作の詳細におけるQoSおよび保持メッセージのチェックがサポートされました。
クライアントの権限リストは、事前に特定のデータソース(データベース、ファイルなど)に保存しておく必要があります。対応するデータレコードを更新することで、実行時にリストを更新可能です。更新されたルールの適用タイミングについては、認可ルール変更の反映タイミングをご参照ください。
EMQXではデフォルトでファイルベースのオーソライザーが設定されており、そのまま利用可能です。認可はACLファイルに設定された事前定義ルールに基づいて処理されます。
データストレージオブジェクトとの統合
EMQXの認可機構は、組み込みデータベース、ファイル、MySQL、PostgreSQL、MongoDB、Redisなど、さまざまなデータストレージオブジェクトとの統合をサポートしています。権限データはREST APIやEMQXダッシュボードを通じて管理可能です。
さらに、EMQXはユーザーが開発したHTTPサービスにも接続でき、さまざまな認可要件に対応可能です。
バックエンドのデータストレージに応じて、以下のように複数の種類のEMQXオーソライザーがあります。各オーソライザーには独自の設定オプションがあります。詳細は表内のリンクをクリックしてください。
| データベース | 説明 |
|---|---|
| ACLファイル | ファイルに設定された静的ルールによる認可 |
| 組み込みデータベース | 組み込みデータベースをルールストレージとした認可 |
| MySQL | MySQLをルールストレージとした認可 |
| PostgreSQL | PostgreSQLをルールストレージとした認可 |
| MongoDB | MongoDBをルールストレージとした認可 |
| Redis | Redisをルールストレージとした認可 |
| LDAP | LDAPディレクトリをルールストレージとした認可 |
| HTTP | 外部HTTPサービスによる認可 |
以下はEMQXのMySQLオーソライザーの設定例です。
例:
{
type = mysql
database = "mqtt"
username = "root"
password = "public"
query = "SELECT permission, action, topic FROM mqtt_acl WHERE username = ${username}"
server = "10.12.43.12:3306"
}認可チェーン
EMQXでは、単一のオーソライザーではなく複数のオーソライザーを設定して認可チェーンを作成し、認可をより柔軟に行うことができます。EMQXはチェーン内のオーソライザーの順序に従い、順次認可処理を行います。認可チェーンが設定されている場合、最初のオーソライザーで該当する認可情報が取得できないときは、次のオーソライザーに切り替えて処理を継続します。
オーソライザーはプリコンディションもサポートしています。オーソライザーにpreconditionが設定されている場合、EMQXはオーソライザーのデータソースを呼び出す前にプリコンディション式を評価します。式の評価結果がtrueのときのみオーソライザーを呼び出します。結果がtrueでないか、評価中にエラーが発生した場合は、そのオーソライザーをスキップし、認可チェーン内の次の有効なオーソライザーに処理を移します。
認可チェックの処理手順は以下の通りです:
現在のオーソライザーに
preconditionが設定されている場合、EMQXはまずプリコンディション式を評価します。結果がtrueでなければ、当該オーソライザーをスキップします。EMQXがクライアントの権限情報を正常に取得できた場合、クライアントの操作と取得した権限リストを照合します。
- 一致すれば、権限設定に基づいて操作を許可または拒否します。
- 一致しなければ、次のオーソライザーに切り替えて処理を継続します。
EMQXがクライアントの権限情報を取得できなかった場合、他にオーソライザーが設定されているか確認します。
- あれば、次のオーソライザーに切り替えて処理を継続します。
- 最後のオーソライザーであれば、
no_matchの設定に従いクライアントの操作を許可または拒否します。
注意
認可の問題を避けるため、必要に応じてACLファイルオーソライザーを無効化または削除することを忘れないでください。ACLファイルオーソライザーはデフォルトで末尾に{allow, all}があり、すべての認可リクエストを許可するためです。
オーソライザーの順序変更方法や実行中のメトリクス確認方法については、オーソライザー管理をご参照ください。
オーソライザーのプリコンディション
EMQX 6.3以降、各オーソライザーにプリコンディションを割り当てて、特定の認可リクエストに対して呼び出すかどうかを制御できます。
プリコンディションはVariform式で、listener、username、clientid、action、topicなどのクライアントおよび認可リクエスト情報を評価します。式がtrueと評価されない場合、オーソライザーはスキップされます。
例えば、ビジネスライン、クライアント属性、パブリッシュ/サブスクライブ操作、トピック範囲に基づいて認可リクエストを異なるバックエンドにルーティングできます。空のpreconditionはプリコンディションなしを意味し、オーソライザーは認可チェーンの位置に従って通常通り実行されます。
preconditionで利用可能なクライアント変数は以下の通りです:
username:クライアントのユーザー名clientid:クライアントIDclient_attrs.*:クライアント属性。例:client_attrs.tenant。詳細はMQTTクライアント属性を参照。cert_common_name:クライアントTLS証明書のCommon Name(CN)cert_subject:クライアントTLS証明書のSubjectpeersni:TLSクライアントが送信するSNI(Server Name Indication)listener:クライアントが使用するリスナーID。例:tcp:defaultzone:クライアントに関連付けられた設定ゾーン
preconditionで利用可能な認可リクエスト変数は以下の通りです:
action:現在の認可アクション。値はpublishまたはsubscribetopic:現在チェック中のパブリッシュトピックまたはサブスクリプショントピックフィルター
以下の例はpreconditionに関連するフィールドのみを示しています。HTTPオーソライザーはordersビジネスクライアントのパブリッシュリクエストのみ処理し、Redisオーソライザーはdevices/${clientid}/#トピックフィルターにマッチするリクエストのみ処理します。
authorization {
sources = [
{
type = http
precondition = "iif(str_eq(client_attrs.biz, 'orders'), str_eq(action, 'publish'), false)"
...
},
{
type = redis
precondition = "topic_match(topic, topic_join(['devices', clientid, '#']))"
...
}
]
}この例の説明:
iif(str_eq(client_attrs.biz, 'orders'), str_eq(action, 'publish'), false):クライアント属性client_attrs.bizがordersで、現在の認可アクションがpublishの場合にtrueとなる式topic_match(topic, topic_join(['devices', clientid, '#'])):現在の認可リクエストのトピックがdevices/${clientid}/#トピックフィルターにマッチする場合にtrueとなる式
認可ルール変更の反映タイミング
ルール変更は、EMQXが更新されたルールを次回評価した際に反映されます。クライアント認可キャッシュに該当結果が存在する場合、キャッシュが期限切れまたはクリアされるまでキャッシュ結果を使用し続けます。ルール変更は既に確立されたサブスクリプションを取り消しません:
- 接続中のクライアントは、許可されたトピックのメッセージを接続期間中受信し続けます。
deny_actionは適用されません。メッセージ配信はパブリッシュやサブスクライブの試行を伴わないためです。 - 永続セッション(
clean_start = false)で再接続したクライアントは、ブローカーにより保存されたサブスクリプションが復元され、オフライン中にキューイングされたメッセージを受信します。
既にサブスクライブ済みのクライアントから読み取りアクセスを取り消すには、ルールを変更し、クライアントのセッションを削除してください。例えば、DELETE /api/v5/clients/{clientid}を使ってクライアントを切断し、セッション状態を削除します。
クライアント認可キャッシュ
EMQXはセッションベースの認可データキャッシュ機構を提供しています。このキャッシュはクライアントのセッション状態に認可結果を保存し、同一接続中の認可ルール評価の繰り返しを減らします。クライアント認可キャッシュ機構は、クライアントのパブリッシュ/サブスクライブ操作に対する権限チェックの効率を向上させ、多数のクライアントリクエストによる認可データバックエンドへのアクセス負荷を軽減します。
クライアント認可キャッシュの動作
クライアントが接続し、パブリッシュ/サブスクライブ操作を行う際:
- EMQXは現在のセッションに保存された認可キャッシュを確認します。
- セッションキャッシュに該当ルールがあれば、EMQXはそれを直接使用します。
- キャッシュされたルールが存在しないか期限切れの場合、EMQXは設定されたオーソライザーを使って完全な認可チェックを実行します。
- 結果は接続中の再利用のためセッションにキャッシュされます。
TIP
キャッシュはクライアントセッション固有であり、クライアントの切断または再接続時にクリアされます。キャッシュのクリアは既に確立されたサブスクリプションのルール再評価を行いません。詳細は認可ルール変更の反映タイミングを参照してください。
ダッシュボードでのクライアント認可キャッシュ設定
EMQXダッシュボードでクライアント認可キャッシュを有効化または設定できます:
アクセス制御 -> 認可 -> 設定 に移動します。
以下のオプションを設定します:
フィールド名 説明 キャッシュを有効にする クライアントセッションごとの認可キャッシュを有効/無効に切り替えます。 キャッシュ最大アイテム数 クライアントごとのキャッシュエントリ最大数。デフォルト: 32。キャッシュの有効期限 各キャッシュエントリの有効期間。デフォルト: 1分。除外トピック キャッシュを無効にするトピックのリスト。 マッチしない場合の動作 オーソライザーがマッチしなかった場合の動作。選択肢: allow(許可)/deny(拒否)。デフォルト:allow。拒否時の動作 操作が拒否された場合の動作。選択肢: ignore(操作リクエストを無視)/disconnect(クライアント接続を切断)。デフォルト:ignore。キャッシュクリア アクティブなセッション認可キャッシュを手動で全てクリアするボタン。 保存をクリックして設定を適用します。
これらのオプションは設定ファイルからも設定可能です。詳細は設定ファイルを参照してください。
TIP
適切に設定すればキャッシュはパフォーマンスを大幅に向上させます。システムのパフォーマンスに応じて適時設定を調整することを推奨します。
外部リソースキャッシュ
セッションベースのキャッシュに加え、EMQXはMySQL、MongoDB、Redisなどの外部バックエンドから取得した認可結果を保存するノードレベルのキャッシュもサポートしています。この機能はリモートデータソースへの繰り返しアクセスを減らし、パフォーマンスを向上させます。
注意
外部リソースキャッシュは外部データソースにのみ適用されます。組み込みデータベースやファイルベースのオーソライザーなどローカルソースには適用されません。
外部リソースキャッシュの動作
パブリッシュ/サブスクライブ操作が外部バックエンドのクエリをトリガーした場合:
- EMQXは外部リソースキャッシュ(ノード全体で共有)を確認します。
- キャッシュに有効な結果があれば、キャッシュヒットとなり外部バックエンドへの呼び出しは行われません。
- 結果がなければ、キャッシュミスとなり外部バックエンドにクエリを送信します。
- バックエンドから返された結果はキャッシュに保存され、キャッシュ挿入メトリクスが増加します。
注意
セッションベースの認可キャッシュと異なり、外部リソースキャッシュはノード全体で共有され、クライアントセッションをまたいで持続します。
外部リソースキャッシュの有効化と設定
EMQXダッシュボードから外部リソースキャッシュを有効化・設定できます:
アクセス制御 -> 認可 に移動します。
右上の外部リソースキャッシュ設定ボタンをクリックすると、右側からパネルが表示されます。
パネル内の外部リソースキャッシュを有効にするボタンでキャッシュ機能をオン/オフ切り替えます。有効化後、以下のキャッシュ設定を行います:
フィールド名 説明 キャッシュ最大アイテム数 ノードごとのキャッシュエントリ最大数。デフォルト: 1,000,000。最大メモリ使用量 キャッシュのメモリ使用上限。デフォルト: 100 MB。キャッシュTTL キャッシュエントリの有効期間。デフォルト: 1分。更新をクリックして設定を適用します。
これらの設定はクラスター全体に適用され、全ノードで一貫した動作を保証します。
外部リソースキャッシュの状態監視
キャッシュメトリクスを表示し、リアルタイムで使用状況を監視するには:
- External Resource Cache Settings の横にある矢印をクリックし、External Resource Cache Status を選択します。サイドパネルが表示され、キャッシュメトリクスが確認できます。
- ドロップダウンメニューを使用して、ノード単位またはクラスター全体のメトリクスを表示します。
メトリクスには以下が含まれます:
- Memory Usage:キャッシュが現在使用している合計メモリ量。
- Cache Entries:保存されているキャッシュ結果の総数。
- Cache Hits:EMQXがキャッシュ内で有効な結果を見つけ、外部バックエンドへの呼び出しを回避した回数。
- 表示されるメトリクス:現在のレート、5分間の平均、最大レート
- Cache Misses:EMQXがキャッシュ内で結果を探したが見つからず、バックエンドクエリが発生した回数。
- 表示されるメトリクス:現在のレート、5分間の平均、最大レート
- Cache Inserts:ミス後にキャッシュに新たに追加された結果の数。
- 表示されるメトリクス:現在のレート、5分間の平均、最大レート
パネル下部のノードリストでは、クラスター内の各ノードの Memory Usage、Cache Entries、および Cache Hits の概要を確認できます。
パネル右上のボタンで統計情報の更新やリセットが可能です。
認可プレースホルダー
EMQXのオーソライザーは設定内でプレースホルダーを使用できます。認可処理時にこれらは実際のクライアント情報に置き換えられ、現在のクライアントにマッチするクエリやHTTPリクエストが構築されます。
有効なプレースホルダーは${PATH.TO.VALUE}の形式で、PATH.TO.VALUEはオブジェクト内の値へのドット区切りパスです。有効な文字は英数字、ドット(.)、アンダースコア(_)です。サポート外の文字を含むプレースホルダーはプレーンテキストとして扱われます。
データクエリ内のプレースホルダー
プレースホルダーはクエリ文の構築に使用されます。例えば、EMQXのMySQLオーソライザーのデフォルトクエリSQLは${username}プレースホルダーを使用しています:
SELECT action, permission, topic FROM mqtt_acl where username = ${username}クライアント(名前:emqx_u)が接続要求を送ると、構築されるクエリ文は以下のようになります:
SELECT action, permission, topic FROM mqtt_acl where username = 'emqx_u'クエリ文でサポートされるプレースホルダーは以下の通りです:
${username}:実行時にユーザー名に置き換えられます。ユーザー名はCONNECTパケットのUsernameフィールドから取得されます。peer_cert_as_usernameが有効な場合は証明書のフィールドや内容で上書きされます。${clientid}:実行時にクライアントIDに置き換えられます。通常はクライアントがCONNECTパケットで明示的に指定します。use_username_as_clientidやpeer_cert_as_clientidが有効な場合はユーザー名や証明書のフィールド、内容で上書きされます。${peerhost}:実行時にクライアントの送信元IPアドレスに置き換えられます。Proxy Protocolが有効な場合はプロキシが報告する送信元IPを使用します。${peerport}:EMQX 6.3.0以降、実行時にクライアントの送信元ポート番号(例:51544)に置き換えられます。Proxy Protocolが有効な場合はプロキシが報告する送信元ポートを使用します。${peername}:EMQX 6.3.0以降、実行時にクライアントの送信元IPアドレスとポート番号に置き換えられます。IPv4の場合はIP:port形式(例:192.168.0.1:51544)、IPv6の場合は角括弧なし(例:2001:db8::1:51544)です。Proxy Protocolが有効な場合はプロキシが報告するIPとポートを使用します。${cert_common_name}:実行時にクライアントTLS証明書のCommon Nameに置き換えられます。ロードバランサーがTCPリスナーにクライアント証明書情報を送信する場合はProxy Protocol v2の使用を推奨します。${cert_subject}:実行時にクライアントTLS証明書のSubjectに置き換えられます。ロードバランサーがTCPリスナーにクライアント証明書情報を送信する場合はProxy Protocol v2の使用を推奨します。${client_attrs.NAME}:クライアント属性。NAMEは事前設定に基づく属性名に置き換えられます。詳細はMQTTクライアント属性を参照してください。${zone}:実行時にクライアントのゾーンに置き換えられます。${zone}プレースホルダーは認可テンプレートで直接使用可能です。ゾーン設定の詳細はゾーンオーバーライドを参照してください。
TIP
${peerhost}および${peerport}プレースホルダーは非推奨です。後方互換性のため残されています。新規テンプレートでは${peername}の使用を推奨します。
LDAPオーソライザーは${peerport}および${peername}プレースホルダーをサポートしていません。
トピック内のプレースホルダー
EMQXはトピック内でのプレースホルダー使用も許可し、動的トピックをサポートします。サポートされるプレースホルダーは以下の通りです:
${clientid}${username}${client_attrs.NAME}:クライアント属性。NAMEはmqtt.client_attrs_initで設定された属性名抽出ルールに置き換えられます。
プレースホルダーはトピックセグメントとして使用可能で、例:a/b/${username}/c/dのように記述します。
EMQX 6.3.0以降、認可トピックテンプレートに補間される値は検証されます。デフォルトでは、補間値にトピックレベル区切り文字(/)やMQTTトピックフィルターのワイルドカード(+、#)を含めることはできません。この制限はテンプレート内に直接記述された区切り文字やワイルドカードには適用されません。
例えば、ユーザー名がaliceの場合、tenant/${username}/#はtenant/alice/#に展開されます。ユーザー名がtenant/aliceや+の場合、補間値に禁止文字が含まれるためテンプレートは展開できません。
補間値に禁止文字が含まれる場合、EMQXはアクティブなセキュリティプロファイルに従い認可ルールを処理します:
legacyプロファイルではルールはマッチせず、EMQXは残りの認可ルールとソースを継続処理します。hardenedプロファイルではパブリッシュまたはサブスクライブ操作を拒否します。authorization.ignore_backend_failuresがtrueの場合は代わりにルールをマッチしないものとして扱います。
EMQX 6.3.0のデフォルトセキュリティプロファイルはlegacyで、authorization.ignore_backend_failuresはfalseがデフォルトです。6.3.0にアップグレード後、アップグレード前に設定されたルールは補間値に禁止文字が含まれるとデフォルトのlegacyプロファイル下でマッチしなくなります。最終結果は残りの認可ルール、認可ソース、authorization.no_matchの設定に依存します。アップグレード前にこれら設定を確認し、期待するフォールバック動作を確認してください。
authorization.topic_template_allow設定は補間値に許可する文字を制御します。すべての設定はデフォルトでfalseです:
authorization.topic_template_allow {
plus = false
hash = false
slash = false
}対応する文字を含む必要がある場合のみtrueに設定してください。これらを有効にすると、クライアント由来の値が認可ルールのトピックフィルターを広げる可能性があります。ユーザー名、クライアントID、クライアント属性の値はトピックテンプレートで使用する前に検証してください。
プレースホルダーの補間を回避するには、EMQX 5.4以降、$を${$}とエスケープできます。例:t/${$}{username}はusernameを置き換えず文字通りt/${username}として扱われます。
TIP
クエリ文でeq構文を使用する場合、eqの後に続くトピックはプレースホルダー補間をサポートしない点に注意してください。この挙動は将来のバージョンで変更される可能性があります。
eq構文はトピックフィルターと完全一致するものをマッチさせるためのものであり、フィルターにマッチする任意のトピックをマッチさせるものではありません。例:eq t/#はt/#にのみマッチし、t/1やt/2にはマッチしません。
認可チェックの優先順位
キャッシュや認可チェッカーに加え、認可結果は認証フェーズ中のスーパーユーザーロールと権限セットによっても影響を受けます。
スーパーユーザーの場合、すべての操作は認可チェックをスキップします。もしアクセス制御リスト(ACL)が設定されていれば、EMQXは認可チェッカーを実行する前にクライアントの権限データに従います。優先順位は以下の通りです:
スーパーユーザー > 権限データ > 認可チェック認可機構の設定
EMQXは認可設定に以下の3つの方法を提供しています:ダッシュボード、設定ファイル、HTTP API。
ダッシュボードでの認可設定
EMQXダッシュボードは直感的なインターフェースで、オーソライザーの関連パラメーター設定、動作状況の確認、認可チェーン内の位置調整が可能です。

設定ファイルでの認可設定
設定ファイルのauthorizationフィールドで認可を設定することも可能です。一般的な設定構造は以下の通りです:
authorization {
sources = [
{ ... },
{ ... }
]
no_match = deny
deny_action = ignore
cache {
max_size = 32
excludes = ["t/1", "t/2"]
ttl = 1m
}
}ここで、
sources(任意):順序付き配列。各要素は対応するオーソライザーのデータソースを定義します。詳細設定は各オーソライザーの設定ファイルを参照してください。sources[].precondition:オーソライザー呼び出し前にスキップ判定を行うVariform式。空の場合はプリコンディションなし。
no_match:設定されたオーソライザーのいずれも認可ルールを見つけられなかった場合のデフォルト動作。任意値:allowまたはdeny。EMQX 6.0以降、デフォルトはdenyに変更。deny_action:パブリッシュ/サブスクライブ操作が拒否された場合の次の動作。任意値:ignoreまたはdisconnect。デフォルトはignore。ignoreは操作を静かに無視し、disconnectはクライアント接続を切断。cache:クライアント認可キャッシュ設定。内容は以下:cache.enable:クライアント認可キャッシュを有効にするかどうか。デフォルトはtrue。JWTパケットのみで認可を行う場合はfalseに設定推奨。cache.max_size:キャッシュ内の最大要素数。デフォルトは32。指定数を超えると古いレコードから削除。cache.excludes:認可キャッシュを生成しない除外トピックのリスト。デフォルトは空配列[]。cache.ttl:キャッシュ値の有効期間。デフォルトは1m(1分)。
TIP
信頼できないまたはパブリックネットワークに公開されたブローカーでは、deny_actionをdisconnectに設定すると、同一接続での不正なパブリッシュやサブスクライブ試行を停止できます。フラッピング検知と組み合わせると、認可拒否が繰り返されるクライアントを一定期間自動的に禁止できます。
deny_action設定はグローバルで、リスナーごとに設定できません。また、拒否された操作を試みる正当なクライアントも切断されます。クライアントが通常許可されたトピックのみでパブリッシュ/サブスクライブする場合にdisconnectを使用し、フラッピング検知の閾値を調整して正常な再接続時の禁止を防止してください。
HTTP APIでの認可設定
認可管理用のAPIエンドポイントは以下の通りです:
/api/v5/authorization/settings:一般パラメーター、no_match、deny_action、cacheの管理/api/v5/authorization/sources:オーソライザーの管理と順序調整/api/v5/authorization/cache:クライアント認可キャッシュのクリア/api/v5/authorization/sources/built_in_database:built_in_databaseオーソライザーの認可ルール管理
詳細な操作手順はHTTP APIを参照してください。
オーソライザー管理
ダッシュボードのアクセス制御->認可ページでオーソライザーの閲覧と管理が可能です。
オーソライザーの順序調整
認可チェーンで述べたように、オーソライザーは設定された順序で実行されます。その他ドロップダウンから上へ移動、下へ移動、先頭へ移動、末尾へ移動を選択してオーソライザーの位置を変更できます。authorization.sources設定項目でも順序調整可能です。
オーソライザーの状態確認
状態列で接続状況を確認できます:
| 状態 | 意味 | トラブルシューティング |
|---|---|---|
| Connected | すべてのノードがデータソースに正常接続している状態。 | - |
| Disconnected | 一部または全ノードがデータソース(データベース、ファイル)に接続できていない状態。 | データソースの稼働状況を確認。 問題解決後、オーソライザーを手動で再起動(無効化→有効化)してください。 |
| Connecting | 一部または全ノードがデータソースに再接続中の状態。 | データソースの稼働状況を確認。 問題解決後、オーソライザーを手動で再起動(無効化→有効化)してください。 |
実行中のメトリクス
オーソライザーの概要ページで統計メトリクスを確認できます。以下のメトリクスが表示されます:
- Allow:認可成功数
- Deny:認可失敗数
- No match:クライアント認可データが見つからなかった回数
- Ignored:認可クエリが無視された回数(例:オーソライザーの
preconditionがtrueでない場合や、認可ソースが適用不可またはエラーで判定不能な場合) - Rate(tps):認可実行レート(トランザクション毎秒)
また、ノードステータスで各ノードの認可状態および実行状況を確認可能です。
認可全体の実行メトリクスを確認する場合は、メトリクス - 認証&認可を参照してください。