ブログに書くつもりじゃなかった

フリーのプログラマーが綴る、裏チラ系の備忘録や雑記帳。

MosquittoでTLS通信

はじめに

昨日作ったMQTTのお試し環境TLS通信できるようにする。

DockerとEclipse MosquittoでMQTT - ブログに書くつもりじゃなかった

証明書の作成

この辺はググればいくらでも出てくる情報だが、俺自信が覚えるために。

認証局秘密鍵を作成
$ openssl genrsa -des3 -out ca.key 2048
Generating RSA private key, 2048 bit long modulus
.......+++
....+++
e is 65537 (0x10001)
Enter pass phrase for ca.key:
Verifying - Enter pass phrase for ca.key:
自己署名証明書を作成
$ openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
Enter pass phrase for ca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:root-ca        
Email Address []:
サーバーの秘密鍵を作成
$ openssl genrsa -out server.key 2048
Generating RSA private key, 2048 bit long modulus
...............................+++
...............+++
e is 65537 (0x10001)
サーバーの証明書要求を作成
$ openssl req -new -out server.csr -key server.key
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:JP
State or Province Name (full name) []:Miyagi
Locality Name (eg, city) []:Sendai
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:mosquitto-broker
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:

Common Nameはホスト名に合わせる。

証明書要求に署名する
$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360 -sha256
Signature ok
subject=/C=JP/ST=Miyagi/L=Sendai/CN=mosquitto-broker
Getting CA Private Key
Enter pass phrase for ca.key:

後述するけど、自分の環境では-sha256オプションが必要だった。

環境構築

mosquitto.conf

リッスンするポート番号を8883に変更。証明書と秘密鍵のパスを指定。

allow_anonymous true
listener 8883
cafile /mosquitto/certs/ca.crt
keyfile /mosquitto/certs/server.key
certfile /mosquitto/certs/server.crt
docker-compose.yml

証明書と秘密鍵のファイルをバインドする。

version: '3'
services:

  mosquitto-publisher:
    build: .
    container_name: mosquitto-publisher
    tty: true
    volumes:
      - ./ca.crt:/ca.crt

  mosquitto-subscriber:
    build: .
    container_name: mosquitto-subscriber
    tty: true
    volumes:
      - ./ca.crt:/ca.crt

  mosquitto-broker:
    image: eclipse-mosquitto
    container_name: mosquitto-broker
    volumes:
      - ./mosquitto.conf:/mosquitto/config/mosquitto.conf
      - ./ca.crt:/mosquitto/certs/ca.crt
      - ./server.key:/mosquitto/certs/server.key
      - ./server.crt:/mosquitto/certs/server.crt

実践

Subscriber側。--cafileオプションでCA証明書を指定する。

$ mosquitto_sub -h mosquitto-broker -t mytopic --cafile /ca.crt

Publisher側。同じく--cafileオプションでCA証明書を指定する。

$ mosquitto_pub -h mosquitto-broker -t mytopic -m "This is a test." --cafile /ca.crt

つまずいた箇所

当初mosquitto_submosquitto_pubを実行したときにTLSエラーが出た。

Error: A TLS error occurred.

証明書を作り直す、dockerコンテナの設定を変えるなどして何度も試したが、なかなか解決せず。結構な時間を使った後で、証明書の中身を覗くと、署名アルゴリズムがまさかのSHA1になってたのを発見。

$ openssl x509 -text -noout -in server.crt

どうやらこれが原因で、サーバー証明書の危険が危ない的なエラーになっていたようだ。証明書要求を認証する際に-sha256オプションを付けることで、無事解消。やれやれ。