Mosquitto TLS/SSL 認証 できない

Mosquitto TLS/SSL 認証 トラブルシューティング

TLSなし起動テスト
# Mosquitto サービス開始
$ sudo systemctl start mosquitto

# ポート・リスニング確認
$ sudo lsof -i -P
mosquitto  396 mosquitto    4u  IPv4   9766      0t0  TCP *:1883 (LISTEN)
mosquitto  396 mosquitto    5u  IPv6   9767      0t0  TCP *:1883 (LISTEN)

# 接続待ちをしているソケットを確認
$ sudo ss -ltunp
tcp    LISTEN   0  100   *:1883   *:*   users:(("mosquitto",pid=396,fd=4))

# Mosquitto サービス停止
$ sudo systemctl stop mosquitto

とても参考になるサイトを発見

Mosquitto MQTTメッセージングブローカーをインストールして保護する方法

設定は /etc/mosquitto/conf.d/mosquitto.conf に記述する。

sl3_get_record:wrong version number のエラーに悩んでる
$ sudo systemctl restart mosquitto

$ mosquitto_pub -h pi -t test -m "hello again" -p 8883 --capath /etc/mosquitto/certs/ -u "admin" -P "パスワード" 
# --capath /etc/mosquitto/certs/ でも
# --capath /etc/mosquitto/ca_certificates/ にしても
sl3_get_record:wrong version number エラーが出る。

証明書作成時の Common Name を変化させてもダメ
-h pi も pi.local も localhost も 192.168.0.220 もダメ

 

test.mosquitto.org で TLS認証をテストする

test.mosquitto.org

python でTLS認証

python の MQTT ライブラリをインストールする。

# pip インストール
$ sudo apt-get install python-dev
$ sudo apt-get install python-pip
$ sudo pip install --upgrade pip

$ sudo pip install paho-mqtt

# CA証明書(mosquitto.org.crt)をダウンロード
$ wget http://test.mosquitto.org/ssl/mosquitto.org.crt

PUB側とSUB側それぞれをSSH開き、PubSubそれぞれのpythonコードを実行すると成功した。
但し、日本語メッセージを発行しても購読できなかった。

Raspberry Pi の mosquitto broker でやってみる。

実行するとエラーメッセージが出たのでよく見ると接続先がtest.mosquitto.orgだったのでpi.localにしたが全く同じエラーメッセージが出た。
pi.local を pi 、192.168.0.220 でも同じメッセージだった。
と言うことはbroker側の証明書の作成が悪いのか、設定が悪いか・・・

Traceback (most recent call last):
File "test_pi_local_TLS_SUB.py", line 15, in <module>
client.connect("pi.local", 8883)
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 839, in connect
return self.reconnect()
File "/usr/local/lib/python2.7/dist-packages/paho/mqtt/client.py", line 994, in reconnect
sock.do_handshake()
File "/usr/lib/python2.7/ssl.py", line 840, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)

mosquitto.conf が間違っていたので訂正。
パスワード認証なしにする。

それでもエラー orz

CA証明書作成スクリプトを使った事例でやってみる

ここここの説明に沿ってやってみる。
どうも証明書作成時に hostname や 接続IPを正しく伝えないといけないようだ。

まず、generate-CA をコマンド化

$ cd ~/bin
$ wget https://github.com/owntracks/tools/raw/master/TLS/generate-CA.sh generate-CA
$ mod 755 generate-CA

# サーバーの IP リストを全て記述 ※127.0.0.1は必ず付加されるので記述不要
$ IPLIST="192.168.0.220"

# サーバーの接続可能なホスト名称を全て記述 ※localhostは必ず付加されるので記述不要
$ HOSTLIST="pi pi.local pi.xxx.jp"

$ generate-CA
$ generate-CA
$ generate-CA
$ ls
ca.crt
ca.key
c​​a.srl
pi.crt
pi.csr
pi.key
$ sudo cp ca.crt /etc/mosquitto/ca_certificates/ 
$ sudo cp myhost.crt myhost.key /etc/mosquitto/certs/

 

localhost であれば発行、購読できたがTLS認証が確立したかはわからなかった。
pi、pi.local、192.168.0.220 ではエラーとなる。

generate-CA の HOSTLIST 、 IPLIST の取り込みを追ってみた。

再度作成しなおしたら $HOSTLIST, $IPLIST に設定した内容が  subjectAltName に反映されてる。
無事 pi, pi.local, localhost で発行、購読できた。
しかし IPアドレスでは接続できなかった。

 

以下上手くいかなかったときの作成手順

Mosquitto TSL/SSL 認証

参考1参考2参考3

CA(認証局)の、CAキー:mqtt_ca.key の作成

$ openssl genrsa -des3 -out mqtt_ca.key 2048
$ openssl rsa -noout -text -in mqtt_ca.key    # 内容確認

CAキーによるCA署名入り、CA証明書:mqtt_ca.crt の作成

$ openssl req -new -x509 -days 3650 -key mqtt_ca.key -out mqtt_ca.crt
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Tokyo
Organization Name (eg, company) [Internet Widgits Pty Ltd]:会社名
Organizational Unit Name (eg, section) []:Development(Enter可)
Common Name (e.g. server FQDN or YOUR name) []:mymyCA(オレオレ認証局とわかる名前)
Email Address []:ユーザー@gmail.com(Enter可)
$ openssl x509 -text -fingerprint -noout -in mqtt_ca.crt  # 内容確認

MQTTサーバーの、サーバーキー:mqtt_srv.key の作成

$ openssl genrsa -out mqtt_srv.key 2048
$ openssl rsa -noout -text -in mqtt_srv.key    # 内容確認

サーバーキーをCA認証してもらう為の、CAリクエスト:mqtt_srv.csr の作成

$ openssl req -new -out mqtt_srv.csr -key mqtt_srv.key
Country Name (2 letter code) [AU]:JP(Enter可)
State or Province Name (full name) [Some-State]:Tokyo(Enter可)
Locality Name (eg, city) []:Tokyo(Enter可)
Organization Name (eg, company) [Internet Widgits Pty Ltd]:会社名(Enter可)
Organizational Unit Name (eg, section) []:Development(Enter可)
Common Name (e.g. server FQDN or YOUR name) []:mymyCA(オレオレ認証局とわかる名前)
Email Address []:ユーザー@gmail.com(Enter可)

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:(Enter)設定するとApacheの起動時に毎回パスワードを求められる
An optional company name []:(Enter)

CAリクエストによりサーバーキーがCA署名入り証明書で認証されたことを証明する、サーバー証明書:mqtt_srv.crt の作成

$ openssl x509 -req -in mqtt_srv.csr -CA mqtt_ca.crt -CAkey mqtt_ca.key -CAcreateserial -out mqtt_srv.crt -days 3650
$ openssl x509 -text -fingerprint -noout -in mqtt_srv.crt      # 内容確認

上記の操作で作成されたファイル

● mqtt_ca.crt  : CA証明書
  mqtt_ca.key  : CAキー (private, public)
  mqtt_ca.srl  : CA serial number file
● mqtt_srv.crt : サーバー証明書
  mqtt_srv.csr : CAリクエスト
● mqtt_srv.key : サーバーキー

# ●ファイルを認証フォルダに移動する
$ sudo mv mqtt_srv.crt mqtt_srv.key /etc/mosquitto/certs/
$ sudo mv mqtt_ca.crt /etc/mosquitto/ca_certificates/

# 残りのファイルは必要ないので削除する。
$ rm mqtt_ca.key mqtt_ca.srl mqtt_srv.csr

Mosquitto設定ファイル

ローカル設定ファイルに追加する。

$ cat << EOL >> /etc/mosquitto/conf.d/mosquitto.conf

# 1883 はlocalhost 以外からは受け付けない
listener 1883 localhost
# TSL/SSL ポート
listener 8883

# CA証明書
cafile /etc/mosquitto/ca_certificates/mqtt_ca.crt

# サーバー証明書
certfile /etc/mosquitto/certs/mqtt_srv.crt

# サーバーキー
keyfile /etc/mosquitto/certs/mqtt_srv.key
EOL

クライアント側に必要なファイルはCA証明書ファイル mqtt_ca.crt のみです。

クライアント側から接続する際には、MQTTクライアントアプリでTLS/SSL接続、ポートの指定、mqtt_ca.crtのパス指定が必要になります。

TLS認証での動作確認
# サーバー再起動して新しい設定を読み込む
$ sudo systemctl restart mosquitto

# TLS+パスワードファイルモードで購読開始
sudo mosquitto_sub -d -t test -h pi.local -p 8883 --cafile /etc/mosquitto/ca_certificates/mqtt_ca.crt -u "admin" -P "パスワード"

# TLS+パスワードファイルモードで発行開始
$ mosquitto_pub -h pi.local -t test -m "TLS Auth for Raspberry Pi 3 B+" -p 8883 --cafile /etc/mosquitto/ca_certificates/mqtt_ca.crt -u "admin" -P "パスワード"

何度も失敗してようやく成功!
肝はCA証明書の作成だった。