最近はラズベリーパイをつかってIoTデバイスを作ろうという試みをやっています。
ラズパイのキットはこれが調子いいです。
売り上げランキング: 48,720
ラズベリーパイ、Linuxが搭載されていますし、無線LANの挙動も実に軽快なので、LAN内にいる時はSSH接続がとても簡単です。しかし、IoTデバイスというのは常にLAN内にあるものとも限らず、SIMカードを使ってスマホのように各キャリアが提供するネットワークを使ってインターネットにアクセスする必要もあります。
私はラズパイをインターネットに接続させるSIMとして、Soracomを選びました。
SoracomのSIMにはグローバルIPが割り振られておりません。
そしてIPが割り当てられていない以上、一般的なTCP/IP – DNSを使ったSSH接続はできないということになります。
とはいえ開発中、Docomoネットワークを使ってインターネットに接続するSIMを使ったラズパイに対して、SSH接続したいことは往々にしてよく起こります。
それができなければわざわざシーケンス制御のプログラムを書いて実行しなければならない、といったような。
ということで、SoracomのSIMをはじめとする、グローバルIPが割り振られていないSIMを使ってインターネットにアクセスをしているラズパイに対して、SSH接続をする方法(NAT超えSSH接続)をここに記しておきたいと思います。
使っているラズパイの条件は下記の通りです。
raspberry pi : Raspbian GNU/Linux 9.8 (stretch)
autossh : 1.4e
soracom sim : SORACOM Air SIM plan-D (SMS/data)
3G USBドングル : Abit AK-020
中継サーバーが必須
まずは中継サーバーを用意しましょう。
この方法は図のように、中継サーバーを介してラズパイにアクセスをすることになります。
上にも書きましたがSoracom SIMを使ったラズパイの場合、グローバルIPが割当てられていないことで、通常のTCP/IPだけでは座標を特定することができないからです。
なので、SSHポートフォワーディング(SSHトンネル)という技術を使って、中継サーバーを介してラズパイにアクセスできるようにします。
簡単に順番に仕組みを説明すると
- ラズパイ、起動直後に中継サーバーに対してSSHポートフォワーディングをする
- Macbook、中継サーバーにSSHアクセスする
- 中継サーバーに入ったMacbook、ポートフォワーディング情報をもとに、ラズパイにアクセスする
ということです。
ポートフォワーディングというのは、SSH接続をする際に、接続先のサーバーの任意のポートと、接続元のデバイスの任意のポートに転送(同一化)させるというような技術です。
このケースの場合、(ラズパイのSSHポートは22番であるという前提とします)接続先の中継サーバーの4649番のポートを、接続元のラズパイの22番ポートに転送するということによって、中継サーバーにアクセスしたMacbookは中継サーバーの4649番ポートにssh接続をすることで、ラズパイに対してssh接続をするという仕組みを取ります。
実践
前提として中継サーバーに接続する際に使うユーザーを中継サーバー側で用意しておく必要があります。
このケースの例としてuserを使いますので、中継サーバー側で作成しておいてください
# adduser user
鍵の作成
この方法ではラズパイの起動直後に中継サーバーに対してSSH接続をしなければなりませんので、パスワードを入力することができません。そのため公開鍵暗号方式を使ってパスワードなしで接続できるようにします。
まずは、中継サーバー側のsshd_configのPubkeyAuthenticationはyesに設定しておきましょう。
次にラズパイ側でssh接続のための鍵を作ります。
ssh-keygen -t rsa
(鍵の暗号化方式はどれがよいかという議論はありますが、ここでは省略、今回はrsaを採用します。)
あとは対話形式で鍵の作成が進んでいきますが、パスフレーズを聞かれるところでは何も入力せずに進んでください。
+---[RSA 2048]----+
| .. . ... |
| ... o . |
| o. + * o |
| . .. o & o|
| S = O |
| ..+ o|
| ..oooEo|
| o*==+*|
| .*@BO=|
+----[SHA256]-----+
こういう暗号のイメージが表示されたら鍵の作成は完了です。
~/.ssh/に
id_rsa
id_rsa.pub
の2つのファイルが生成されています。
id_rsaが秘密鍵、id_rsa.pubが公開鍵です。
秘密鍵は絶対に人の手に渡らないように、ネットワークに流れることのないようにしましょう。
中継サーバーへ公開鍵の転送
出来上がった公開鍵を中継サーバーに送り、鍵を認証してもらいます。
ssh-copy-id user@192.168.0.100
#sshdのlistenポート番号を変更している場合は下記のように
ssh-copy-id user@192.168.2.30 -o port=10000
userと@以降のipについてはssh接続するユーザー名と接続先のホスト名またはIPアドレスを入力します。
コマンドが通ればパスワードを尋ねられますので、中継サーバー上でuserに設定しているパスワードを入力しましょう。公開鍵の転送が完了します。
この状態で
ssh user@192.168.0.100
と入力して、パスワードを聞かれずにサーバーにログインできれば成功です。
SSHポートフォワーディング
ラズパイから中継サーバーにログインする時に使うコマンドに、ポートフォワーディング用のオプションを追記します。
ssh -R 4649:localhost:22 user@192.168.0.100
-R 4649:localhost:22
というオプションを追加することで、中継サーバーの4649番ポートをラズパイの22番ポートに転送できます。
したがって上図に示しているMacbookは、中継サーバーにログインした後
ssh pi@localhost -o port=4649
とすることで、中継サーバーを経てラズパイにログインすることが可能になりました。
ラズパイから中継サーバーへssh接続の自動化
ラズパイの起動直後に中継サーバーへssh接続を自動化するには、ラズパイのcrontabに追記するのが良いのではないかと思います。
crontab -e
によってcrontabを開き、
@reboot ssh user@192.168.0.100
と書き込めば起動時に自動的に中継サーバーに接続しに行くようになります。
このとき、いくつかの設定を追加するのも良いかと思います。
具体的には ~/.ssh/config に下記のような設定を追加しておきます。
Host RelayServer
HostName relay-server.com #中継サーバーのホスト名
User user
IdentityFile ~/.ssh/id_rsa
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
ServerAliveInterval 60
ServerAliveCountMax 3
ExitOnForwardFailure yes
RemoteForward 4649 localhost:22
それぞれのオプションの説明をします。
HostNameは中継サーバーのアドレスです。
Userには中継サーバーにログインするユーザー名を入力します。
IdentityFileは秘密鍵の場所を書きます。
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
によって、はじめて接続するホストの場合でも警告(fingerprint云々)を出さないようにしたり、known_hostsファイルに影響を与えることなく接続できます。
ServerAliveInterval 60
ServerAliveCountMax 3
このオプションによって、サーバーからのタイムアウトを回避します。
60秒毎にサーバーにメッセージを送り、ServerAliveCountMax の設定回数、3回まで繰りかえします。
もしサーバーが応答しなくなったら 180秒後に接続が切断されるようになるということですね。
ExitOnForwardFailure yes
このオプションによって、既にポートフォワード先のポートが空いてなかった場合はssh接続をせずに終了します。
RemoteForward 4649 localhost:22
このオプションで接続先の中継サーバーの4649番ポートに、接続元のラズパイの22番ポートに転送できます。
これらの設定が終われば、
ssh RelayServer
と入力するだけで上記で設定したオプションを踏まえたssh接続ができます。
自動で接続する際には -N -f オプションをつけてもいいです。それぞれ
-N は接続先でポートフォワーディングのみに利用する接続であることを明示するオプション
-f はバックグラウンドで実行することを明示するオプションです。
crontabの方にも
@reboot ssh -N -f RelayServer
と書いておくとこれらが自動で実行されます。
autosshのインストール
さらにautosshを使ってssh接続するという選択もあります。
普通のsshを使っても問題はないのですが、autosshの場合、セッションが何らかの原因で途切れてしまった場合、自動的に再接続をしてくれます。
autosshはsshと互換のあるコマンドですので、普段からautosshを使うのもありですね。
#apt-get install autossh
でインストールできます。
上記のことをautosshでやる場合、crontabには
@reboot autossh -M 0 -N -f RelayServer
と書きましょう。
-M 0 オプションは
autossh標準のsshコネクションモニタリングを無効にし、OpenSsh自体のモニタリングを有効にします。
OpenSsh自体のモニタリングとはServerAliveInterval 60や、ServerAliveCountMax 3などの設定のことです。
autosshのmanページで、これは推奨されています。
この方法でのSSH接続は信頼性があまり高くない
以上のことを実行すると、ラズパイ起動時に中継サーバーに自動で接続しにいき、そのセッションを使ってクライアント(macbook)からラズパイに接続しにいくことができるようになります。
しかし、ラズパイを再起動などすると、再接続までにとても時間がかかったりします(時間測ったら10分くらいかかりました)
その場合、中継サーバーをリブートしてから、ラズパイをリブートすると、すぐに接続できたりするのですが…
おそらく、ラズパイリブートする前にautosshの接続をきちんと切ってからリブートすればいいのかなあなんて今書きながら思いましたが、まだ試していません。
いずれにしろ、この方法を使ったSSH接続はあくまで開発途中での実験やデバッグに用いるのがよさそうです。
中継サーバー上のポートListenの履歴を、ラズパイが沈黙した後にすぐに削除するなどの施策を取ることができれば完全に安定させることができるのかも知れませんが。
なお、この記事を書くにあたって下記のサイトを参考にさせていただきました。
ありがとうございます。
SSH公開鍵認証でパスワード無しでログインする!ユーザも指定できる! | ぴぐろぐ
Soracom Airで繋がったデバイスにリモートからSSHする | DevelopersIO
この記事へのコメントはありません。