Skip to content

認証

認証はクライアントの身元を検証するプロセスです。ほとんどのアプリケーションにおいて不可欠な要素であり、不正なクライアント接続からサービスを保護するのに役立ちます。

EMQXは複数の認証メカニズムをサポートしており、クライアントとサーバー間の認証要求に対応するために、TLS X.509証明書認証およびTLS-PSK認証もサポートしています。

本章では、身元認証の基本概念と設定について解説します。

TIP

デフォルトではEMQXは認証機能を有効にしておらず、すべてのクライアントの接続を許可します。実稼働環境で使用する場合は、少なくとも1つの認証方式を事前に設定してください。

認証メカニズム

EMQXがサポートする認証メカニズムは以下の通りです。

  • X.509証明書認証
  • JWT認証
  • ユーザー名/パスワード認証
  • MQTT 5.0の拡張認証
  • PSK認証

X.509証明書認証

EMQXはクライアント認証のためのX.509証明書認証をサポートしています。EMQXでX.509証明書認証を使用すると、クライアントとサーバーはTLS/SSLを通じて信頼できる接続を確立し、通信当事者の真正性と送信データの完全性を保証します。EMQXは片方向認証(クライアントがサーバーのみを認証)と双方向認証(クライアントとサーバーがお互いの証明書を検証)をサポートしており、様々なセキュリティ要件や展開シナリオに対応可能です。

JWT認証

JSON Web Token (JWT)は、サーバー側でクライアントの認証情報やセッション情報を保持しないトークンベースの認証方式です。

クライアントは接続要求時にJWTを携帯し、EMQXは事前に設定したシークレットまたは公開鍵を使ってJWTの署名を検証します。JWKSエンドポイントを設定している場合、JWT認証器はJWKSエンドポイントから取得した公開鍵リストを用いてJWT署名を検証します。

パスワード認証

EMQXは最もシンプルで一般的なパスワード認証をサポートしており、クライアントはユーザー名、クライアントID、対応するパスワードなどの認証情報を提供する必要があります。場合によっては、TLS証明書の一部フィールド(例:証明書のCommon Name)をクライアントの身元情報として利用することも可能です。いずれの場合も、これらの認証情報は事前にデータベースに保存されており、パスワードは通常ソルト付きのハッシュ形式で保存されます。

EMQXにおけるパスワード認証の流れは以下の通りです。クライアントは接続要求時に認証情報を携帯し、EMQXはクライアントが提供した認証情報に対応するハッシュ化されたパスワードをデータベースから照会し、一致した場合にのみ接続を許可します。

emqx-authn-flow

組み込みのデータベースに加え、EMQXはMySQL、PostgreSQL、MongoDB、Redisなどの各種バックエンドデータベースとの連携もサポートしています。

また、EMQXはユーザーが開発したHTTPサーバーなどの外部サービスに認証処理を委譲する設定も可能です。

MQTT 5.0拡張認証

MQTT 5.0拡張認証は、基本的な認証にチャレンジ/レスポンス方式の認証を追加したものです。拡張認証の実装により、Salted Challenge Response Authentication Mechanism(SCRAM)認証やKerberos認証など、より安全な認証方式を利用可能になります。EMQXの拡張認証は、組み込みデータベースや外部HTTPサービスを通じたSCRAMユーザー管理をサポートしています。

PSK認証

EMQXのPSK認証は、証明書ベースのTLSに代わるシンプルかつ安全な認証方式を提供します。クライアントとサーバーが共有する秘密鍵に基づき、デジタル証明書を必要としません。この方式は、証明書の管理にかかるオーバーヘッドが大きいリソース制約のある環境で特に有用です。

EMQX認証機

EMQXは使用する認証メカニズムおよびバックエンドデータベースに基づき、以下の認証方式(以下「認証器」と呼びます)をサポートしています。

メカニズムデータベース説明
パスワードベース組み込みデータベースMnesiaデータベースを認証情報ストレージとして用いる認証
パスワードベースMySQLMySQLデータベースを認証情報ストレージとして用いる認証
パスワードベースPostgreSQLPostgreSQLデータベースを認証情報ストレージとして用いる認証
パスワードベースMongoDBMongoDBデータベースを認証情報ストレージとして用いる認証
パスワードベースRedisRedisデータベースを認証情報ストレージとして用いる認証
パスワードベースLDAPLDAPサーバーを認証情報ストレージとして用いる認証
パスワードベースHTTPサーバー外部HTTP APIを用いた認証情報検証による認証
JWTJWTを用いた認証
SCRAM組み込みデータベースSCRAMを用いた認証
SCRAMHTTPサーバーRESP APIベースのSCRAMを用いた認証
GSSAPIKerberosKerberosを用いたGSSAPI認証
ルールベースClient-infoを用いた認証

認証チェーン

EMQXは認証チェーンの作成をサポートしており、複数の認証器を定義された順序で評価できます。チェーン内の各認証器は異なるタイプである必要があります(例:1つはHTTP、1つはLDAP、1つは組み込みデータベースなど)。

TIP

現時点でEMQXはMQTTクライアントに対してのみ認証チェーンの作成をサポートしています。ゲートウェイは認証チェーンをサポートしておらず、単一の認証器を使用してください。

X.509証明書ベースの認証を適用している場合は、認証チェーンの処理を行う前に必ず実行されます。

認証チェーンの動作

認証チェーンが設定されている場合、EMQXはまず最初の認証器から該当する認証情報の取得を試み、失敗した場合は次の認証器に切り替えて処理を継続します。

パスワードベース認証を例に動作を説明します。

  1. 前提条件の評価(設定されている場合)
    認証器に前提条件が設定されている場合、EMQXはクライアント属性情報(例:listenerclientidusername)に基づいて式を評価します。
    • 式がtrueの場合、認証器を呼び出します。
    • そうでなければ認証器をスキップします。
  2. 認証器の実行
    • 認証情報が見つかり有効(例:パスワードが正しい)であれば、クライアントは認証成功となり接続が許可されます。
    • 認証情報が見つかり無効であれば、クライアントはアクセス拒否されます。
    • 認証情報が見つからなければ、EMQXは次の認証器に処理を移します。
  3. エラーまたは無効時のスキップ
    認証器が無効化されている場合や、実行中に内部エラー(例:データベースが利用不可)が発生した場合もスキップされます。
  4. フォールバック動作
    すべての認証器がスキップされるか、いずれもクライアントを認証できなかった場合、EMQXはデフォルトで接続を拒否します。

認証機の前提条件

EMQX 5.9以降、各認証器に前提条件を割り当てることが可能になり、特定のクライアントに対して認証器を呼び出すかどうかを制御できます。前提条件はVariform式で、クライアント属性(listenerusernameclientidなど)を評価します。式がtrueでない場合、認証器はスキップされます。

この機能により認証チェーン内で条件分岐が可能となり、異なるリスナー経由のクライアントに対して異なる認証器を適用するなど、認証ロジックの細かな制御が可能です。EMQXは適切な場合にのみ認証器を呼び出し、外部システムへの不要なリクエストを回避します。

前提条件でサポートされるクライアント属性

前提条件で使用可能なクライアント属性は以下の通りです。

  • username: クライアントのユーザー名
  • password: クライアントのパスワード
  • clientid: クライアントID
  • client_attrs.*: クライアント属性
  • cert_common_name: クライアントTLS証明書のSubjectフィールド
  • cert_subject: クライアントTLS証明書のCommon Name(CN)
  • peersni: TLSクライアントが送信したSNI(Server Name Indication)
  • listener: リスナーID(例:tcp:default
  • zone: 関連付けられたコンフィグゾーン

前提条件の例

異なるリスナー経由のクライアントに異なる認証機を適用する例:

  • tcp:defaultのクライアントに対してHTTP認証機を適用:

    str_eq(listener, 'tcp:default')
  • ssl:defaultのクライアントに対してPostgreSQL認証機を適用:

    str_eq(listener, 'ssl:default')

外部リソースキャッシュ

EMQXはMySQL、MongoDB、Redisなどの外部バックエンドから取得した認証結果をノードレベルでキャッシュする仕組みを提供しています。このキャッシュは認証結果の検索性能を向上させ、特に高スループット環境において外部リソースへのアクセスを削減します。

注意

外部リソースキャッシュは外部データソースにのみ適用されます。組み込みデータベース認証器などのローカルソースには適用されません。

外部リソースキャッシュの動作

外部リソースキャッシュはノード単位で認証結果を保存し、同一ノード上のすべてのクライアントセッションで共有されます。これにより外部認証バックエンドへの重複クエリを回避します。

  1. クライアントが接続し認証がトリガーされる。
  2. EMQXはキャッシュに以前の結果があるか確認する。
    • 有効な結果があればキャッシュヒットとなり、外部バックエンドへの問い合わせは行われない。
    • 結果がなければキャッシュミスとなり、外部バックエンドに問い合わせる。
  3. バックエンドから返された結果はキャッシュに保存され、キャッシュ挿入のメトリクスが増加する。

この仕組みによりレイテンシ削減、バックエンド負荷軽減、システムの応答性維持が可能となります。

外部リソースキャッシュの有効化と設定

EMQXダッシュボードから外部リソースキャッシュを有効化および設定できます。

  1. アクセス制御 -> 認証に移動します。

  2. 右上の外部リソースキャッシュ設定ボタンをクリックすると、右側からサイドパネルが表示されます。

  3. パネル内の外部リソースキャッシュを有効にするボタンでキャッシュ機能をオン/オフできます。有効化後、以下のキャッシュ設定を行います。

    項目名説明
    最大キャッシュアイテム数ノードあたりの最大キャッシュエントリ数。デフォルト:1,000,000
    最大メモリ使用量キャッシュメモリ使用量の上限。デフォルト:100 MB
    キャッシュTTLキャッシュエントリの有効期間。デフォルト:1分
  4. 更新をクリックして設定を適用します。

これらの設定はクラスター全体に適用され、全ノードで一貫した動作を保証します。

外部リソースキャッシュの状態監視

キャッシュメトリクスを表示し、リアルタイムで使用状況を監視するには:

  1. External Resource Cache Settings の横にある矢印をクリックし、External Resource Cache Status を選択します。サイドパネルが表示され、キャッシュメトリクスが確認できます。
  2. ドロップダウンメニューを使って、ノード単位またはクラスター全体のメトリクスを表示できます。

メトリクスには以下が含まれます:

  • Memory Usage:キャッシュが現在使用している合計メモリ量。
  • Cache Entries:保存されているキャッシュ結果の総数。
  • Cache Hits:EMQXがキャッシュ内で有効な結果を見つけ、外部バックエンドへの呼び出しを回避した回数。
    • 表示されるメトリクス:現在のレート、5分間平均、最大レート
  • Cache Misses:EMQXがキャッシュ内で結果を見つけられず、バックエンドクエリが発生した回数。
    • 表示されるメトリクス:現在のレート、5分間平均、最大レート
  • Cache Inserts:ミス後にキャッシュに新しい結果が追加された回数。
    • 表示されるメトリクス:現在のレート、5分間平均、最大レート

パネル下部にはノードリストがあり、クラスター内の各ノードごとの Memory UsageCache EntriesCache Hits の概要を確認できます。

パネル右上のボタンで統計情報の更新やリセットが可能です。

スーパーユーザー

通常、認証はクライアントの身元情報の検証のみを行い、クライアントが特定のトピックに対してパブリッシュやサブスクライブの権限を持つかどうかは認可システムで判断します。しかしEMQXはスーパーユーザーの役割と権限プリセット機能を提供し、その後のパブリッシュ/サブスクライブの認可処理を容易にします。

TIP

権限プリセットはJWT認証およびHTTP認証でサポートされています。現在のクライアントが所有するパブリッシュ/サブスクライブ権限のアクセス制御リスト(ACL)はJWTペイロードやHTTPレスポンスボディに含まれ、認証通過後にクライアントにプリセットされます。

データベースクエリ、HTTPレスポンス、JWTクレームのis_superuserフィールドでユーザーがスーパーユーザーかどうかを確認できます。

パスワードハッシュ化

パスワードを平文で保存すると、データベースを覗いた誰もがユーザーのパスワードを読み取れてしまいます。したがって、パスワードはハッシュ化アルゴリズムを用いて生成されたハッシュ値として保存することが推奨されます。EMQXは様々なセキュリティ要件に対応するため複数のパスワードハッシュ化アルゴリズムをサポートしています。

また、EMQXはソルトをハッシュに付加することもサポートしており、ソルト付きのユニークなハッシュ(password_hash)は様々な攻撃から保護します。

ワークフロー

パスワードハッシュ化のワークフローは以下の通りです。

  1. EMQX認証器は設定されたクエリ文を用いて、データベースからハッシュ化パスワードおよびソルト値を含む適格な認証情報を照会する。
  2. クライアントが接続を試みる際、EMQX認証器はクライアントが提供したパスワードを設定されたハッシュアルゴリズムと照会したソルト値でハッシュ化する。
  3. EMQX認証器はステップ1で照会したハッシュパスワードとステップ2で計算したハッシュ値を比較し、一致すれば許可する。

以下はEMQXがサポートするハッシュアルゴリズムの例です。

# シンプルなアルゴリズム
password_hash_algorithm {
  name = sha256             # plain, md5, sha, sha512
  salt_position = suffix    # prefix, disable
}

# bcrypt
password_hash_algorithm {
  name = bcrypt
}

# pbkdf2
password_hash_algorithm {
  name = pbkdf2
  mac_fun = sha256          # md4, md5, ripemd160, sha, sha224, sha384, sha512
  iterations = 4096
  dk_length = 32           # 任意、単位:バイト
}

ハッシュアルゴリズムによってパフォーマンスに大きな差があるため、用途に応じて選択してください。参考までに、4コア8GBマシンで各アルゴリズムを100回実行した際の平均実行時間は以下の通りです。

認証プレースホルダー

EMQXはクエリ文やHTTPリクエスト内でプレースホルダーを使用可能です。認証時にこれらのプレースホルダーは実際のクライアント情報に置換され、現在のクライアントに合致したクエリやHTTPリクエストを構築します。

有効なプレースホルダーは${PATH.TO.VALUE}の形式で、PATH.TO.VALUEはオブジェクト内の値へのドット区切りパスです。有効文字は英数字、ドット(.)、アンダースコア(_)です。サポートされない文字を含むプレースホルダーは単なるテキストとして扱われます。

例えば、EMQXのMySQL認証器ではデフォルトクエリSQLに${username}プレースホルダーを使用しています。

SELECT password_hash, salt FROM mqtt_user where username = ${username} LIMIT 1

クライアント(名前:emqx_u)が接続要求を行うと、構築されるクエリ文は以下のようになります。

SELECT password_hash, salt FROM mqtt_user where username = 'emqx_u' LIMIT 1

EMQXが現在サポートするプレースホルダーは以下の通りです。

  • ${clientid}: 実行時にクライアントIDに置換されます。クライアントIDは通常CONNECTパケットで明示的に指定されます。use_username_as_clientidpeer_cert_as_clientidが有効な場合は、ユーザー名や証明書のフィールド、証明書の内容で上書きされます。

  • ${username}: 実行時にユーザー名に置換されます。ユーザー名はCONNECTパケットのUsernameフィールドから取得されます。peer_cert_as_usernameが有効な場合は証明書のフィールドや内容で上書きされます。

  • ${password}: 実行時にパスワードに置換されます。パスワードはCONNECTパケットのPasswordフィールドから取得されます。

  • ${peerhost}: 実行時にクライアントのIPアドレスに置換されます。EMQXはProxy Protocolをサポートしており、TCPプロキシやロードバランサーの背後に配置されていても実際のIPアドレスを取得可能です。

  • ${peername}: 実行時にクライアントのIPアドレスとポート(IP:PORT形式)に置換されます。

  • ${cert_subject}: 実行時にクライアントTLS証明書のSubjectに置換されます。ロードバランサーがクライアント証明書情報をTCPリスナーに送信する場合はProxy Protocol v2の使用を確認してください。

  • ${cert_common_name}: 実行時にクライアントTLS証明書のCommon Nameに置換されます。ロードバランサーがクライアント証明書情報をTCPリスナーに送信する場合はProxy Protocol v2の使用を確認してください。

  • ${client_attrs.NAME}: クライアント属性。NAMEは事前定義された設定に基づき実行時に属性名に置換されます。クライアント属性の詳細はMQTTクライアント属性を参照してください。

  • ${zone}: 実行時にクライアントのゾーンに置換されます。${zone}プレースホルダーは認証テンプレート内で直接使用可能です。ゾーン設定の詳細はゾーンオーバーライドを参照してください。

    例として、以下のACLルールは${zone}を用いてクライアントの割り当てられたゾーンに基づき動的に権限を適用しています。

    {allow, all, all, ["${zone}/${username}/#"]}

認証の設定

EMQXは認証の設定をダッシュボード、設定ファイル、HTTP APIの3通りで提供しています。

ダッシュボードによる認証設定

EMQXダッシュボードは認証器の状態確認や設定カスタマイズを直感的に行える方法です。以下のスクリーンショットのように、組み込みデータベースベースのパスワード認証とJWT認証の2つの認証器を設定しています。

設定ファイルによる認証設定

設定ファイルでもEMQX認証機を設定可能です。

例えば、以下のauthenticationフィールドでは複数の認証器からなる認証チェーンを作成しており、設定ファイル内の順序で認証器が実行されます。

# base.hocon

# すべてのMQTTリスナーに対するグローバル認証チェーン
authentication = [
  ...
]

listeners.tcp.default {
  ...
  # 指定されたMQTTリスナーに対する認証チェーン
  authentication = [
    ...
  ]
}

gateway.stomp {
  ...
  # すべてのSTOMPリスナーに対するグローバル認証機
  authentication = {
    ...
  }

}

認証機の種類により設定項目は異なります。詳細は設定章を参照してください。

HTTP APIによる認証設定

設定ファイルに比べ、HTTP APIはより便利でランタイム更新をサポートし、設定変更をクラスター全体に自動同期できます。

EMQX認証APIを使って認証チェーンや認証器を管理可能です。例えばグローバル認証器の作成や特定認証器の設定更新などが行えます。

  • /api/v5/authentication:グローバルMQTT認証管理用APIエンドポイント
  • /api/v5/gateway/{protocol}/authentication:他のアクセスプロトコル向けグローバル認証管理APIエンドポイント
  • /api/v5/gateway/{protocol}/listeners/{listener_id}/authentication:他のアクセスプロトコルのリスナー認証管理APIエンドポイント

認証機ID

特定の認証器を操作するには、上記エンドポイントに認証器IDを付加します。例:/api/v5/authentication/{id}。メンテナンスを容易にするため、IDはEMQXが自動生成してAPIで返すのではなく、以下の仕様に従います。

<mechanism>:<backend>

または

<mechanism>

例:

  1. password_based:built_in_database
  2. jwt
  3. scram:built_in_database

リスナーIDにも同様の規則があります。

bash
<transport_protocol>:<name>

ゲートウェイリスナーIDはプロトコル名を先頭に付加します。

bash
<protocol>:<transport_protocol>:<name>

認証器IDおよびリスナーIDはURLで使用する際、URLエンコード規則に従う必要があります。例えば、:%3Aに置換します。

bash
PUT /api/v5/authentication/password_based%3Abuilt_in_database

データ操作API

組み込みデータベースおよびMQTT 5.0拡張認証を用いた認証では、認証データの作成、更新、削除、一覧取得などを行うHTTP APIを提供しています。詳細はHTTP APIでの認証データ管理を参照してください。

APIリクエストやパラメータの詳細はHTTP APIを参照してください。