# デバイス接続のための mTLS ベストプラクティス

相互 TLS（mTLS）は、クライアントとサーバーの双方が相手の証明書を認証する仕組みであり、有効な証明書を持たないデバイスの接続を根本的に防止します。暗号化ポートでのパスワード認証を無効化することで、デバイスはユーザー名やパスワードを提供せずに接続でき、認証はTLSクライアント証明書のみに依存します。

完全な構成は以下の3ステップで行います。

1. **クライアント証明書の発行**：各デバイスに固有のクライアント証明書を発行し、証明書のCNフィールドにデバイスの固有識別子を記載します。
2. **EMQX CloudでのmTLS設定**：サーバー証明書とクライアントCAをアップロードし、双方向認証を有効化、証明書のCNフィールドをUsernameまたはClientIDにマッピングします。
3. **暗号化ポートでのパスワード認証の無効化**：暗号化ポートでパスワード認証を無効化すると、デバイスはクライアント証明書のみで接続します。

## 証明書フィールドのマッピング

EMQX Cloudはクライアント証明書の特定フィールドをMQTT接続のUsernameまたはClientIDに自動マッピングできます。有効化すると、デバイスは接続時に認証情報を提供する必要がなくなり、EMQXが証明書から直接値を読み取ります。マッピングされた値はACLルールの基準として利用可能です。

対応フィールドはCN、DN、CRTであり、[デプロイ設定](./deployment_settings.md#mqtt-settings)で選択可能です。本ガイドではCN（Common Name）フィールドを例に説明します。CNにはデバイスのシリアル番号、MACアドレス、UUIDなどを使用することを推奨します。各デバイスのCNはグローバルに一意でなければならず、同一証明書を複数デバイスで共有してはいけません。

## 証明書の準備

mTLSには以下の2種類の証明書が必要です。

- **サーバー証明書**：EMQX Cloudにアップロードし、クライアントがサーバーの正当性を検証できるようにします。生成手順は[サーバー側CA証明書の生成](./tls_ssl.md#generate-server-side-ca-certificate)を参照してください。
- **クライアント証明書**：各デバイスに配布し、サーバーがデバイスの正当性を検証できるようにします。生成手順は以下に記載します。

## クライアント証明書の発行

### クライアントCAの生成

クライアントCAは各デバイスのクライアント証明書発行に使用し、一度だけ生成すれば十分です。事前に[OpenSSL](https://www.openssl.org/)がインストールされていることを確認してください。

```bash
openssl req \
    -new \
    -newkey rsa:2048 \
    -days 3650 \
    -nodes \
    -x509 \
    -subj "/C=CN/O=EMQX Technologies Co., Ltd/CN=EMQ CA" \
    -keyout client-ca.key \
    -out client-ca.crt
```

生成された `client-ca.crt` は後ほどEMQX Cloudにアップロードします。

### 各デバイスの証明書発行

以下の手順をデバイスごとに繰り返し、`device-001` を実際のデバイス識別子に置き換えてください。

1. デバイスの秘密鍵を生成します。

   ```bash
   openssl genrsa -out device-001.key 2048
   ```

2. CNフィールドにデバイス固有識別子を入れた証明書署名要求（CSR）を生成します。

   ```bash
   openssl req -new -key device-001.key -out device-001.csr \
       -subj "/CN=device-001"
   ```

3. クライアントCAで署名し、デバイス証明書を生成します。

   ```bash
   openssl x509 -req -days 3650 -sha256 \
       -in device-001.csr \
       -CA client-ca.crt \
       -CAkey client-ca.key \
       -CAcreateserial \
       -out device-001.crt
   ```

4. 証明書を検証します。

   ```bash
   openssl verify -CAfile client-ca.crt device-001.crt
   ```

## EMQX CloudでのmTLS設定

### 双方向TLSの有効化

デプロイの**TLS/SSL設定**パネルにサーバー証明書、秘密鍵、クライアントCA証明書をアップロードします。詳細手順は[専用環境でのTLS/SSL設定](./tls_ssl.md#configure-two-way-tls-ssl)を参照してください。

### CNをUsernameにマッピング

CNフィールドをMQTT接続の`Username`にマッピングします。これによりACLルールをUsernameに基づいて適用可能です。

::: tip 注意
この機能はDedicated v5およびDedicated Flexのデプロイメントでのみ利用可能です。設定項目が見当たらない場合は、[チケットを提出](../feature/tickets.md#create-a-ticket)してアップグレードをご相談ください。
:::

1. デプロイ詳細画面で左メニューの**Deployment Settings**をクリックし、**MQTT Settings**タブを選択します。
2. **Use Peer Certificate as Username**のドロップダウンから`cn`を選択します。
3. **Save**をクリックします。

### CNをClientIDにマッピング

システムでClientIDによるデバイス管理が必要な場合、CNを`ClientID`にマッピングすることも可能です。

::: tip 注意
この機能はDedicated v5およびDedicated Flexのデプロイメントでのみ利用可能です。設定項目が見当たらない場合は、[チケットを提出](../feature/tickets.md#create-a-ticket)してアップグレードをご相談ください。
:::

1. デプロイ詳細画面で左メニューの**Deployment Settings**をクリックし、**MQTT Settings**タブを選択します。
2. **Use Peer Certificate as ClientID**のドロップダウンから`cn`を選択します。
3. **Save**をクリックします。

::: warning 注意
CNをClientIDにマッピングする場合、すべてのデバイスのCNがグローバルに一意である必要があります。同じCNを複数のデバイスが共有すると、ClientIDの競合により接続が相互に切断されます。
:::

## 暗号化ポートでのパスワード認証の無効化

上記設定完了後、暗号化ポートでのパスワード認証を無効化できます。これにより、デバイスはユーザー名やパスワードを提供せずクライアント証明書のみで接続可能になります。

::: warning 注意
パスワード認証を無効化する前に、すべてのクライアントが有効なクライアント証明書を持ち、エンドツーエンドの接続テストが成功していることを必ず確認してください。稼働中のデバイス接続に影響を与えないためです。また、平文ポート（1883）は閉じ、暗号化ポート（8883 / 8084）のみを公開することを推奨します。
:::

**V5 Dedicatedデプロイメント**ではコンソール上で直接操作可能です。手順は[ポート管理 - 暗号化ポートのクライアント認証管理](./port_management.md#manage-client-authentication-for-encrypted-ports)を参照してください。

その他のデプロイタイプの場合は、サポートへ[チケット](../feature/tickets.md)を提出してください。SREチームがデプロイメントのポート8883および8084でのクライアント認証無効化を支援します。

## クライアント接続例

### MQTTXの例

[MQTTX](https://mqttx.app/)を使ったmTLS接続テスト手順：

1. 新しい接続を作成し、接続名を入力します。Client IDはランダム生成可能です。

2. ホストを選択し、デプロイメントの接続アドレスとポートを入力します。
   - TLS接続：`mqtts://`を選択し、ポートは`8883`。
   - TLS上のWebSocket：`wss://`を選択し、ポートは`8084`。

3. パスワード認証が無効化されている場合、UsernameとPasswordは空欄のままにします。

4. **SSL/TLS**を有効化し、**Self signed**を選択します。

5. 以下の証明書ファイルを指定します。
   - **CA File**：サーバーCA証明書（`server-ca.crt`）。
   - **Client Certificate File**：デバイスのクライアント証明書（`device-001.crt`）。
   - **Client Key File**：デバイスのクライアント秘密鍵（`device-001.key`）。

6. 右上の**Connect**をクリックします。

## FAQ

### ClientID競合によるデバイス切断が発生する場合

**症状：** 2台のデバイスが同じClientIDまたは同じクライアント証明書を使用している。後から接続したデバイスが先に接続していたデバイスを切断する。

**原因：** MQTTプロトコルでは、同一ClientIDの接続はブローカー内で同時に1つしか存在できません。

**対処法：** 各デバイスに一意の証明書とCNを持たせてください。CNをUsernameにマッピングすることでClientID競合のリスクをさらに低減できます。

### 証明書が漏洩した場合の対応

1. CN-to-Usernameマッピングを有効にしている場合、漏洩したデバイスのCNに対応するUsernameを[ブラックリスト](./blacklist.md)に即時追加し、再接続を防止します。
2. 対象デバイスに新しい証明書を発行し、デバイス側の証明書設定を更新します。
3. ブラックリストのエントリが期限切れまたは手動削除されるまで、漏洩した証明書は接続に使用できません。

### パスワード認証無効化後も追加認証は必要ですか？

暗号化ポートでパスワード認証を無効化すると、認証はTLSクライアント証明書のみに依存し、ユーザー名／パスワード認証より強固なセキュリティを提供します。クライアント証明書を一時的に使用できないデバイスがある場合は、移行期間中はパスワード認証を有効にしておき、すべてのデバイスが証明書認証に移行後に無効化することを推奨します。
