多段 ssh における接続パターン 2 つ

Published: 2023/10/15


多段 ssh とは、中間サーバー(aka 踏み台サーバー)に一度 ssh してから、そこから再度 ssh する行為を指す。

手動で ssh をしている場合には、 ssh をローカルと中間サーバーで2回行えばよいが、何度もアクセスするサーバーである場合には、これをコマンド1発で行いたくなる。

これを実現する方法はおおまかに次の2つのパターンがあり、それぞれの方法について解説する。

  1. ローカルの ssh クライアントが目的サーバーと ssh のコミュニケーションを取る
  2. ローカルから中間サーバーに ssh して、中間サーバーの ssh クライアントがさらに目的サーバーと ssh のコミュニケーションを取る

パターン1: ローカルのクライアントが目的サーバーと ssh

「多段 ssh」でググって見つかるのは大体この方法。

SSH Proxy Commandssh -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-addnc の組み合わせでその要件を果たす。 その設定ないしオプションを行った上で目的サーバーへの ssh を行うと、中間サーバーへの ssh はまず中間サーバーの秘密鍵を手元からフォワードされた ssh-agent に対して ssh-add してくれるので、 nc による接続が確立した後に行われる手元 ssh と目的サーバーの SSH 接続においては、中間サーバーにおいてあった鍵が利用できるようになっていて、結果 SSH が成功する。

ローカルのメモリ(ssh-agent)上に中間サーバーの鍵が読み込まれてしまうことにはなるが、普通の ssh-agent であれば、その読み込んだ鍵を勝手に永続化したりなどはしないので、それでもってヨシとするのであれば、この方法でいける。

参考


Tags: ssh

関連記事