セキュリティプロファイル
バージョン6.3以降、EMQXはノード全体のセキュリティプロファイルをサポートしています。このプロファイルはセキュリティ関連のデフォルト動作のセットを選択します。EMQXは以下の2つのプロファイルを提供しています:
legacy(デフォルト):以前のEMQXバージョンのデフォルト動作を維持します。hardened:厳格でデフォルトで安全な動作を適用します。
EMQX 7.0ではhardenedがデフォルトで使用される予定です。初期デプロイメントにはhardenedを使用してください。legacyからの移行前に、以下の動作変更を確認してください。
プロファイルの選択
プロファイルはEMQX_SECURITY_PROFILE環境変数で選択します。emqxコマンドが起動時に読み込むemqx.envファイルに設定してください:
- rpmおよびdebインストール:
/etc/emqx/emqx.env - Dockerイメージ:
/opt/emqx/etc/emqx.env - tar.gzインストール:
etc/emqx.env
ファイル内のEMQX_SECURITY_PROFILEの行のコメントを外し、値を設定します:
EMQX_SECURITY_PROFILE=hardenedその後、ノードを再起動してください。
emqx.env内の値は環境変数から継承した値を上書きし、パッケージのアップグレードでも編集内容は保持されます。環境変数として直接設定することも可能です。例えば、docker run -e EMQX_SECURITY_PROFILE=hardenedや、フォアグラウンド起動前にexport EMQX_SECURITY_PROFILE=hardenedを実行します。
EMQXは起動時に一度だけこの変数を読み込み、設定ファイルの解析前に適用するため、設定ファイル内でプロファイルを設定することはできません。有効な値はlegacy、hardened、または空(デフォルト選択)です。それ以外の値はノードの起動を停止させます。クラスター内のすべてのノードで同じ値を設定してください。
TIP
セキュリティプロファイルはデフォルト動作のみを変更します。以下に記載するほとんどの動作は、選択したプロファイルに関わらず個別に設定可能です。
現在のプロファイルの確認
ダッシュボードで、Monitoring -> Cluster Overview -> Nodesをクリックし、Security Profile列を確認してください。この列には各ノードがlegacyまたはhardenedプロファイルで起動したかが表示されます。値は起動時に固定され、ノードの再起動後にのみ変更可能です。
すべての稼働中ノードの値を比較し、クラスターで一貫したプロファイルが使用されていることを確認してください。停止中のノードや6.3より前のバージョンを実行しているノードはセキュリティプロファイルを報告しません。
hardenedプロファイルでの動作変更
hardenedプロファイルはlegacyと比較して以下の動作を変更します。
ノードおよびクラスターのセキュリティ
- 既知の安全でないErlangクッキーは拒否されます。 ノードは組み込みのデフォルトErlangクッキーや一般的に使われるサンプル値
emqxsecretcookieを使用している場合、起動しません。非デフォルトのnode.cookieを設定するか、EMQX起動前にEMQX_NODE__COOKIEを設定してください。クラスター内のすべてのノードで同じクッキーを使用してください。
リスナーの公開範囲
hardenedプロファイルは、明示的なバインドアドレスが指定されていないリスナーに対し、node.default_listener_address(バインドアドレス未指定のリスナーに対するノードレベル設定)で以下のデフォルトバインドアドレスを使用します:
- MQTTリスナーはデフォルトでループバックにバインドされます。 MQTTのTCP、SSL、WebSocket、セキュアWebSocket、QUICリスナーは、
bindが省略されているかポートのみ指定の場合、ループバックインターフェースのみにバインドします。外部接続を受け入れるには、例えばbind = "0.0.0.0:1883"のように明示的なバインドアドレスを設定してください。 - ダッシュボードのHTTPリスナーもデフォルトでループバックにバインドされます。 ダッシュボードのHTTPリスナーは
bindが省略またはポートのみ指定の場合、ループバックインターフェースのみにバインドします。外部接続を受け入れるには明示的なバインドアドレスを設定してください。
この設定はゲートウェイリスナーにも適用されますが、ゲートウェイリスナーのデフォルトバインドアドレスはセキュリティプロファイルによって変更されません。サポートされる値や設定の詳細はDefault Listener Addressを参照してください。
認証
- 明示的な認証が必須です。 認証機構が設定されていない、またはすべて無効化されている場合、クライアントは拒否されます。匿名アクセスを明示的に許可するには、リスナーの
enable_authn = falseを設定してください。 - 認証バックエンドの障害はアクセス拒否となります。 認証バックエンドのエラー、不正なレスポンス、認証前提条件の評価エラー、JWT検証キーの利用不可は、次の認証機構に進まずクライアントを拒否します。フォールバックを許可するには
authentication_settings.ignore_backend_failures = trueを設定してください。 - JWT認証機構はJWTの欠如を無視しません。 JWT認証機構は設定されたJWTフィールドがないクライアントを拒否します。これを無視して次の認証機構に進ませるには、認証機構の
on_missing_jwt = ignoreを設定してください。 - 非JWT認証情報は混在認証チェーンでJWT認証機構をスキップする必要があります。 JWT認証機構は不正なJWTを受け取ると認証失敗となります。JWT認証機構と後続のパスワード認証機構が同じフィールド(例:
password)を参照する場合、JWT認証機構のprecondition = "is_jwt(password)"を設定し、通常のパスワードは次の認証機構に進むようにしてください。 - JWKSのTLS検証が有効です。 JWT認証機構はJWKSのHTTPSエンドポイントから鍵を取得する際にピア証明書とホスト名を検証します。信頼されていない証明書のエンドポイントは利用不可となります。特定のJWKSエンドポイントで検証を無効にするには
ssl.verify = verify_noneを設定してください。
認可
- 認可バックエンドの障害は操作拒否となります。 認可バックエンドのエラー、不正なルール、テンプレート評価エラーは、後続の認可ソースに進まず、パブリッシュやサブスクライブ操作を拒否します。バックエンド障害を無視して次の認可ソースに進むには
authorization.ignore_backend_failures = trueを設定してください。 - 認可のトピックテンプレート置換に禁止文字が含まれると操作拒否となります。 デフォルトでは、置換値に
/、+、#が含まれるとlegacyではマッチなし、hardenedでは操作拒否となります。例えばクライアントIDがi/am/+/good/#の場合、ルール{allow, all, all, ["t/${clientid}/#"]}.にマッチします。個別の文字を許可するにはauthorization.topic_template_allow.slash、authorization.topic_template_allow.plus、authorization.topic_template_allow.hashを設定してください。 - デフォルトのファイル認可ソースはdeny-by-defaultです。 デフォルトの
acl.confは最後に{allow, {security_profile, legacy}}.というルールがあり、legacyプロファイルでは許可されますがhardenedでは適用されません。hardenedではマッチしない操作はauthorization.no_match(デフォルトはdeny)にフォールスルーします。許可的動作にするには最後のルールを{allow, all}.に変更してください。{security_profile, legacy}および{security_profile, hardened}条件は任意のacl.confルール内で使用可能で、andやor式内でも利用でき、選択したプロファイルに応じたカスタムルールを適用できます。 - 内部サブスクリプションは認可されます。 Auto Subscribeなどの機能によるサブスクリプションはトピック検証、認可、機能チェック、サブスクライブフックを通過します。特権管理による強制サブスクライブ操作はMQTT認可をバイパスし続けます。
遅延パブリッシュ
- 遅延メッセージは再生時に再認可されます。 EMQXはメッセージがスケジュールされた時点の認可コンテキストを使い、現在のパブリッシュ認可ルールと禁止レコードをチェックします。スケジュール時に認可されたメッセージでも再生時に破棄される可能性があります。
重要なお知らせ
hardenedプロファイルでは、アップグレード前に作成された保留中の遅延メッセージは認可コンテキストを含まないため破棄されます。legacyプロファイルはこれらのメッセージを再生し続けます。
拡張機能
- アクセス制御フックの失敗はリクエスト拒否となります。 認証または認可フックからの例外は処理を中断し、リクエストを拒否します。これはプラグインやExHook拡張によるカスタム認証・認可で特に重要です。
- ExHookの
message.publish失敗はパブリッシュ拒否となります。 ExHookサーバーが利用不可、またはfailed_actionがdenyのサーバーがmessage.publish処理中に失敗した場合、EMQXはメッセージのパブリッシュを防止します。legacyでは同様の失敗でもパブリッシュはブロックされません。 - プラグインのインストールにはパッケージダイジェストが必要です。
emqx ctl plugins allow <Name-Vsn>はsha256:<hex>引数を必須とします。この許可はプラグインパッケージをそのダイジェストに紐付け、EMQXはアップロードされたバイト列が一致する場合のみインストールします。ダイジェストなしの許可は拒否され、クラスターのピアから送信されたものも含みます。legacyでは引数は任意です。
ダッシュボード
- デフォルトのダッシュボード認証情報は受け付けられません。 デフォルトパスワード
publicのローカルダッシュボードアカウントはログインできません。アップグレード前に作成された管理者アカウントも含みます。hardenedプロファイルに切り替える前にパスワードを変更してください。
デフォルトリスナーアドレス
node.default_listener_address設定は、明示的なアドレス指定がないリスナーのバインドアドレス(ポートのみ指定のbind = 1883など)を設定します。MQTTリスナー、ゲートウェイリスナー、ダッシュボードHTTPリスナーに適用されます。明示的なIP:portバインドがある場合はそちらが優先されます。
EMQXは各ノードでローカルにデフォルトアドレスを決定し、リスナー起動時に適用します。設定されたbind値は変更されず、ポートのみのバインドが永続的にIP:portに変わることはありません。同じリスナー設定のノードでも異なるアドレスでリスニング可能です。
このオプションを使い、セキュリティプロファイルに関係なくリスナーの公開範囲を制御できます。例えば、hardenedプロファイルを維持しつつ、デフォルトリスナーをすべてのネットワークインターフェースにバインドするには、ノードのemqx.confに以下を追加します:
node.default_listener_address = "all"有効な値:
| 値 | バインドアドレス |
|---|---|
loopback | 127.0.0.1。ダッシュボードはinet6オプションが設定されている場合、代わりに::1にバインドします。 |
nodename | Erlangノード名の@以降のホスト部分。IPアドレスの場合はそのままバインドし、そうでなければ起動時に解決し、最初のIPv4アドレス、IPv4がなければ最初のIPv6アドレスにバインドします。 |
all | すべてのネットワークインターフェース。デフォルトのIPv4設定では0.0.0.0になります。アドレスファミリーはリスナー設定に依存します。 |
| IPアドレス | 例えば192.168.1.10や::1などのリテラルアドレス。多くのシステムでは::がIPv4とIPv6の両方を受け入れ、OSのbindv6only設定が決定します。 |
| ホスト名 | 起動時に解決されます。例えばbroker1.example.comなど。 |
設定されていない場合、セキュリティプロファイルがMQTTリスナーとダッシュボードHTTPリスナーのデフォルトアドレスを決定します:legacyはすべてのインターフェースにバインドし、hardenedはループバックにバインドします。ゲートウェイリスナーはどちらのプロファイルでもすべてのインターフェースにバインドします。
このオプションはノードローカルであり、EMQXは起動時に一度だけ読み込みます。変更にはノード再起動が必要です。環境変数EMQX_NODE__DEFAULT_LISTENER_ADDRESSでも設定可能です。
TIP
公式Dockerイメージのエントリポイントは、環境変数が未設定または空の場合にEMQX_NODE__DEFAULT_LISTENER_ADDRESS=allを設定します。コンテナのループバックインターフェースは公開ポート経由で到達できないためです。このデフォルトにより、ポートのみ指定のバインドはどちらのプロファイルでもすべてのネットワークインターフェースにバインドされ、公開されたコンテナポートからのアクセスが可能になります。上書きするには、環境変数を明示的に別の有効な値に設定してください。明示的なIPアドレスを指定したリスナーバインドは変更されません。
セキュリティプロファイル間のバックアップ復元
データバックアップはエクスポート元ノードのセキュリティプロファイルを記録します。デフォルトでは、legacyプロファイルのバックアップおよびこのメタデータがないバックアップは、hardenedノードにインポートすると拒否されます。legacyノードへのインポートは影響を受けません。
この保護を上書きする前にプロファイル間の違いを確認してください。互換性ルールと上書き方法についてはBackup and Restoreを参照してください。
ローリングアップグレード
クラスター内のすべてのノードは同じセキュリティプロファイルを使用する必要があります。ノード間でプロファイルが異なる場合、アクセス制御の判断はクライアントが接続するノードによって異なります。6.3以前のバージョンを実行するノードは常にlegacyとして動作します。
6.3以前のバージョンからローリングアップグレードを行う場合:
- アップグレードしたノードに
EMQX_SECURITY_PROFILE=hardenedを設定しないでください。変数を未設定のままにするか、legacyに設定し、アップグレード済みノードが旧バージョンのノードと同様に動作するようにします。 - すべてのノードでローリングアップグレードを完了させます。
- その後、以下の移行手順に従ってクラスターを
hardenedに切り替えます。
移行
既存のデプロイメントをlegacyからhardenedに移行するには:
- 上記の動作変更を確認し、厳格なデフォルトが適合しない場合は明示的な設定を適用します。
- 非デフォルトのErlangクッキーを設定し、クラスター内のすべてのノードが同じ値を使用していることを確認します。
- 外部接続を受け入れる必要がある場合、リスナーとダッシュボードに明示的なバインドアドレスが設定されているか、すべてのデフォルトリスナーに対して
node.default_listener_addressを設定していることを確認します。 - すべてのノードに認証が設定されているか、匿名アクセスが明示的に許可されていることを確認します。
- デフォルトパスワードを使用しているダッシュボードアカウントを変更します。
- アップグレード後に
hardenedを有効にする前に、アップグレード前に作成された保留中の遅延メッセージが再生されるのを待つか、EMQXがそれらを破棄することを受け入れてください。 - すべてのノードで
EMQX_SECURITY_PROFILE=hardenedを設定し、1台ずつ再起動します。
以前の動作を維持するには、EMQX_SECURITY_PROFILE=legacyを設定するか、変数を未設定のままにしてください。