認可
EMQXにおける認可とは、MQTTクライアントのパブリッシュ/サブスクライブ操作に対する権限管理を指します。クライアントがパブリッシュ/サブスクライブ操作を行う際、EMQXは特定の手順に従うか、ユーザー指定のクエリ文を使用して設定済みのデータソースからクライアントの権限リストを照会します。照会結果に基づき、EMQXは現在の操作を許可または拒否します。
クライアントの単一の権限データは以下の要素で構成されます:
| 権限 | クライアント | 操作 | 操作の詳細 |
|---|---|---|---|
| 許可/拒否 | クライアント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ファイルオーソライザーは必要に応じて無効化または削除してください。デフォルトで末尾に{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:default)zone: クライアントに関連付けられた設定ゾーン
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はセッションベースの認可データキャッシュ機構を提供しています。このキャッシュはクライアントのセッション状態に認可結果を保存し、同一接続内での認可ルール評価の繰り返しを減らします。クライアント認可キャッシュ機構はクライアントのパブリッシュ/サブスクライブ操作に対する権限チェックの効率を向上させ、多数のクライアントリクエストによる認可データバックエンドへのアクセス負荷を軽減します。
クライアント認可キャッシュの動作
クライアントが接続しパブリッシュ/サブスクライブ操作を行う際:
- EMQXは現在のセッションに保存された認可キャッシュを確認します。
- セッションキャッシュに一致するルールがあれば、それを直接使用します。
- キャッシュされたルールが存在しない(または期限切れの場合)、EMQXは設定されたオーソライザーを使って完全な認可チェックを実施します。
- 結果はセッションにキャッシュされ、同一接続内で再利用されます。
TIP
キャッシュはクライアントセッション固有であり、クライアントが切断または再接続するとクリアされます。
ダッシュボードでのクライアント認可キャッシュ設定
EMQXダッシュボードでクライアント認可キャッシュを有効化・設定できます:
アクセス制御 -> 認可 -> 設定 に移動します。
以下のオプションを設定します:
項目名 説明 キャッシュを有効にする 各クライアントセッションの認可キャッシュを有効/無効に切り替えます。 キャッシュ最大件数 クライアントごとのキャッシュ最大エントリー数。デフォルト: 32。キャッシュの有効期限 各キャッシュエントリーの有効期間。デフォルト: 1分。除外トピック キャッシュを無効にするトピックのリスト。 マッチしない場合の動作 オーソライザーが一致しなかった場合の動作。選択肢: allow(許可)/deny(拒否)。デフォルト:allow。拒否時の動作 操作拒否時の動作。選択肢: ignore(操作リクエストを無視)/disconnect(クライアント接続を切断)。デフォルト:ignore。キャッシュクリア アクティブなセッション認可キャッシュを手動で全てクリアするボタン。 保存をクリックして設定を適用します。
これらのオプションは設定ファイルからも設定可能です。詳細は設定ファイルを参照してください。
TIP
適切に設定すればキャッシュはパフォーマンスを大幅に向上させます。システムのパフォーマンスに応じて適宜調整することを推奨します。
外部リソースキャッシュ
セッションベースのキャッシュに加え、EMQXはMySQL、MongoDB、Redisなどの外部バックエンドから取得した認可結果をノードレベルでキャッシュする機能も備えています。この機能によりリモートデータソースへのアクセスを減らし、パフォーマンスを向上させます。
注意
外部リソースキャッシュは外部データソースにのみ適用されます。組み込みデータベースやファイルベースのオーソライザーには適用されません。
外部リソースキャッシュの動作
パブリッシュ/サブスクライブ操作が外部バックエンドへのクエリをトリガーした際:
- EMQXは外部リソースキャッシュ(同一ノード内の全クライアントで共有)を確認します。
- キャッシュに有効な結果があれば、キャッシュヒットとして外部バックエンドへの呼び出しは行われません。
- 結果がなければ、キャッシュミスとなり、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アドレスに置き換えられます。EMQXはProxy Protocolをサポートしているため、TCPプロキシやロードバランサーの背後に配置されていても実際のIPアドレスを取得可能です。${peername}: 実行時にクライアントのIPアドレスとポートに置き換えられ、形式はIP:PORTです。${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}プレースホルダーは認可テンプレート内で直接使用可能です。ゾーン設定の詳細はゾーンオーバーライドを参照してください。
トピック内のプレースホルダー
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は認可の設定方法として、ダッシュボード、設定ファイル、HTTP APIの3つを提供しています。
ダッシュボードでの認可設定
EMQXダッシュボードは直感的に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設定項目でも順序を調整可能です。
オーソライザーの状態確認
状態列で接続状態を確認できます:
| 状態 | 意味 | トラブルシューティング |
|---|---|---|
| 接続済み | 全ノードがデータソースに正常に接続済み | - |
| 未接続 | 一部または全ノードがデータソース(データベース、ファイル)に接続できていない | データソースの稼働状況を確認; 問題解決後にオーソライザーを手動で再起動(無効化→有効化) |
| 接続中 | 一部または全ノードがデータソースに再接続中 | データソースの稼働状況を確認; 問題解決後にオーソライザーを手動で再起動(無効化→有効化) |
実行中のメトリクス
オーソライザーの概要ページで統計メトリクスを確認できます。主なメトリクスは以下の通りです:
- 許可数:認可通過回数
- 拒否数:認可拒否回数
- マッチなし数:クライアントの認可データが見つからなかった回数
- 無視数:認可クエリが無視された回数(例:オーソライザーの
preconditionがtrueでない場合や、認可ソースが適用外またはエラーで判定不能な場合) - レート(tps):認可処理の実行レート
また、ノード状態から各ノードの認可状況や実行状況を確認できます。
認可全体の実行メトリクスを確認したい場合は、メトリクス - 認証&認可を参照してください。