# SSL/TLS接続の有効化

EMQXは、MQTTクライアントのアクセスを受け入れる際に、SSL/TLSを介して安全な接続を確立できます。SSL/TLS暗号化機能は、トランスポート層でネットワーク接続を暗号化し、通信データのセキュリティを強化するとともに、その整合性を保証します。

本ページでは、SSL/TLS接続の機能と利点、およびクライアントとEMQX間でのSSL/TLS接続の確立方法について紹介します。

## セキュリティ上の利点

SSL/TLS接続を有効にすることで、以下のセキュリティ上の利点が得られます。

1. **強力な認証**：通信の両当事者は、相手が保持するX.509デジタル証明書を検証して相手の身元を確認します。これらの証明書は通常、信頼された認証局（CA）によって発行されており、偽造できません。
2. **機密性**：各セッションは、両当事者が交渉したセッションキーで暗号化されます。第三者が通信内容を知ることはできず、たとえセッションキーが漏洩しても他のセッションのセキュリティには影響しません。
3. **整合性**：暗号化通信においてデータが改ざんされる可能性は極めて低いです。

## 2つの利用モード

MQTT接続を含むすべての接続に対してSSL/TLS暗号化接続を有効にし、アクセスおよびメッセージ送信のセキュリティを確保できます。クライアントのSSL/TLS接続については、利用シナリオに応じて以下の2つのモードから選択可能です。

| 利用モード                                                     | 利点                                                         | 欠点                                                         |
| -------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| クライアントとEMQX間で直接SSL/TLS接続を確立する。             | 利用が簡単で追加コンポーネントが不要。                         | EMQXのリソース消費が増加し、接続数が多い場合はCPUやメモリの高負荷を招く可能性がある。 |
| プロキシやロードバランサーでTLS接続を終了させる。             | EMQXのパフォーマンスに影響がなく、ロードバランシング機能を提供。 | TCP SSL/TLS終了をサポートするクラウドベンダーのロードバランサーは限られている。また、HAProxyなどのソフトウェアをユーザー自身でデプロイする必要がある。 |

プロキシやロードバランサーでTLS接続を終了させる方法については、[クラスターのロードバランシング](../cluster/lb.md)を参照してください。

## 一方向／双方向認証

EMQXは包括的なSSL/TLS機能を提供し、X.509証明書による一方向および双方向のクライアント／サーバー相互認証を実現しています。

| 認証方式           | 説明                                                         | 検証方法                                                     | 長所と短所                                                  |
| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 一方向認証         | クライアントはサーバーの身元を検証するが、サーバーはクライアントの身元を検証しない。 | クライアントは通常証明書を提供する必要がなく、サーバー証明書が信頼された認証局（CA）によって発行されていることのみを検証する。 | 通信データの機密性と整合性は保証できるが、通信当事者の身元は保証できない。 |
| 双方向認証         | サーバーとクライアントが相互に身元を検証する。               | 各デバイスに証明書を発行し、サーバーはクライアント証明書の正当性を検証する。 | サーバーとクライアント間の相互信頼を確保し、中間者攻撃を防止できる。 |

## SSL/TLS証明書

SSL/TLSを有効にする前に、接続の認証とセキュリティ確保のためにSSL/TLS証明書を準備する必要があります。

EMQXは、従来のパスベース証明書と、リスナーやコネクター間での集中管理および再利用を可能にする管理証明書（EMQX 6.1以降）をサポートしています。

EMQXでのSSL/TLS証明書の取得、管理、使用に関する完全なガイドは、[SSL/TLS証明書](./tls-certificate.md)を参照してください。

## 一方向認証でのSSL/TLS有効化

デフォルトで、EMQXはポート`8883`にSSL/TLSリスナーを有効化し、一方向認証（クライアントはサーバー証明書を検証するが、サーバーはクライアント証明書を検証しない）に設定されています。

SSL/TLSリスナーは、ダッシュボードまたは設定ファイルのいずれかで構成可能です。どちらの場合も、EMQXは2つの証明書提供方法をサポートしています。

- パスベース証明書（従来のPEMファイル）：設定でファイルパスを直接参照する方法。
- 管理証明書（EMQX 6.1以降）：再利用可能なリソースとして管理され、名前で参照する方法。

運用モデルやデプロイ形態に最適な方法を選択してください。

### ダッシュボードでの有効化

1. **管理** -> **リスナー** に移動します。

2. **default**という名前のSSLリスナーをクリックし、**リスナー編集**ページを開きます。

3. 以下のSSL/TLS設定を行います。

   - **Verify Peer**：一方向認証ではデフォルトで無効です。無効の場合、EMQXはクライアント証明書を検証しません。
   
   - **Force Verify Peer Certificate**：**Verify Peer**が有効な場合にのみ適用されます。一方向認証では無効のままにしてください。
   
   - **Session Tickets**：TLS 1.3のセッション再開を有効にします。クライアントは、サーバーが発行した暗号化されたセッションチケットを提示することで、再接続時に完全なTLSハンドシェイクを省略し、レイテンシとCPU使用率を低減できます。
   
     - **`disabled`**：セッションチケットを無効化（デフォルト）。接続ごとに完全なTLSハンドシェイクを実施。
     - **`stateless`**：ステートレスセッションチケットを有効化。サーバーはセッション状態を保持せず、再接続性能が向上します。セッション再開後はTLSクライアント証明書情報が利用できないため、証明書ベースの認証や認可が不要な場合に適しています。
     - **`stateless_with_cert`**：証明書情報を含むステートレスセッションチケットを有効化。セッション再開後も証明書情報が利用可能で、mTLSなど証明書ベース認証に適していますが、ネットワーク帯域の使用量がやや増加します。
   
     ::: tip 注意事項
   
     セッションチケットを生成するには、ノードレベルのオプション`node.tls_stateless_tickets_seed`に空でない文字列（例：`node.tls_stateless_tickets_seed = "averysecuresecret"`）を設定する必要があります。リスナーでセッションチケットを有効にしても、このオプションが設定されていなければチケットは生成されません。
   
     セッションチケットはTLS 1.3でのみサポートされ、クラスター環境でのスケーラビリティ確保のためステートレスモードのみ対応しています。TLS 1.2のステートフルセッション再開はEMQXでサポートされていません。
   
     また、EMQXはクライアントの早期データ送信（0-RTT）もサポートしていません。クライアントはTLSハンドシェイク完了後にMQTTデータを送信する必要があります。
   
     :::
   - **Certificate Source**：サーバー証明書の提供方法を選択します。
   
     - **手動入力**：従来のパスベース証明書を使用。以下の項目を設定します。
   
       - **TLS Cert**：サーバー証明書ファイルのパス。
       - **TLS Key**：秘密鍵ファイルのパス。
   
     - **管理証明書から選択**：管理証明書バンドルを使用（EMQX 6.1以降）。以下の項目を設定します。
   
       - **Namespace**：管理証明書バンドルが格納されているネームスペース（デフォルトは`global`）。
       - **Managed Cert Bundle Name**：既存の管理証明書バンドルを選択。新規作成は**管理証明書を作成**をクリック。詳細は[ダッシュボードでの証明書バンドル作成](./tls-certificate.md#create-certificate-bundles-via-dashboard)を参照。
       - **SNI**（任意）：同一リスナーに複数証明書が設定されている場合に証明書を識別するためのServer Name Indication値。
   
       複数の管理証明書エントリは**+**ボタンで追加可能です。
   
       複数証明書が設定されている場合、EMQXはクライアントのSNIに基づいて証明書を動的に選択します。SNIが一致しない場合はリストの最初の証明書がデフォルトとして使用されます。
   
   - **SSL Versions**：TLS/DTLSのすべてのバージョンをサポート。デフォルトは`tlsv1.3`と`tlsv1.2`です。PSK認証でPSK暗号スイートを使用する場合は、`tlsv1.2`、`tlsv1.1`、`tlsv1`も設定してください。PSK認証の詳細は[PSK認証の有効化](./psk-authentication.md)を参照。
   
   - **Cipher Suites**：必要に応じて許可する暗号スイートを指定可能（任意）。
   
   - **CACert Depth**：証明書チェーンの最大深度。デフォルトは`10`。
   
   - **Key File Passphrase**：秘密鍵ファイルが暗号化されている場合のパスワード。パスワードをファイルから読み込む場合は`file://<path-to-file>`形式を使用。ファイルの内容（末尾の空白は除去）がパスワードとして使用されます。クラスター環境ではすべてのEMQXノードにファイルが存在する必要があります。詳細は[ファイルからのシークレット読み込み](../configuration/secret-from-file.md)を参照。
   
   - **OCSP Staplingの有効化**：デフォルトは無効。証明書失効状況をOCSPで確認する場合に有効化。詳細は[OCSP Stapling](./ocsp.md)を参照。
   
   - **CRLチェックの有効化**：デフォルトは無効。証明書失効リスト（CRL）による検証を行う場合に有効化。詳細は[CRLチェック](./crl.md)を参照。
   
4. 設定完了後、**更新**をクリックして反映します。

### 設定ファイルでの有効化

設定ファイルの`listeners.ssl.default`設定グループを編集してSSL/TLS接続を有効にすることも可能です。

1. SSL/TLS証明書ファイルをEMQXの`etc/certs`ディレクトリに配置します。

2. 設定ファイル`base.hocon`（インストール方法により`./etc`または`/etc/emqx/etc`にあります）を開きます。

3. `listeners.ssl.default`設定グループを編集します。

   - ファイルベースの証明書を使用する場合は、証明書ファイルを自分のものに置き換え、一方向認証を有効にするには`verify = verify_none`を追加します。

     ```hocon
     listeners.ssl.default {
       bind = "0.0.0.0:8883"
       
       ssl_options {
         cacertfile = "etc/certs/rootCAs.pem"
         certfile = "etc/certs/server-cert.pem"
         keyfile = "etc/certs/server-key.pem"
         
         verify = verify_none
         fail_if_no_peer_cert = true
       }
     }
     ```

     **設定内容の詳細：**

     - **`cacertfile`**：クライアント証明書の検証に使用する信頼済みCA証明書を含むPEMファイルのパス。一方向認証では空またはCA証明書なしでも構いません。
     - **`certfile`**：サーバーのSSL/TLS証明書チェーンを含むPEMファイルのパス。リスナーで使用するサーバー証明書がルートCAから直接発行されていない場合は、中間CA証明書をサーバー証明書の後に連結して完全なチェーンを形成してください。
     - **`keyfile`**：サーバー証明書に対応する秘密鍵を含むPEMファイルのパス。
     - **`verify`**：EMQXがクライアント証明書を検証するか制御します。
       - `verify_none`：クライアント証明書を検証しない（一方向認証）。
       - `verify_peer`：クライアント証明書を検証する（双方向認証／mTLSで必要）。
     - **`fail_if_no_peer_cert`**：クライアントが証明書を提示しない場合のハンドシェイク挙動。
       - `false`：クライアント証明書なしの接続を許可し、証明書が提示された場合のみ無効なら拒否（一方向認証）。
       - `true`：クライアントが証明書を提示しない場合は接続を拒否（mTLSに必要）。

   - EMQXで集中管理され名前で参照する管理証明書を使用する場合は、以下の例を参照してください。

     > 管理証明書バンドルは事前にダッシュボードまたはHTTP APIで作成しておく必要があります。リスナー設定は既存の管理証明書を参照するだけです。

     **グローバルネームスペースの証明書参照例**

     ```
     listeners.ssl.default {
       bind = "0.0.0.0:8883"
     
       ssl_options {
         managed_certs = [
           {
             bundle_name = "example-cert-1"
             sni  = "example.com"
           },
           {
             bundle_name = "example-cert-2"
             sni  = "api.example.com"
           }
         ]
     
         verify = verify_none
         fail_if_no_peer_cert = false
       }
     }
     ```

     > グローバルネームスペースの管理証明書を参照する場合、`namespace`フィールドは省略します。グローバルネームスペースがデフォルトで使用されます。

     **非グローバル（テナント）ネームスペースの証明書参照例**

     ```
     listeners.ssl.default {
       bind = "0.0.0.0:8883"
     
       ssl_options {
         managed_certs = [
           {
             namespace = "tenant-a"
             bundle_name = "mqtt-cert"
             sni       = "mqtt.tenant-a.example.com"
           }
         ]
     
         verify = verify_none
         fail_if_no_peer_cert = false
       }
     }
     ```

     > 非グローバル（テナント）ネームスペースで作成された管理証明書を使用する場合は、`namespace`フィールドを明示的に指定する必要があります。

     複数の管理証明書が設定されている場合：

     - EMQXはクライアントのSNIに基づいて証明書を選択します。
     - SNIが一致しない場合はリストの最初の証明書がデフォルトとして使用されます。

4. EMQXを再起動して設定を反映します。

SSL/TLS設定完了後、MQTTクライアントでEMQXに接続できます。

## 一方向認証でのクライアント接続テスト

テストには[MQTTX CLI](https://mqttx.app/cli)を使用できます。一方向認証では通常、クライアントがCA証明書を提供し、サーバーの身元を検証します。

```bash
mqttx sub -t 't/1' -h localhost -p 8883 \
  --protocol mqtts \
  --ca certs/rootCA.crt
```

サーバー証明書のCommon Name（CN）がクライアント接続時に指定したサーバーアドレスと一致しない場合、以下のエラーが発生します。

```bash
Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Host: localhost. is not cert's CN: Server
```

この場合、クライアント証明書のCNをサーバーアドレスに合わせるか、`--insecure`オプションで証明書CN検証を無視できます。

```bash
mqttx sub -t 't/1' -h localhost -p 8883 \
  --protocol mqtts \
  --ca certs/rootCA.crt \
  --insecure
```

## 双方向認証でのSSL/TLS有効化

双方向認証は一方向認証の拡張であり、EMQXがクライアント証明書を検証してクライアントの正当性を保証するように追加設定します。

さらに、クライアント用の証明書を発行する必要があります。具体的な操作は[クライアント証明書の発行](./tls-certificate.md#issue-client-certificates)を参照してください。

ダッシュボードでは、**Verify Peer**を**有効**にし、**Force Verify Peer Certificate**オプションを`true`に設定すると双方向認証が強制されます。

設定ファイルの`listeners.ssl.default`設定グループに以下の設定を追加することも可能です。

```bash
listeners.ssl.default {
  ...
  ssl_options {
    ...
    # ピア認証を有効化
    verify = verify_peer
    # 双方向認証を強制。クライアントが証明書を提供できない場合、SSL/TLS接続を拒否する。
    fail_if_no_peer_cert = true
  }
}
```

## 双方向認証でのクライアント接続テスト

テストには[MQTTX CLI](https://mqttx.app/cli)を使用できます。双方向認証ではCA証明書に加え、クライアント自身の証明書も提供する必要があります。

```bash
mqttx sub -t 't/1' -h localhost -p 8883 \
  --protocol mqtts \
  --ca certs/rootCA.crt \
  --cert certs/client-0001.crt \
  --key certs/client-0001.key
```

サーバー証明書のCNがクライアント接続時に指定したサーバーアドレスと一致しない場合、以下のエラーが発生します。

```bash
Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Host: localhost. is not cert's CN: Server
```

この場合、クライアント証明書のCNをサーバーアドレスに合わせるか、`--insecure`オプションで証明書CN検証を無視できます。

```bash
mqttx sub -t 't/1' -h localhost -p 8883 \
  --protocol mqtts \
  --ca certs/rootCA.crt \
  --cert certs/client-0001.crt \
  --key certs/client-0001.key \
  --insecure
```
