mosquittoとIoTCoreを使用してTLSでMQTT通信をやってみた(mTLS、パスワード認証)
よくMQTTでブローカーとして使用されるmosquittoをローカルのコンテナで立ち上げ、IoTCoreとTLSで通信する手順をまとめます。
MQTTやIoTCoreに関する基本的な説明は省きますが、初心者の方でもわかりやすいように図で補足しながら進めます、全体の構成をイメージできるようになれば幸いです。
バージョン情報
- mosquitto : 2.0.20
- Openssl : 3.4.0
前置き
今回作る構成のイメージはこちら
ローカル端末のDockerにてmosquittoを立ち上げ、これをブローカーとします。
そしてローカルのターミナルとIoTCoreでパブリッシュ、サブスクライブをしてメッセージの送受信を行います。
IoTCore 準備
まずはIoTCore側の準備から始めます
証明書作成
セキュリティ → 証明書 で、「証明書を追加」
証明書のステータスを「アクティブ」にして「作成」
すると以下の証明書や鍵をダウンロードする画面が表示されます
今回は必要な物のみダウンロード
- デバイス証明書
- プライベートキーファイル(秘密鍵)
- Amazon 信頼サービスエンドポイント-Amazon ルートCA1(CA証明書)
ダウンロードしたファイルを作業ディレクトリに配置
certs/iotcoreにおきます
わかりやすくするために名前も変更しておきましょう
続いて、先ほど作成した証明書に適用するポリシーを作成します
IoTCoreにて、セキュリティ → ポリシー で「ポリシーを作成」
ポリシー名とポリシードキュメントを入力
今回はテストのため、ポリシーアクションもポリシーリソースも * にしておきます
ちなみにJsonだとこんな感じ
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
ポリシーを作成したら証明書にアタッチします
ということで作成した証明書の画面に入り、「ポリシーをアタッチ」
作成したポリシーを選択
これでIoTCore側の準備は完了です
証明書類の作成
TLS通信のため証明書類を作成する手順です、オレオレ証明書で進めます。
今回はローカルのターミナルをクライアント、ローカルのmosquittoコンテナをサーバーとして相互TLS認証(mTLS)をする方針でいきます。
TLS通信周りの話は証明書やら鍵やらがたくさん出てきてわかりにくいと思うので、図を混ぜながら解説します。
こちらも参考に
CA
CAの秘密鍵の作成
openssl genrsa 2048 > ca.key
CA証明書の作成
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
サーバー側
サーバーの秘密鍵の作成
openssl genrsa 2048 > server.key
サーバーのCSR作成
openssl req -new -out server.csr -key server.key
CAによる署名
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360
クライアント側
クライアントの秘密鍵の作成
openssl genrsa 2048 > client.key
クライアントのCSR作成
openssl req -new -out client.csr -key client.key
CAによる署名
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360
ここまで進めると、下記のように9つのファイルが出力されていると思います
続いてフォルダの整理をやっていきます
certs/にmosquittoフォルダを作成し、以下のファイルを格納します
- CA証明書
- サーバーの秘密鍵
- サーバー証明書
Dockerfile 作成
続いて、作業ディレクトリにDockerfileとmosquittoの設定ファイルである「mosquitto.conf」を作成します
まずはDockerfile
Dockerfile
FROM eclipse-mosquitto:2.0
# 設定ファイル,証明書フォルダをコピー
COPY ./mosquitto.conf /mosquitto/config/mosquitto.conf
COPY ./certs /mosquitto/config/certs
# ポートの公開
EXPOSE 8883
mosquitto.confの作成
mosquittoの設定ファイルです、サーバー証明書、IoTCoreの証明書、IoTCoreのアドレス、ログ設定などいろいろな設定をこのファイルで定義します
設定項目に関する公式ドキュメント
# Mosquittoのリスナー設定
listener 8883
protocol mqtt
# CA証明書,サーバー証明書,秘密鍵
cafile /mosquitto/config/certs/mosquitto/ca.crt
certfile /mosquitto/config/certs/mosquitto/server.crt
keyfile /mosquitto/config/certs/mosquitto/server.key
# AWS IoT Coreへの接続設定
connection aws-iot
address ************.iot.ap-northeast-1.amazonaws.com:8883
# AWS IoT Coreのトピック設定
topic # both
# AWS IoT Core用のTLS設定
bridge_cafile /mosquitto/config/certs/iotcore/RootCA.pem
bridge_certfile /mosquitto/config/certs/iotcore/cert.crt
bridge_keyfile /mosquitto/config/certs/iotcore/private.key
# 相互認証
require_certificate true
use_identity_as_username true # クライアント証明書のCNをユーザー名で使用する
# ログ設定
log_dest stdout # ログをstdout(標準出力)に出力する
log_type all # すべてのログを出力する
log_timestamp true # ログにタイムスタンプを付与する
connection_messages true # クライアントの接続/切断のメッセージも付与する
# ブリッジ設定
bridge_insecure false
start_type automatic
notifications false
try_private true
編集が必要なのは下記の部分です
# AWS IoT Coreへの接続設定
connection aws-iot
address ************.iot.ap-northeast-1.amazonaws.com:8883
このaddressに、IoTCoreのドメインを設定します
IoTCoreはデフォルトで1つドメインを作成してくれているので、今回はそれを使用します
IoTCoreの「設定」
ドメイン設定を表示(どちらでもOK)
ドメイン名をコピーして先ほどの設定ファイルの値を更新
※リージョンによってドメインが変わります 今回は東京リージョンで進めます
address ************.iot.ap-northeast-1.amazonaws.com:8883
末尾の「:8883」はポート番号のため消さないように注意
今の作業ディレクトリの状況
.
├── Dockerfile
├── ca.key
├── ca.srl
├── certs
│ ├── iotcore
│ │ ├── RootCA.pem
│ │ ├── cert.crt
│ │ └── private.key
│ └── mosquitto
│ ├── ca.crt
│ ├── server.crt
│ └── server.key
├── client.crt
├── client.csr
├── client.key
├── mosquitto.conf
└── server.csr
データの送受信を確認
すべての設定が済んだので、Dockerコンテナを立ち上げMQTTのメッセージ送受信をしていきます
Dockerビルド、コンテナ起動
docker build -t my-mosquitto .
docker run --rm -d --name mqtt-test -p 8883:8883 my-mosquitto
※ --rm オプションでコンテナ停止後、そのままコンテナを削除するようにしてます。
IoTCore テストクライアントの準備
東京リージョンにして、「MQTTテストクライアント」
IoTCore側の操作(サブスクライブ、パブリッシュ)はこの画面で行います。
ローカル端末の名前解決
サーバー証明書のCommon Nameを「locahost」と設定し、ローカル端末からmosquittoコマンドを実行するときのホスト名も「locahost」と指定するため、ローカル端末がlocahostというホスト名を名前解決できるか確認しておきます。
Macの場合、以下のコマンドでホストファイルを確認できます
cd ~
sudo vim /private/etc/hosts
127.0.0.1とlocalhostの組があればOKです。
(自分の場合は最初から127.0.0.1とlocalhostが紐づいていました)
ローカル端末からパブリッシュ
まずはローカル端末のターミナルよりmosquittoコマンドを使用してMQTTメッセージをパブリッシュし、IoTCoreでサブスクライブしてみます
図だとこんな感じです、コマンド実行時証明書にアクセスする必要があるため、ターミナルは作業ディレクトリに入っておきます。
IoTCore サブスクライブ
まずはMQTTテストクライアントにてサブスクライブの設定
「トピックをサブスクライブする」のタブでトピックのフィルターを入力します。
今回は「test/topic」という名前でやり取りすることにします。
ローカル端末 パブリッシュ
IoTCoreの待ち受けが完了したのでターミナルからパブリッシュをしていきます
今回はmosquitto_pubコマンドを使用します
mosquitto_pub \
--cert client.crt \
--key client.key \
--cafile ./certs/mosquitto/ca.crt \
-h localhost \
-t "test/topic" \
-m '{"device_name": "test-sensor-001"}'
- --cert … クライアント証明書
- --key … クライアントの秘密鍵
- --cafile … CA証明書
- -h … 宛先
- -t … トピック名(先ほどIoTCoreで入力したトピックをここに)
- -m … メッセージ本文
mosquitto_pubに関するドキュメント
こちらを実行し、データの送受信が成功するとIoTCore側で送信したメッセージが確認できます。
IoTCoreからパブリッシュ
次は逆向きでデータを送受信します。
ローカル端末 サブスクライブ
今度は「mosquitto_sub」コマンドを使用します
コマンドの内容はpubの時から-m属性を抜かしたものと一緒です。
mosquitto_sub \
--cert client.crt \
--key client.key \
--cafile ./certs/mosquitto/ca.crt \
-h localhost \
-t "test/topic"
mosquitto_subに関するドキュメント
コマンド実行後、待ち受け状態になったら次に進みます
IoTCore パブリッシュ
MQTTテストクライアントの、「トピックに公開する」タブを開き、先ほどローカル側で-tにて指定したトピック(test/topic)と、メッセージ本文を入力して「発行します」
すると待ち受け状態のターミナルにメッセージが受信されます。
これでmosquittoコンテナをブローカーとしてローカル端末とIoTCore間でMQTTのやり取りができました。
おまけ TLSをパスワード認証でやってみる
mosquittoでTLS通信を行う際、相互認証のほかにパスワード認証も機能することを確認できました。
相互認証ではクライアント証明書が必要でしたが、パスワード認証だとユーザー名とパスワードでTLS通信が実施できます。
必要な手順
作業ディレクトリにユーザー名とパスワードの組を記入したパスワードファイルを生成します
pass.txt
user001:password001
以下のコマンドでパスワードを暗号化とファイルの権限を変更します
mosquitto_passwd -U pass.txt
chmod 0700 ./pass.txt
これで、pass.txtのpassword001の部分が暗号化されます
Dockerfile
作成したパスワードファイルを配置するため以下の行を追加します
COPY ./pass.txt /mosquitto/config/pass.txt
mosquitto.conf
mosquitto.confにパスワード認証のための設定を追加します
password_file /mosquitto/config/pass.txt
これでDockerコンテナを起動し、メッセージパブリッシュ時のコマンドに-u、-Pオプションを追加すれば、パスワード認証によるTLS通信ができるようになります
-uがユーザー名、-Pがパスワードのため、今回の例だとこんな感じ
mosquitto_pub \
--cafile ./certs/mosquitto/ca.crt \
-h localhost \
-t "test/topic" \
-m '{"device_name": "test-sensor-001"}'
-u user001 \
-P password001
以上、参考になれば幸いです