Raspberry PiによるSOS発報システム その6 ～キャリアグレードNAT下の端末に外部からSSHでアクセスする

#もくじ
[その1 ～システム概要](https://qiita.com/maitech/items/a1497892c80826c12330)
[その2 ～GPIOを利用したスイッチの状態検知](https://qiita.com/maitech/items/d63a77dea72355f142b5)
[その3 ～アルゴリズム設計](https://qiita.com/maitech/items/f44eb0652fdb268eb9d0)
[その4 ～ハードウェアの準備](https://qiita.com/maitech/items/58a1dc2aab50afe9c5ab)
[その5 ～自動メール送信でハマる](https://qiita.com/maitech/items/9cda9861fd59453fd66e)
その6 ～キャリアグレードNAT下の端末に外部からSSHでアクセスする ←本記事です
[その7 ～総括](https://qiita.com/maitech/items/4864a1ddf991f48d728d)

#はじめに
[前回](https://qiita.com/maitech/items/9cda9861fd59453fd66e)までの投稿で，本システムのメイン機能を実現するところまで紹介しました。
今回はシステムのメンテナンスに必須となるリモートアクセスについて書いてみたいと思います。

#いつも元気に動いてくれるなら良いのですが...
このようなシステムを作ると，それがしっかり動作しているかどうか気になったり（いやこれは初めのうちだけかもしれませんが），あとからプログラムのバグに気づいたときなどは一刻も早く修正したくなったりするものです。

システムを設置した義母宅が自宅の近所であれば気軽に修正に行けますが，実際には数100km離れた場所にあるためおいそれと修正に出かけるわけにはいきません。

というわけで，実際にはSSHで接続してメンテナンスを行うのが現実的です。

#まさかのキャリアグレードNAT
下の図は，[その1](https://qiita.com/maitech/items/a1497892c80826c12330)で紹介した本システムの構成図に補足を書き入れたものです。

![Schematics2_L.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551473/4938d5bb-de84-706c-41e5-e4e5a740021d.png)
私の自宅であるHome AにはLinuxサーバがありますが，FTTHルータにポートフォワードの設定を行っているため，FTTHルータのWAN側IPアドレスがわかれば(*1)外部からSSH接続が可能になっています。

当初は今回のシステムの中核である図中のRaspberry Piにも自宅と同じようにルータのポートフォワードを設定すれば同じようにSSHできると踏んでいたのですが，これは甘い考えでした。

そうです。義母宅であるHome Bに設置したLTEルータはキャリアグレードNAT下のプライベートネットワークに接続され，グローバルIPアドレスが割り当てられないため，Home B内のLTEルータにHome Aから直接アクセスすることができないのです。
（ちょっと考えてみれば，すでに全てが配布済みのIPV4アドレスを月額298円で占有できるわけがないということはすぐにわかりそうなものですが...）

キャリアのNATサーバーの設定をゴニョゴニョすれば技術的には可能と思いますが，単なるサービス享受者である私にそんなことができるわけがありません(笑)

これは詰んだか...。リモートメンテナンスを半ばあきらめかけていた時，Home BのRaspberry Pi側からはHome AのLinuxサーバにSSHでアクセスできることに気づきました。押してダメなら引いてみましょう。

*1：ダイナミックDNSサービスを利用しているので，実際にはホスト名でアクセス可能です

#Raspberry Pi側から自宅にトンネルを掘ってもらう
というわけで，Home BのRaspberry Piに，Home AのLinuxサーバへトンネルを掘ってもらい，そのトンネルを使ってHome AのWindowsマシンからHome BのRaspberry Piにアクセスすることにしました。イメージは以下の2つの図の通りです。
![Schematics4_L.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551473/fc1758f7-7155-c76f-55c2-b7ec8ff1dc86.png)

![Schematics5_L.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551473/84af73a4-4cbe-26d7-c85b-f9f244bebb5c.png)

##トンネリングの具体的方法 ～鍵認証とautosshによる自動SSHトンネリング
Raspberry Pi側には操作者がいないので，トンネリング作業は自動，つまりパスワード入力無しで行わなければいけません。
また，同様の理由から，何らかの理由でトンネルが切断された際には自動的に再接続が行われる必要があります。

そこで，[こちら[1]](https://m-tmatma.github.io/ssh/auto_login.html)と[こちら[2]](https://www.clear-code.com/blog/2014/9/12.html)を参考にさせていただき，作業を行いました。

###鍵認証によるパスワード無しSSH接続の準備
まずは以下のコマンドをRaspberry Piのホームディレクトリで実行し，公開鍵と秘密鍵の生成を行います。

```
$ ssh-keygen -t rsa
```

これにより秘密鍵が.ssh/id_rsaとして，公開鍵が.ssh/id_rsa.pubとして生成されます。

次に公開鍵を踏み台サーバーに転送します。

```
$ scp .ssh/id_rsa.pub hoge@hogehoge.com:~/.
```

ここで，`hoge`は踏み台サーバへのログイン名，`hogehoge.com`は踏み台サーバのホスト名またはIPアドレスです。

続いて，踏み台サーバにログインし，ホームディレクトリで下記コマンドを実行することで公開鍵のセットとパーミッションの設定をします。

```
$ cat id_rsa.pub >>  .ssh/authorized_keys
$ rm  id_rsa.pub
$ chmod 755 ~
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys
```

これにて鍵認証の準備は完了。
Raspberry Pi側からSSHで踏み台サーバにログインしてみると，パスワード無しでログインできるようになっているはずです。


### 自動トンネリングの準備
続いて，Raspberry Pi側で自動トンネリングの準備を行います。

まずはSSH接続が断たれても自動で再接続してくれるautosshをインストールします。

```
$ sudo apt install autossh
```

続いて，sshトンネリングのために，以下に示すシェルスクリプトを適当な場所に作成します。

```:/home/pi/ssh_tunnel/make_ssh_tunnel.sh
#!/bin/bash
autossh hogehoge.com -l hoge -R 10022:xxx.xxx.xxx.xxx:22 -f -N
```

ここで，`hogehoge.com`は踏み台サーバのホスト名またはIPアドレス，`hoge`は踏み台サーバへのログイン名，`10022`は転送したい踏み台サーバのポート番号，`xxx.xxx.xxx.xxx`はRaspberry PiのIPアドレス（ローカルIPアドレス），`22`は転送を受けるRaspberry Pi側のポート番号です。
これにより，踏み台サーバーの10022番ポートへのアクセスはRaspberry Piの22番ポートに転送されることになります。

このシェルスクリプトを起動時に実行させるようにします。
今回はこれをcronで実現させており，/etc/crontabに以下の1行を付け加えています。

```:/etc/crontab
@reboot pi /home/pi/ssh_tunnel/make_ssh_tunnel.sh
```

これで再起動後にRaspberry Pi側から踏み台サーバに自動的にトンネリングが行われます。

#トンネリングを利用したSSH接続
まずは自宅で常用しているWindowsマシンから踏み台サーバにSSH接続し，その状態で以下のコマンドを実行します。

```
$ ssh localhost -p 10022 -l pi
```

そうです。踏み台サーバから，踏み台サーバ自身の10022ポートに対してSSH接続するのです。
先に設定したトンネリングにより，踏み台サーバ自身の10022番ポートは，Raspberry Piの22番ポートに転送されますので，実質的にはこれでキャリアグレードNAT下にあるRaspberry PiにSSH接続できるようになります。

これでいつでも自宅から遠隔地にあるキャリアグレードNAT下のRaspberry PiにSSH接続できるようになりました。
めでたしめでたし。

#次回予告
これにて本システムの紹介は終了となります。
次回は今後の課題等を含めて総括し，最終回としたいと思います。

#参考にさせていただいた情報
[1][Subversion, wwwc, clcl, swift3, OpenCover などのページ / SSH の自動ログインメモ](https://m-tmatma.github.io/ssh/auto_login.html)
[2][株式会社クリアコード > ククログ > SSHポートフォワード（トンネリング）を使って、遠隔地からLAN内のコンピュータにログインする](https://www.clear-code.com/blog/2014/9/12.html)

[](
![Schematics_L.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551473/583c6314-f82a-6299-f062-b8fa03bb32c7.png)\
![Schematics3_L.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551473/185a298f-e32c-9783-5303-353ee5ef564a.png)\
)