多段 ssh における接続パターン 2 つ
Published: 2023/10/15
多段 ssh とは、中間サーバー(aka 踏み台サーバー)に一度 ssh してから、そこから再度 ssh する行為を指す。
手動で ssh をしている場合には、 ssh をローカルと中間サーバーで2回行えばよいが、何度もアクセスするサーバーである場合には、これをコマンド1発で行いたくなる。
これを実現する方法はおおまかに次の2つのパターンがあり、それぞれの方法について解説する。
- ローカルの ssh クライアントが目的サーバーと ssh のコミュニケーションを取る
- ローカルから中間サーバーに ssh して、中間サーバーの ssh クライアントがさらに目的サーバーと ssh のコミュニケーションを取る
パターン1: ローカルのクライアントが目的サーバーと ssh
「多段 ssh」でググって見つかるのは大体この方法。
SSH Proxy Command に ssh -W を組み合わせることで、手元の ssh クライアントが直接、目的サーバーの sshd と SSH プロトコルで会話できるようになる。
N 段の多段 ssh の場合には、 N 個の ssh 接続(プロセス)が手元で実行される。 具体的には、 N 段目の ssh 接続は、 N-1 段目の ssh 接続に、 N-1 番目のサーバーから N 番目サーバーへの TCP 接続を指示し、その TCP 入出力を N-1番目 ssh プロセス自身の入出力に接続させる。 N-1 番目 ssh プロセスの入出力越しに SSH プロトコルを実行することにより、 N 番目の ssh プロセスは N 番目のサーバーへの ssh を実現する。
ProxyJump での接続も基本的に CLI 上の syntax sugar のため、このパターンでの接続となる。
パターン2: 中間サーバーの ssh を使って目的サーバーへ ssh
$ ssh -t middle-server ssh dest-server
ssh は、オプションではない引数たちを ssh した先のサーバーでそのまま実行する。
その際、 -t
(もしくは、 -tt
) オプションを付与しておくことで、コマンド実行系の ssh ではあるが、 pseudo-terminal の構築を強制できる。
結果として、手動で ssh を2回行った場合と同じ効果が得られる。
N 段化するには、以下のようにする。
$ ssh -t server-1 ssh -t server-2 ... ssh server-N
注意点として、各 ssh コマンドは各中間サーバーにて実行されるため、それぞれの中間サーバーでの ssh 用のオプションやホストの指定を行う必要がある。
また、ローカルの ssh_config はあくまでローカルの ssh プロセスに対するオプション置き場になるため、上記のような長ったらしいコマンドを設定ファイル化することは、一段目の接続を除いて不可能である、というデメリットがある。
補足: 中間サーバーにある鍵を利用して多段 ssh する場合
サーバーの構成ないしその運用のポリシーによっては、中間サーバーからの ssh には、中間サーバーに置いてある鍵を利用しなければならない場合がある。
パターン2の接続を行う場合は、原理的に技術的な問題が発生することは考えにくい。 ただ、コマンドが長いので不便ではある。 コマンドを短くするためにパターン1形式で接続したい場合には、工夫が必要になる。
Host middle-server
ForwardAgent yes
# その他接続オプション
Host target-server
ProxyCommand ssh middle-server 'ssh-add path/to/privkey && nc %h %p'
# その他接続オプション
具体的には、まず手元で ssh-agent を起動する。
中間サーバーへの接続では Agent Forwarding を行う前提で、目的サーバーへの ProxyCommand に、中間サーバー上の鍵を ssh-add
する処理を紛れこませる。
素直な ssh -W の処理ではないので、 ProxyCommand としては ssh-add
と nc
の組み合わせでその要件を果たす。
その設定ないしオプションを行った上で目的サーバーへの ssh を行うと、中間サーバーへの ssh はまず中間サーバーの秘密鍵を手元からフォワードされた ssh-agent に対して ssh-add
してくれるので、 nc
による接続が確立した後に行われる手元 ssh と目的サーバーの SSH 接続においては、中間サーバーにおいてあった鍵が利用できるようになっていて、結果 SSH が成功する。
ローカルのメモリ(ssh-agent)上に中間サーバーの鍵が読み込まれてしまうことにはなるが、普通の ssh-agent であれば、その読み込んだ鍵を勝手に永続化したりなどはしないので、それでもってヨシとするのであれば、この方法でいける。
参考
SSH from A through B to C, using private key on B
I'm looking for a simple way to SSH from my local machine, A, through a proxy, B, to a destination host, C. The private key that goes with the public key on C is on B, and I can't put that key on my
serverfault.com

Tags: ssh
関連記事
Too many authentication failures の原因と対処
2023/8/20
Github における ssh 接続の認証認可の制約とその対処
2022/9/4