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拡張認証は基本認証を拡張し、チャレンジ/レスポンス方式の認証を含みます。これにより、SCRAM認証(Salted Challenge Response Authentication Mechanism)やKerberos認証など、より安全な認証機構の利用が可能になります。EMQXの拡張認証実装は、組み込みデータベースや外部HTTPサービスを介したSCRAMユーザー管理をサポートしています。

PSK認証 ​

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

EMQX認証機(Authenticator) ​

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はクライアント属性情報(例:listener、clientid、username)に基づいて式を評価します。

    • 式がtrueの場合、認証機を呼び出します。
    • そうでなければ、認証機をスキップします。
  2. 認証機の実行

    • 認証情報が見つかり有効(例:パスワードが正しい)なら、クライアントは認証に成功し接続が許可されます。
    • 認証情報が見つかったが無効なら、クライアントはアクセス拒否されます。
    • 認証情報が見つからなければ、EMQXは次の認証機に移ります。
  3. エラーや無効時のスキップ
    認証機が無効化されているか、実行中に内部エラー(例:データベースが利用不可)が発生した場合もスキップされます。

  4. フォールバック動作
    すべての認証機がスキップされるか、いずれも認証に成功しなかった場合、EMQXはデフォルトで接続を拒否します。

認証機の前提条件 ​

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

この機能により、認証チェーン内で条件付きロジックを実現できます。例えば、異なるリスナー経由のクライアントに異なる認証機を適用したり、クライアント属性に基づいて認証機を選択したりできます。これにより、適切な場合にのみ認証機を呼び出し、外部システムへの不要なリクエストを回避できます。

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

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

  • 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')

JWT認証機とパスワード認証機を同一認証チェーンに組み合わせる場合、JWT認証機に以下の前提条件を設定します。

is_jwt(password)

EMQX 6.2.3以降、この前提条件はパスワードが構造的にJWTである場合のみtrueを返します。JWT認証機はJWTパスワードに対して呼び出され、JWTでないかパスワードがない場合はスキップされ、次の認証機に処理が移ります。

外部リソースキャッシュ ​

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 Usage、Cache Entries、および Cache Hits の概要を確認できます。

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

スーパーユーザー ​

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

TIP

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

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

認証結果からのクライアントID上書き ​

MQTTクライアントに対し、認証バックエンドは認証成功時の結果にclientid_overrideを返すことができます。この値は空でない文字列で、完全な置換用クライアントIDを含みます。EMQXは認証後、クライアントセッション開始前にこの値を適用します。フィールドがないか空の場合は、従来のクライアントIDを保持します。

この仕組みは、認証バックエンドから返されるテナント識別子など、認証後にのみ利用可能な信頼情報に基づいてクライアントIDを置換したい場合に有効です。マルチテナント環境では、EMQXがテナントIDを有効なクライアントIDに含めることで、異なるテナントのクライアントが同一の元クライアントIDを使ってもセッション競合を回避できます。認証前に接続情報から置換用クライアントIDを構築できる場合は、mqtt.clientid_overrideを使用してください。仕組みの選択、実行順序、失敗時の挙動についてはクライアントID分離を参照してください。

MQTT接続にはクライアントID上書きの仕組みを1つだけ使用してください。両方設定されている場合は認証結果の上書きが後に実行され、mqtt.clientid_overrideで生成されたクライアントIDを置換します。

WARNING

EMQX 6.3.1以降、ゲートウェイプロトコルは認証結果によるクライアントID上書きをサポートしていません。ゲートウェイ経由のクライアントに対してはclientid_overrideを無視し、ゲートウェイプロトコルで決定されたクライアントIDを保持します。また、gateway_authn_clientid_override_not_supportedの警告ログを出力します。

認証バックエンドの設定 ​

clientid_overrideは認証結果のフィールドであり、すべての認証機で共通のダッシュボード設定ではありません。各認証バックエンドで以下のように設定します。

認証バックエンドclientid_overrideの提供方法
HTTP成功したJSONレスポンスのトップレベル文字列フィールドとして返す。
JWTJWTペイロードのトップレベル文字列クレームとして追加。
LDAPLDAP属性に保存し、Client ID Override Attributeに属性名を設定。デフォルトはclientIdOverride。
MongoDBドキュメントフィールドに保存し、Client ID Override Fieldにフィールド名を設定。デフォルトはclientid_override。
MySQLクエリ結果のclientid_override列で返す。
PostgreSQLクエリ結果のclientid_override列で返す。
Redisclientid_overrideフィールドに保存し、クエリコマンドに含める。

置換用クライアントIDをクライアントID分離に利用する場合は、グローバルに一意であることを保証してください。

パスワードハッシュ化 ​

パスワードを平文で保存すると、データベースを覗いた誰でもパスワードを読み取れてしまいます。そのため、パスワードハッシュアルゴリズムを用いて生成されたハッシュ値を保存することが推奨されます。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リクエスト内でプレースホルダーを利用できます。認証時にこれらは実際のクライアント情報に置換され、現在のクライアントに合致したクエリやリクエストが構築されます。

有効なプレースホルダーは${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_clientidやpeer_cert_as_clientidが有効な場合はユーザー名や証明書のフィールド、証明書内容で上書きされます。

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

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

  • ${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が有効な場合はプロキシから報告された情報を使用します。

  • ${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}/#"]}

TIP

${peerhost}および${peerport}プレースホルダーは非推奨です。後方互換性のため引き続きサポートされていますが、新規テンプレートでは対応する箇所で${peername}を使用してください。

認証の設定 ​

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})。メンテナンスを容易にするため、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を参照してください。