コーヒー飲みながら仕事したい

仕事で使う技術的なことの備忘録とか


Wordpress に引っ越しました!

Docker でコンテナをコミットする

以下、コミットの流れを備忘録として残します。

コミット

docker commit <コンテナID> <コミット名>:<tag>

上記でコミットしたコンテナは、イメージとして利用できるみたいです。

docker run -it <コミット名>:<tag>

コンテナへのアタッチ

ついでに、コンテナへのアタッチ方法です。
アタッチとは、コンテナをイメージとして起動するのではなく、コンテナをそのまま起動する?感じだと思っています。

# 開始
docker start <コンテナID>

# アタッチ
docker attach <コンテナID>

なぜか docker attach は実行後、 Enter を2回押さないといけません。

mosquitto で CommonName が異なっていても無理やり TLS 接続できるようにする

追記(修正)

mosquitto Ver1.4.15 にて修正されているようです。
ですので、最新の mosquitto を使用すると、 CommonName が異なっていても、 --insecure オプションをつければ、無理やり TLS 接続できます。

mosquitto クライアントアプリの TLS 接続における CommonName に関する仕様

mosquitto のクライアントアプリである「mosquitto_sub」および「mosquitto_pub」の仕様で、TLS接続する際、サーバーの証明書1に含まれるコモンネーム(CommonName)とサーバー(ブローカー)の接続先名称が異なる場合は接続に失敗する。

例えば、サーバーの証明書に含まれる CommonName が i_love_coffee だった場合、クライアント側の接続は以下のようになる。

# 接続失敗
$ mosquitto_sub -t abc -h 192.168.0.1 -p 8883 -d  --cafile <CAの証明書> 
Error: A TLS error occurred.

# 接続成功
$ mosquitto_sub -t abc -h i_love_coffee -p 8883 -d  --cafile <CAの証明書> 
Client mosqsub/1900-i_love_coffee sending CONNECT
Client mosqsub/1900-i_love_coffee received CONNACK
Client mosqsub/1900-i_love_coffee sending SUBSCRIBE (Mid: 1, Topic: abc, QoS: 0)
Client mosqsub/1900-i_love_coffee received SUBACK
Subscribed (mid: 1): 0

接続しようとするサーバーと CommonName が異なれば TLS 接続失敗するというのは、セキュリティ上至極まっとうである。
しかし、オレオレ認証したりデバッグする環境では、 CommonName なんて気にしたくないし、実行環境がころころ変わる場合もあり、かなり不便。

--insecure オプション・・・

一応、 --insecure オプションをつけると、ホスト名等を気にせずサーバー認証できると、 マニュアルに書いてあるが、実際にそのオプション付けても、 CommonName が異なるとはじかれる。
(これバグなの?仕様?)

mosquitto の改造

ということで、今回、ソースコードを変更して無理やり CommonName が異なっていても TLS 接続できるようにしてみた。

変更仕様としては以下である。

  • --insecure オプションを付加した場合のみ、サーバーの証明書に含まれる CommonName と接続先サーバー(ブローカー)名が異なっていても、 TLS 接続可能とする
  • 対象は mosquitto.dll
    • mosquitto_sub と mosquitto_sub は mosquitto.dll をロードして動作するため、この DLL を変更してデプロイすれば、変更される

で、ソースの変更内容は以下である。

github.com

とりあえずこれで、目的を達成することができた。


  1. サーバーの証明書(*.crt)については、前回の記事を参照

SSL/TLS の仕組みについて備忘録

備忘録と言いつつ、ほとんど参考サイトの掲載になるが、↓のサイトの「デジタル証明書の仕組み」の絵が非常に参考になります。

www.infraexpert.com

これで、認証局とか CSR(証明書要求)とかの登場人物がどういう関係かがわかります。最強です。感謝。

なお、自分なりに少し情報を整理してみます。
以前やった OpenSSL による SSL/TLS 環境の作成で出てきた拡張子とそれが何なのか?

tassi-yuzukko.hatenablog.com

  • ca.key認証局秘密鍵と公開鍵の対情報。オレオレ認証のときは自分で作るが、普通は認証局の中で厳密に保管されているはず。
  • ca.crt認証局ルート証明書。中身は認証局の公開鍵と認証局の情報をデジタル署名されたものが含まれている。これもオレオレ認証では自分で作るが、普通は認証局が公開している。
  • server.key:サーバーの秘密鍵と公開鍵の対情報。
  • server.csr:サーバーの証明書署名要求。中身はサーバーの公開鍵とコモンネーム等の各種証明書。各種証明書を認証局にデジタル署名してもらうと *.crt になる。
  • server.crt認証局によるサーバー証明書。中身はサーバー公開鍵と認証局によりディジタル署名されたサーバーの各種証明書。これは認証局の公開鍵で復号できる。

なお、↓も非常に参考になります。

d.hatena.ne.jp

mosquitto を Visual Studio でコンパイルする

githubに公開されている mosquitto のソースファイルを、Visual Studioコンパイルします。

前提

CMake を使用してソリューションファイルを生成

ここでは、CMake のインストール方法については言及しません。

mosquitto のソースファイルの用意

mosquitto のリポジトリgithub からクローンします。

CMake のビルド環境を用意

必要ファイルのダウンロード

Readmeに書いてある通り、以下をそれぞれ用意する必要があります。

環境変数の設定

ここで、ビルドを通すために、以下の通り環境変数を設定する必要があります。

  • OpenSSL
    • OPENSSL_ROOT_DIR という環境変数名で、OpenSSLの の展開フォルダを設定(例: c:\temp\OpenSSL-Win32\

CMake のビルドを実行

CMake を起動し、以下を指定し、 Configure ボタンを押す。

  • Where is the source code: に、 mosquitto の CMakeList.txt の存在するパス
  • Where to build the binaries: に、ソリューションを出力するフォルダパス

コンパイラに何を使うか聞かれるので、今回は Visual Studio 2010 を選択しました。

f:id:tassi-yuzukko:20180308164842p:plain

Finish ボタンを押すと、自動でコンパイルが走ります。

が、たぶん、 c-ares library not found とか言って怒られるので、画面上の WITH_SRVチェックボックスを外し、再度 Generate すします。

f:id:tassi-yuzukko:20180308164018p:plain

正常に終了したら、CMake のコンソール上に Generating done と表示されます。

すると、指定したフォルダに、 Visual Studio のソリューションファイルが出力されています。

参考

github.com

Visual Studio で mosquitto をビルドする

生成されたソリューションファイル(mosquitto.sln)を起動します。

そのままビルドしてもエラーになるので、以下のようにライブラリの設定をします。

OpenSSL の環境変数

system の Path 環境変数に、OpenSSLの の展開フォルダ\bin を設定します。(例: c:\temp\OpenSSL-Win32\bin\

pthreads の設定

pthreads を展開したフォルダから、以下のものをコピーしていきます。

ヘッダファイル

  • pthread.h
  • sched.h
  • semaphore.h

上記ファイルを、C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include へコピー

lib ファイル

  • pthreadVC2.lib
  • pthreadVCE2.lib
  • pthreadVSE2.lib

上記ファイルを、 C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib へコピー

dll ファイル

  • pthreadGC2.dll
  • pthreadGCE2.dll
  • pthreadVC2.dll
  • pthreadVCE2.dll *pthreadVSE2.dll

上記ファイルを、 C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin へコピー

参考

全ては時の中に… : 【VC++】スレッド(pThread)を利用する環境を整える

ビルド実行

上記でたぶん、ビルドできるはずです。

とりあえず mosquitto_sub をコンパイルしてみましたが、警告が出まくりますが、なんとか mosquitto_sub.exe が出力されました・・・

EMQ を使用して mqtt の通信をする

EMQ とは

EMQ とは、 Erlang で実装された mqtt ブローカーです。
mqtt ブローカーとしては mosquitto が有名ですが、以下の特徴があります。

  • mosquitto と比較しても、 EMQ もなかなか性能が良い(らしい)
  • mosquitto ではできない、ブローカーのクラスタを実現できる
  • Web ブラウザの GUI が提供されているので、クライアントの管理がしやすい

Document

英語ですが、こちらに公式ドキュメントが公開されています。

インストール

環境は、 Windows 10 64bit とします。

EMQ からダウンロードして、C直下にでも解凍します。解凍するだけで、OS へのインストール作業は不要です。

ブローカーの設定

とりあえずここでは、クラスタ設定は省略します。単一ブローカーのみの接続を想定します。

C:\emqttd\etc\emq.conf (C直下に解凍した場合)がブローカーの設定ファイルです。

IPアドレスの設定

以下を変更します。ここでは、ブローカーのIPアドレス192.168.0.1 を想定します。

設定キー名 変更前 変更後
node.name node.name = emq@127.0.0.1 node.name = emq@192.168.0.1
listener.tcp.external listener.tcp.external = 127.0.0.1:1883 listener.tcp.external = 192.168.100.106:1883
listener.tcp.internal listener.tcp.internal = 127.0.0.1:11883 listener.tcp.internal = 192.168.100.106

SSLの設定

↓に雑ですが記載しています。

tassi-yuzukko.hatenablog.com

ブローカーの起動

C:\emqttd フォルダに移動し、コマンドプロンプトで以下を実行します。

bin\emqttd console

最初の起動では、ファイアウォールの許可みたいなのが出るかもしれませんが、[OK] すればよいです。

ちょっと待つと、Erlang のウィンドウが表示されます。
ウィンドウ内で (emq@192.168.0.1)1> Load emq_mod_presence module successfully. と表示されれば、起動成功です。

f:id:tassi-yuzukko:20180308101429p:plain

Web ブラウザで確認

上記の起動方法でブローカーが正常に起動しているならば、http://localhost:18083/へアクセスするとダッシュボードが表示されます。

f:id:tassi-yuzukko:20180308101433p:plain

終了方法

Eranlg のウィンドウを閉じれば、同時にブローカーも停止します。

クラスタについて

今回は省略しましたが、クラスタに関しては、以下が参考になります。

qiita.com

EMQ で TLS 接続する

今回はEMQ(emqttd)を使用して、mqtt の TLS 接続をする方法。
EMQのインストール方法とかは割愛。

サーバーの公開鍵/暗号鍵の生成、それらのオレオレ認証

↓が参考になった。
基本的には前記事の mosquitto の場合と同じ。

medium.com

EMQ側の設定を変更

これも↑のサイトのまんまになるが、一つ気を付けないといけないのが、公開鍵の生成時に「CommonName」にブローカーの FQDN を設定する必要があること。
ここは mosquitto の場合と同じで、 CommonName とブローカーのホスト名が異なると、 TLS 接続できない。

mosquitto で OpenSSL を 用いて TLS 接続する

mosquitto をで TLS 接続する方法です。
OpenSSL を使用するのが簡単だと思うけど、ちょっと間が空くとすぐやり方を忘れてしまうので備忘録として残しておきます。

2018/03/11 追記/修正

いろいろ TLS について勉強してみると、言葉の使い方や理解が正しくない箇所が複数あったので修正しました。
そして、まだ勉強不足なので間違っている箇所がある可能性は十分あります・・・。

前提

  1. OS : Windows 10 64bit
  2. mqtt ブローカーもクライアントも mosquitto を使用する
  3. 秘密鍵/公開鍵やサーバー証明書の生成は、OpenSSL を使用して行う
  4. TLS するためのサーバー証明書は、自己認証局(オレオレ認証局)で実現する
  5. あらかじめ pfx 形式1のものが存在しており、それを使用して自己認証局の開局する
    (pfx ファイルのパスワードは把握しているものとする)

今回は 5. が特殊な条件ですが、現案件がこういう条件下なのでこれを前提で記述します。

pfx ファイルを秘密鍵/公開鍵情報とルート証明書に分離する

pfx ファイル(ca.pfx)を OpenSSL を使用して秘密鍵/公開鍵情報(ca.key)と自己認証局ルート証明書(ca.crt)に分離します。

# 秘密鍵/公開鍵の取り出し
$ openssl pkcs12 -in ca.pfx -nocerts -nodes -out ca.key
Enter Import Password: # ca.pfx ファイルのパスワードを入力
MAC verified OK # ca.key が出力される

# 自己認証局のルート証明書の取り出し
$ openssl pkcs12 -in ca.pfx -clcerts -nokeys -out ca.crt
Enter Import Password: # ca.pfx ファイルのパスワードを入力
MAC verified OK # ca.crt が出力される

mosquitto で TSL 接続を行う場合は、出来上がった crt ファイルをOSに「信頼できるルート証明書」として登録する必要はないので、事実上これで自己認証局の開局は済んだことになります。(mosquitto を起動する際に、ブローカーでもクライアントでも、起動引数にパスを付加することでこのルート証明書を使用します)

参考

blog.prophet.jp

サーバー(ブローカー)の秘密鍵/公開鍵を生成

ブローカーの TSL 接続用の秘密鍵/公開鍵として server.key を生成します。

# 秘密鍵/公開鍵生成
$ openssl genrsa -out server.key 2048

サーバー(ブローカー)のサーバー証明書署名要求の作成

「証明書署名要求」とは、公開鍵にコモンネーム(Common Name)等のサーバーの情報を付加したものです。

www.infraexpert.com

ブローカーの証明書署名要求として server.csr を生成します。

# 証明書署名要求の生成
$ openssl req -out server.csr -key server.key -new

いろいろ入力を促されますが、とりあえずはオレオレ認証なので Common Name (e.g. server FQDN or YOUR name) []: 以外は全て未入力(そのまま Enter )でよいです。
Common Name には、ブローカーの FQDN (ホスト名またはIPアドレス)を入力する必要があります。
もし正しく FQDN を入力しなかったら、Error: A TLS error occurred. と言われてブローカーと接続できません。

Common Name (コモンネーム)について追記

そもそも、SSL/TLS 接続を行う際に、クライアント側がサーバーを認証する(なりすましでないと特定する)手法が、サーバーへの接続文字列とコモンネームを比較することらしいです。
つまり、コモンネームが一致しないならば、相手が本物と特定できない(クライアントは相手がなりすましだと思わざるをえない)ので、それくらいコモンネームは重要です。

詳細は↓のサイトが非常に参考になります。

cspssl.jp

このサイトは SSL 接続の知識が体系的にまとめられていて、非常に勉強になります。

サーバー証明書の署名と発行

上記で生成したサーバー証明書署名要求を、自己認証局秘密鍵ca.key)でデジタル署名して、サーバー証明書を発行します。

# サーバー証明書の署名と発行
$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 36500

ここでは、有効期限を100年としています。(普通はこんなことしませんが、オレオレ認証なので・・・)

とりあえずここまでで、 OpenSSL を使用した TSL 接続用の鍵生成や署名は終了です。

参考

qiita.com

mosquitto.conf の設定

TSL 接続で使用する各証明書ファイルのパスを mosquitto.conf に追加します。
ファイルのどこに書いても良いそうです。

// C:\Program Files (x86)\mosquitto\mosquitto.conf
listener 8883
cafile   ./certs/ca.crt
certfile ./certs/server.crt
keyfile  ./certs/server.key

ここでは、上記で生成した鍵等を、 C:\Program Files (x86)\mosquitto\certs に入れているものとしています。

動作確認

# ブローカーの起動
$ mosquitto -v -c mosquitto.conf
1520414168: mosquitto version 1.4.12 (build date 29/05/2017 11:24:45.10) starting
1520414168: Config loaded from mosquitto.conf.
1520414168: Opening ipv6 listen socket on port 8883.
1520414168: Opening ipv4 listen socket on port 8883.
# mosquitto_sub の起動
$ mosquitto_sub -d -t test -h <BrokerのFQDN> -p 8883 --cafile ./certs/ca.crt
# mosquitto_pub の起動
$ mosquitto_pub -d -t test -m aaaaaa -h <BrokerのFQDN> -p 8883 --cafile ./certs/ca.crt

  1. 秘密鍵と公開鍵、サーバー証明書認証局の場合はルート証明書)をまとめて一つにし、パスワードにより暗号化されたもの