Qiita初投稿です
他の人にSSHポートフォワーディング機能を説明する事になり、良い機会なので投稿の練習がてら記事にしようと思いました。
はじめに
SSH接続はリモートにログインして作業するだけではなく、ローカル/リモートにポートを開けて様々なデータを転送するポートフォワーディング機能があります。この記事はその機能の基本的な説明や、その機能を使った利用例というような話になります。
0. SSHサーバ側の設定
以降で説明するポートフォワーディング機能を使うにはSSHサーバ側の設定が必要な可能性があります。AllowTcpForwardingがYesとなり有効になっている事を確認してください。
AllowTcpForwarding yes
1. ローカルポートフォワーディング(-L)
指定したローカルマシンのポートを接続先SSHサーバ(リモート)からアクセス可能なアドレス+ポートにフォワード出来る方法です(待ち受けはローカルマシンのポート)
多分一番使われてるSSHポートフォワーディングかと思います。
用途としては、イントラNW内では有効化しているが、GWにポート開放してインターネット経由でアクセスまでさせたくないサービス((A)リモートデスクトップのポート(3389)、SMBファイル共有のポート、など)を一時的に使うために使ったりします。
コマンド
ssh <SSHサーバアドレス> -L <ローカルの待ち受けポート番号>:<リモートホストから見た転送先IPアドレス>:<転送先ポート番号>
(A)の場合の例
ssh <SSHサーバアドレス> -L 3389:localhost(SSHサーバがRDPサーバも兼ねてる場合):3389
この接続が開始された後ならローカルホストへRDP接続すればRDPサーバへアクセスしてRDPが使える様になります
2. リモートポートフォワーディング(-R)
指定した接続先SSHサーバ(リモート)のポートを、ローカルマシンからアクセス可能なアドレス+ポートにフォワード出来る方法です(待ち受けは接続先SSHサーバのポート)
あまり使われる事は無いかも。
用途としては、NAT配下のローカルNWで且つポート開放設定が不可能なNW(例えば非グローバルIPなモバイルNWなど)に居るホストが提供しているサービス((B)例としてSSH)を、外のSSHサーバを踏み台にしてインターネットからアクセス可能にする等が出来ます。
コマンド
ssh <SSHサーバアドレス> -R <リモートの待ち受けポート番号>:<ローカルホストから見た転送先IPアドレス>:<転送先ポート番号>
(B)の場合の例
ssh <SSHサーバアドレス> -R 20022(リモートホストの20022番を使っていい場合):localhost:22(ローカル側が22番でSSHDを立ち上げてる場合)
またリモートポートフォワードを実行した場合、開けたポート(上記例では20022)はループバックアドレス(127.0.0.1)からのみアクセス可能になります。
他ホストからアクセス可能なようにするには接続先SSHサーバのsshd_confにGatewayPorts yes
を設定する必要があります(デフォルトではGatewayPorts no
となってます)
3.ダイナミックポートフォワーディング(-D)
指定したローカルマシンのポートをSOCKプロキシサーバにする事が出来る方法です。
たぶん一番使われる事はないかも。1.2.でローカル/リモートのフレーズで完結してる感ありますし、
ローカルのポート番号を指定し、リモートからアクセス可能なフォワード先はSOCKプロキシのプロトコルに基づいて動的に切り替わります。
コマンド
ssh <SSHサーバアドレス> -D <ローカルの待ち受けポート番号>
これで割り当てたポート番号はSOCKプロキシと同じになるので、例えばfirefoxのSOCKプロキシに指定するとかできたりします。
4. 起動時にSSH接続を確立したい場合
こんな便利なポートフォワーディング機能なので、OS起動時に自動でSSH接続を確立させたいってニーズもあると思います。
その場合はautosshを利用するのが一般的です。UbuntuやDebianならapt install autossh
でインストールできます。
autosshは可能な限り接続を維持し続けるsshクライアントです。切断された場合も再接続を試みて接続を維持しようとします。
このautosshを使い、公開鍵方式で認証させ(パスワード認証だとインタラクティブにパスワードを入れる必要があるし、セキュリティ的にも良くない)、下記オプションを利用する形でsystemdのサービス化すれば、OS起動時に自動でSSHポートフォワードを張る機能が実現できます。
※ポートフォワーディング利用時によく使われるオプション
-M 9000(ポート番号) : SSH監視の接続性を9000/9000+1のポートで行う、サーバ側クライアント側で2つのポートが利用可能な事が条件
-C : データ転送に圧縮をかける
-N : 接続先でシェルを起動しない、リモートのコマンド実行しないssh接続
-f : ssh接続のバックグランドでの動作
(おまけ) NAT配下の複数デバイスをリモートフォワード機能でSSHログインできるようにする場合の課題
量産された複数のデバイス(IoTデバイスを想定)にSSHで入れるようにする場合、前述の2.リモートフォワーディングを使うことになると思います。その場合下記の様な課題が出るはずなので、それぞれの課題にどう対策するかは考える必要があると思います。
Azuru IoT Hubなどで同じ様な機能が提供されてたりするので、既に何らかのクラウドと連携している場合は類似サービスが利用可能か検討した方が良いかと。
①スケーラビリティ
すべてのデバイスが同じリモートポートを使う設計では最初の1デバイスしかリモートアクセス出来るようになりません。(ポートの取り合い)
その対策としてはリモートポートで使われる可能性のあるポートをある程度のレンジ(例えば100個~)で確保しておき、接続時に予め利用できるポートをネゴする実装(WebAPIなど)があればある程度スケーラビリティは確保できると思います。
②インターネットからのアクセスのリジェクト
リモートフォワーディング時に開けたポートを、他ホストからアクセス可能にする場合(踏み台サーバのsshd_confのGatewayPorts yes
設定)、使いやすさは増す反面セキュリティは低下します(なのでGatewayPortsのデフォルト値はno)
接続デバイスのSSHセキュリティが担保されない場合、そのポートを他ホストやインターネット直接に公開するのは危険です。
他ホストからのアクセスはブロックしておき、デバイスのSSHへ接続する場合も必ず踏み台サーバに1回ログインして、2段階目にデバイスへSSHする方がより安全です。
当然ですが、踏み台のSSHのセキュリティがボトルネックになるので、踏み台SSHサーバのセキュリティは担保する必要があります。
③セキュリティ(踏み台サーバの)
すべてのデバイスがSSHサーバに接続可能なので、もしも悪意あるユーザがIoTデバイスを読み取り接続情報を取得して踏み台サーバへ潜入した場合、踏み台サーバ上で何をするか分かりません
踏み台サーバはSSHサーバのみの機能を持たせたdockerみたいな環境で隔離させて、踏み台サーバを壊されない様にするのが良いと思われます。
そのdocker上で実行可能なコマンドも制限するような権限のユーザにログインさせるなど対策が良いかと思います。
④セキュリティ(ほかの接続デバイスへ入られる懸念)
③に類似していますが、踏み台サーバの仕組みやアクセス手順を知っている悪意あるユーザならば、全く関係のない任意の接続デバイスへログインされる懸念もあると思います。
すべての接続デバイスのログイン手段が同一だと(例えば全部同じユーザ名/パスワードで認証)、このリスクは回避しようがありません。
接続デバイスの認証方法は所有者のみ知れるような仕組みを考える必要があります。