2016年3月30日水曜日

OpenBlocks IoT Familyをユーザー定義スクリプトと組み合わせて遠隔地へのアクセス手段として利用する

OpenBlocks IoT Family には、モバイル回線での接続が可能なモデルがあります。モバイル回線を使って、遠隔地のアクセス手段にOpenBlocks IoT Familyを利用する方法を紹介します。

OBDN技術ブログによる動作検証は、該当するデバイスやソフトウェアの動作について、保証およびサポートを行うものではありません。
内容に関するご指摘などありましたら、ブログ記事の担当までご連絡下さい。

はじめに


OpenBlocks IoT Family (以下OpenBlcoks)には、モバイル回線の通信機能があります。IoTゲートウェイとしては多くの場合常時ネットワーク接続手段の一つとして利用しますが、 OpenBlocksではモバイル回線の ON / OFF を SMS のメッセージによって制御する機能が用意されています。つまり通常時は通信していない状態にしておき、必要な時だけ回線を接続できるのです。また SMS を使ってあらかじめ設定しておいたシェルスクリプトを動かす機能もあります。これらのSMSによる制御機能を活用して、遠隔地のネットワークへアクセス手段としての OpenBlocks を利用します。

なお SMS を使って OpenBlocks を制御するためには、SMS に対応した SIM を使う必要があります。データ通信のみの SIM では SMS を扱うことはできませんのでご注意下さい。

リモートアクセス


次の図を見て下さい。



このような環境で、遠隔地からメンテナンスなどでサーバーにアクセスしたいというのはシステムの運用ではごく普通の要望です。

OpenBlocks の中身は Debian GNU/Linux のサーバーですので、遠隔地からOpenBlocksへログインできれば、目的のサーバーやネットワーク機器へアクセスできます。このために SSH (Secure Shell)のトンネルを活用してみます。

SSHポートフォワーディング


SSHにはTCPの接続を中継する機能が用意されています。これはポートフォワーディングやトンネリングと呼ばれます。このSSHのTCPの中継機能を例をあげて説明しましょう。

ある会社のオフィス内にWebサーバー HostA があり、インターネット上にシステム運用者がアクセスできるサーバー HostB がある場合を例にします。オフィスには NAT を使ったファイアウォールが用意されていて、オフィス内部からインターネットへは比較的自由にアクセスできるような設定になっています。この場合以下の図のように HostA から HostB へ SSH を経由してログインするのは広く行われています。



ここでインターネット側にある HostB から HostA に SSH でログインしたい場合どうしたら良いのでしょうか。

前述の通り HostA → HostB は特別な設定を行わなくても SSH で接続できるのは明らかですが、HostB → HostA の SSH 接続はファイアウォールがあることと、HostA がプライベート IP アドレスを利用しているため簡単にはできません。ここで利用するのが SSHによるポートフォワーディングです。

次の図を見てください。



この例は HostA から接続する際に、SSH のポートフォワーディングの設定で、HostB のIPv4 ループバックアドレスである 127.0.0.1 のポート番号 10022 を、HostA の IPv4 ループバックアドレスである 127.0.0.1 の ポート番号 22 つまり HostA の SSH サービスへ接続しています。

具体的には HostA から HostB へ SSH 接続する場合に次のように SSH コマンドに -R オプションを指定して起動します。(注:今回 SSH接続のオプションは全てコマンドの引数で指定していますが、これらは SSH の config ファイルで指定できます)

HostA$ ssh -R 10022:127.0.0.1:22 HostB
..........
.....
..........
HostB$ 

SSH で HostA から HostB へログインできたら、前述のポートフォワーディングが設定できています。この状態になれば HostB 側で 次のように IPv4 アドレスで 127.0.0.1 ポート番号 10022 に接続する ssh コマンドを実行すると、HostA へログインできます

HostB$ ssh -p 10022 127.0.0.1
..........
.....
..........
HostA$ 

リモートアクセスのための SSH の設定


SSH ポートフォワーディングを理解できたところで、OpenBlocks を設定してみます。前述の例で HostA が OpenBlocks となります。

まずは OpenBlocks で SSH ログイン認証のための鍵を作ります。機械的なログインに利用するため、パスフレーズは空にします。

root@obsiot:~# ssh-keygen -t ecdsa -N "" -C "Remote Access for BX1"
Generating public/private ecdsa key pair.
Enter file in which to save the key (/root/.ssh/id_ecdsa):
Your identification has been saved in /root/.ssh/id_ecdsa.
Your public key has been saved in /root/.ssh/id_ecdsa.pub.
The key fingerprint is:
13:4d:49:02:63:b6:e5:ac:2b:77:c3:46:bb:d1:63:42 Remote Access for BX1
The key's randomart image is:
+--[ECDSA  256]---+
|      =.o.o.     |
|     o * +.      |
|      . + .      |
|       . .       |
|      . E        |
|       = +       |
|    . o O +      |
|     o o * .     |
|        .        |
+-----------------+
root@obsiot:~#
root@obsiot:~# ls -l .ssh/id_ecdsa*
-rw------- 1 root root 227 Mar 29 11:43 .ssh/id_ecdsa
-rw-r--r-- 1 root root 183 Mar 29 11:43 .ssh/id_ecdsa.pub
root@obsiot:~#

この鍵を HostB との間でログインに使うため、authorized_keys を設定します。

root@obsiot:~# cat .ssh/id_ecdsa.pub  >> .ssh/authorized_keys

またこの鍵のペアを HostB の SSH でログインするユーザー(ここでは tunuser )の ~/.ssh ディレクトリに設定します。

tunuser@HostB$ ls -l .ssh
total 8
-rw-------  1 tunuser wheel  227 Mar 29 11:43 id_ecdsa
-rw-r--r--  1 tunuser wheel  183 Mar 29 11:43 id_ecdsa.pub
tunuser@HostB$ cp .ssh/id_ecdsa.pub .ssh/authorized_keys
tunuser@HostB$ ls -l .ssh
total 12
-rw-r--r--  1 tunuser wheel  183 Mar 29 12:22 authorized_keys
-rw-------  1 tunuser wheel  227 Mar 29 11:43 id_ecdsa
-rw-r--r--  1 tunuser wheel  183 Mar 29 11:43 id_ecdsa.pub
tunuser@HostB$ 

以上が設定できたら OpenBlocks から HostB にログインできるかどうかを確認しみます。この時一緒にポートフォワーディングも指定しています。(注:OpenBlocks をインターネットへ接続した状態で実験しています)

root@obsiot:~# ssh -R 10022:127.0.0.1:22 tunuser@HostB
The authenticity of host 'HostB (XXX.XXX.XXX.XXX)' can't be established.
ECDSA key fingerprint is d5:5e:df:18:bb:69:8e:e7:91:11:f5:d5:ff:3d:90:c4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'HostB,XXX.XXX.XXX.XXX' (ECDSA) to the list of known hosts.
..........

.....
..........
tunuser@HostB$ 

この通りログインを確認できました。ポートフォワーディングも指定してあるので、HostB 側から OpenBlocks へログインしてみます。(注:OpenBlocks のデフォルトではSSH 接続が閉じているため設定で解放する必要があります)

tunuser@HostB$ ssh -p 10022 root@127.0.0.1
The authenticity of host '[127.0.0.1]:10022 ([127.0.0.1]:10022)' can't be established.
ECDSA key fingerprint is 08:03:4c:2f:35:7b:15:d2:99:b8:42:f5:66:8c:3a:68.
No matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[127.0.0.1]:10022' (ECDSA) to the list of known hosts.
Linux obsiot.example.org 3.10.17-poky-edison #1 SMP PREEMPT Fri Mar 11 12:01:23 JST 2016 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Mar 29 11:07:29 2016
root@obsiot:~#

この通りポートフォワーディングを使って、インターネットにあるサーバー HostB から OpenBlocks へのログインが確認できました。

OpenBlocks の SMS コントロールコマンド(抜粋)


今回のリモートアクセスで利用するSMSコントロールコマンドを以下に挙げます。


コマンド
コマンドの内容
CON
モバイル回線を接続する
COFF
モバイル回線を切断する
SSHON
SSHを解放する
SSHOFF
SSHを閉鎖する
USCR1F
ユーザー定義のシェルスクリプトの1番をフォアグラウンドで実行する

OpenBlocks に設定した SIM の電話番号へ SMS を使ってこれらのコマンドを送ると、コマンドに応じて OpenBlocks が動作します。また SMS のコントロールコマンドは複数を"+"で接続して 1通の SMS で送ることで、連続した動作を指定できます。

例えば、モバイル回線を接続してユーザー定義シェルスクリプトの1番を実行し、モバイル回線を切断するには次のようなコマンドを送ります。

      CON+USCR1F+COFF

OpenBlocks の設定


SMS 制御でリモートアクセスを行うための OpenBlocks の設定の要点をまとめてみます。

  1. 通常時はモバイル回線は接続せず、回線の ON / OFF は SMS で制御する。
  2. モバイル回線が ON になったら SSH で HostB へ接続してポートフォワーディングを有効にするシェルスクリプトを用意する

まず上記 1 を設定します。これは WEB の設定メニューの「ネットワーク」メニューの「基本」タブの下部にある「サービスネットワーク (モバイル回線)」で設定します。



各項目の設定ポイントは次の通りです。
  • [使用設定]は「使用する」を選んでモバイル回線が利用できるようにします。
  • [APN]、[ユーザー名]、[パスワード]、[認証方式]の項目は利用する SIM に合わせて設定します。
  • [自動接続]は OpenBlocks の起動時にモバイル回線を接続するかどうかを設定するもので、通常時はモバイル回線は OFF にしておくので「自動接続しない」を選びます。
  • [SMSコントーロール]は「有効」を選択し、SMS の制御に使う電話番号を登録します。 OpenBlocks ではセキュリティ面から SMS の制御は、登録した電話番号からのみ受け付けるようになっています。

SSHポートフォワーディングを起動するシェルスクリプト


SSHポートフォワーディングを起動するシェルスクリプトは、[拡張]メニューの[スクリプト編集]のタブで、「ユーザー定義スクリプト1」を選んでから内容を入力します。



シェルスクリプトの内容は次の通りです。

#!/bin/sh

ssh -T -R 10022:127.0.0.1:22 tunuser@HostB sleep 600

この ssh コマンドはシェルスクリプトの中で起動するため、ユーザーのインタラクティブなコマンド操作を受け付ける必要はありません。そこで -T オプションを指定して、HostBでの pty を要求しないように設定しています。

ssh コマンドで HostB に対して「sleep 600」を設定します。これは SSH が 600秒間(つまり10分間)接続し、その後 sleep の終了とともに SSH の接続が終了します。何もしないと 10 分間で接続が切れる設定となります。「え?それじゃ 10分間しか SSH 接続が利用できないの?」という心配の必要はありません。SSH のポートフォワーディングでは、ポートフォワーディングの利用中は SSH 接続が切れることはありません。つまりこのスクリプトが起動してから10分以内にポートフォワーディングの接続を使って、HostB から OpenBlocks へログインすれば、そのポートフォワーディング経由のログインセッションが続いている限りSSH 接続も維持されます。

以上の設定が完了したら、OpenBlocksを一旦再起動します。

リモートアクセスを使ってみる


以上の設定が終わったので、実際に試してみましょう。OpenBlocks の SIM の電話番号に対して次の SMS のメッセージを送ります。

     CON+SSHON+USCR1F+SSHOFF+COFF

意味は、(1)モバイル回線を接続、(2)SSH接続を許可、(3)ユーザー定義シェルスクリプト1を実行、(4)シェルスクリプトの終了後SSH接続を不許可にし、(5)モバイル回線を切断、ということになります。

SMS の送信後 40秒ぐらいで OpenBlocks が HostB に SSH 接続を行います。その状態で HostB から以下のコマンドを実行すれば、OpenBlocks へログインできます。

tunuser@HostB$ ssh -p 10022 root@127.0.0.1

実際に試してみると SSH の接続までに 40秒近くかかるため、SSH 接続が成立したタイミングがはっきりしないという難点があることがわかりました。そこで例えばシェルスクリプトを次のように修正すると、tunuser アカウントのホームディレクトリに 「SSHOK」というファイルがあるか無いかで SSH 接続が成立しているかどうか判断できわかりやすくなります。

#!/bin/sh

ssh -T -R 10022:127.0.0.1:22 tunuser@HostB 'touch SSHOK ; sleep 600 ; rm SSHOK'

この他にもシェルスクリプトを工夫することで、HostB が停止している場合は別の HostC へ接続するなど様々なバリエーションが考えられます。

終わりに


SSH ポートフォワーディングは、ここで紹介したものとは逆向きつまり SSH の接続元から接続先へのポートフォワーディングもできます。ちなみに紹介例の向きのポートフォワーディングをリモートフォワード、逆向きをローカルフォワードと言います。本例での HostB から OpenBlocks へ SSH でログインする場合にもポートフォワーディングを併用できるので、サーバーのリモートデスクトップ接続を外部へ中継することなども可能です。

一昔前でしたらリモートアクセスには電話回線を通じてアナログモデムが使われているのが普通で、サーバーやネットワークのメンテナンスを行う人は必ずモデムを所有していました。しかし今ではモデムを所有している人は少なくなりつつあるどころか、モデムそのものの存在すら知らない人が増えているのも事実です。OpenBlocks のこのような使用例はモデムの代替の一つの解になるのではと思います。

0 件のコメント:

コメントを投稿