sshトンネルが必要になるたびに使い方を忘れてて、引数はどうだったっけ?ってなるので基本形をメモ。覚えてれば簡単なんだけど、あやふやだと踏み台サーバのIPアドレスやポート、ファイアウォールのポートなどがごっちゃになったりして毎回面倒なので簡単に思い出せるようにメモしとく。
- sshトンネル、sshポートフォワーディングとは
- 使用するターミナル
- sshトンネルを掘る時の基本形
- 踏み台サーバを経由してターゲットにsshでログインする
- 踏み台サーバを経由してターゲットのMySQLにアクセスする
- sshポートしか解放されていないネットワーク内の様々なサービスにアクセスする
- 外部にアクセスできるポートが制限されている場合の応用
- 今時のsshの定義方法
sshトンネル、sshポートフォワーディングとは
今更だけど、sshトンネルは遠隔地にあるマシンのポートをローカルマシンのポートに割り当ててセキュアな通信経路をつくること。ローカルからは直接アクセスできないマシンにアクセスができるようにする目的で用いる(事が多い)。
sshポートフォワーディングは手段の呼び名で、sshトンネルはその手段を使ってセキュアな通信経路を作ること。なので「セキュアなトンネルを作ろう!」「実現のためにsshポートフォワーディングを使おう!」ということ(だと思ってる)。多分、下記のSMOOZさんの解説が正しいと思う。
以下、sshトンネルでポートに割り当てて通信経路を確立することを「トンネルを掘る」と表現する。
手順は以下の2ステップになる。
- トンネルを掘る
- 使いたいサービスにアクセスする
使用するターミナル
windowsでトンネルを掘る場合、teraterm等いろいろなツールが使えるけど、最近はmobaXtermを使うことが多い。mobaXtermだとlinuxと同じコマンドで実行できる。あまり使うことは無いけどWindows10以降のコマンドプロンプトでも同じコマンドで実行できた。
sshトンネルを掘る時の基本形
引数は以下の2つのパートに分かれてることを認識しておくと扱いやすい気がする。
- アクセスしたいターゲットマシンのポートをローカルマシンのポートに割り当てる
- 踏み台サーバにアクセス(ログイン)する
ssh -L [ローカルのポート]:[ターゲットのIP]:[ターゲットのポート] \
-l [踏み台のユーザID] [リモートのドメインorグローバルIP] -p [踏み台のsshポート]
緑の部分がターゲットのポートをローカルマシンのポートに割り当てるための部分。
青の部分が踏み台サーバへのアクセス(ログイン)するための部分。
sshはパスワード、または暗号鍵を使った方法で接続できる。上記はパスワードを使って接続する方法で、ターゲット、及び踏み台に暗号鍵を使う場合は以下の様になる。
ssh -i [ターゲットの秘密鍵ファイル] \ -L [ローカルのポート]:[ターゲットのIP]:[ターゲットのポート] \ -l [踏み台のユーザID] [リモートのドメインorグローバルIP] -p [踏み台のsshポート] \
-i [踏み台の公開鍵ファイル]
1行目の薄緑の部分でターゲットにアクセスするために使う秘密鍵、4行目の薄水色の部分で踏み台にアクセスするために使う公開鍵を指定する。
会社のネットワークだったりレンタルサーバのサービスだったりすると、踏み台サーバに秘密鍵をセットして、その鍵とペアになる公開鍵を(多数の)ユーザに配布してアクセスできるようにしてあることが多い。ターゲットマシンは誰が責任者になるかによるけど、レンタルサーバだったりすると、借りてるユーザが責任者になるので秘密鍵を持ってる人以外はアクセスできなくしてセキュリティを担保することが多くて、ターゲットには公開鍵、アクセスするときにはそのペアになる(限定された人だけが持つ)秘密鍵を使って接続する。とは言え、どっちに秘密鍵を置くかはシステムのポリシーによって異なることがある。本記事では暗号キーの実例は割愛する。
この2つの書き方を覚えておくと、リモート先にあるサーバの様々なサービス(apacheやMySQL等)をあたかもローカルに存在するかのように扱えるようになる。
踏み台サーバを経由してターゲットにsshでログインする
ネットワーク構成
よくある踏み台を経由して、ネットワークの内部(踏み台サーバの奥に)にあるサーバにsshでログインするパターン。
以下のようなネットワーク構成になっていると想定した例を示す。
図のリモート側の構成のポイントは以下の通り。
- ファイアウォール(ルータ等)で外部からのポート40022へのアクセスを踏み台サーバのポート22に転送(いわゆるポート開放されてる状態)
- 踏み台サーバの向こう側にログインしたいLinuxサーバがある
トンネルを掘る
図の黄色い矢印のイメージで、リモート側のLinuxサーバ(ターゲット)のポート22をローカルマシンのポート30022に接続する(割り当てる)。
図の例だとトンネルを掘る引数は以下のようになる。
ssh -L 30022:192.168.20.11:22 -l user_jump hogehoge.com -p 40022
- user_jump:踏み台サーバのユーザID
- hogehoge.com:リモートのドメイン名(グローバルIPでも可)
これで、ローカルのポート30022にアクセスすると、図の緑の矢印のようにあたかもリモート先のLinuxサーバのsshにアクセスしているかのように使えるようになる。
アクセスする
上記のトンネルを掘ったターミナルは踏み台にログインした状態になるのでそのままにしておき、別のターミナルを使って下記の引数でsshを実行するとLinuxサーバにログインできる。
ssh user_server@localhost -p 30022
- user_server:LinuxマシンのユーザID
踏み台サーバを経由してターゲットのMySQLにアクセスする
ネットワーク構成
ターゲットマシンの様々なサービスにアクセスできる例として、リモートのMySQLにローカルのWindowsマシンのDBeavewrからアクセスする例を示す。
Linuxサーバのポートが変わるだけでその他はsshでログインするケースと変わりない。変わるのは赤字の部分のみ。
MySQLはLinuxサーバのポート3306で動いている。黄色い矢印のイメージで、ポート3306をローカルのポート33306に接続する。ルータや踏み台は変わりなく、ルータは踏み台用のポート22を外部ポート40022で解放している状態。このポートが解放されていればLinuxマシンのどんなポートでもトンネルを掘れるとこがミソ。
トンネルを掘る
図の例だとトンネルを掘る引数は以下のようになり、sshでログインする場合と赤字の部分が変わるだけ。
ssh -L 33306:192.168.20.11:3306 -l user_jump hogehoge.com -p 40022
アクセスする
トンネルが掘れたら、DBeaverの接続設定でServer hostをlocalhost、Portを33306にすると接続できる。
sshポートしか解放されていないネットワーク内の様々なサービスにアクセスする
ネットワーク構成
踏み台は存在しないけど、リモートのポートがsshしか解放されていない場合にsshのポートを利用してトンネルを掘ることで踏み台がある時と同じ考え方でssh以外のサービスにアクセスできる。
まずは、MySQLにアクセスする例。
リモートのルータは外部からのsshのアクセス(ポート40022)をLinuxサーバのssh(ポート22)に転送するようになってる。
トンネルを掘る
トンネルのやり方はMySQLにアクセスする方法と同じで赤字の部分が変わるだけ。
ssh -L 33306:192.168.20.11:3306 -l user_target hogehoge.com -p 40022
なぜこうなるかと言うと、踏み台のsshサーバを使っていたのをLinuxマシンにのsshサーバに変えるだけなので、結果的にユーザIDをLinuxマシンのユーザIDに変えるだけになる。
アクセスする
これでDBeaber等のクライアントで、ローカルのポート33306からMySQLにアクセスできる。
その他の例
次の例は、Linuxマシンのポート80でapacheが動いていたらポート番号を変えて
ssh -L 30080:192.168.20.11:80 -l user_target hogehoge.com -p 40022
とすると、下記のURLでブラウザからアクセスできるようになる。
このように、踏み台があっても無くてもsshのポートが解放されてればあらゆるサービスのトンネルを掘ることができる。
外部にアクセスできるポートが制限されている場合の応用
これまではリモート先の入り口の制限がきつい場合の話しで、ここからは逆にローカロの出口が制限されてる場合の話し。
職場等で外部にアクセスできる(外部に出ることができる)ポートが制限されていて、HTTPのポート80、HTTPSの442くらいしか外部にアクセスできないケースも多い。そんな時も外部に出られるポートが1つでもあればなんとかできることがある。
例えば、HTTPSのポート442を使って自宅のMySQLにアクセスする場合、自宅のルータの設定でポート442へのアクセスをLinuxサーバのポート22に転送できればなんとかなることもある。
但し、HTTP、HTTPSのポートを使う場合は以下の問題がある。
- 多くの場合、ファイアウォールのWebアクセスの制限にかかって遮断される
- 自宅のHTTP、HTTPSの公開ポートを変えなければならなくなる
- 管理者から変なことに使うなと怒られる
等により、HTTP、HTTPSのポートを使うことは現実的ではないので、他に使えるポートを探す必要がある。例えば外部のクラウドサービスにアクセスするためのポート等。但し、他の用途に利用する場合は職場のセキュリティポリシーに反しないことを確認の上で。
今時のsshの定義方法
今時はワンライナーで書くより、~/.ssh/configに定義して使う方がトレンドみたい。使ったことなかったんだけど試してみたら踏み台の奥にあるMySQLにトンネルが掘れた。
Host JUMP_HOST # 踏み台サーバ HostName hogehoge.com
Port 30022 User user_jump LocalForward 33306 localhost:33306 Host TARGET_HOST # Linuxサーバ HostName 192.168.20.11 User user_target LocalForward 33306 localhost:3306 ProxyCommand ssh -CW %h:%p STEP_HOST
上記の定義をしておくと、下記のコマンドでターゲットのsshにログインできる。
ssh TARGET_HOST
接続の実行時の様子はこんな感じ。コマンド実行後、踏み台のパスワード、Linuxサーバのパスワードを聞いてくる。
$ ssh TARGET_HOST stty: standard input: Inappropriate ioctl for device user_jump@hogehoge.com's password: user_server@192.168.20.11's password: Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 6.5.0-14-generic x86_64) Last login: Wed Jun 19 13:58:18 2024 from 192.168.20.11 kirin@cf-n10:~$
この方法は、一回定義しとけば実行が簡単で、ターミナルも1つでできるのでとても良いと思う。でも、この書き方はあまり良く分かってないので今後調べていこう。