2009/05/22(Fri)2段ssh

2009/05/22 1:28 Software::Linux
最近ではネットワークの隠蔽性を高めるため、インターネットから直接リーチャブルでない(到達できない)場所にSSHサーバーがいることもある。
ここに対してsshセッションを外側張りたい場合、基本的には、インターネットからリーチャブルなゲートウェイの働きをするsshdを通して、その中でさらにssh、つまり2段sshをやるわけだが、sshコマンドを2回も打つのがめんどくさい。どうにか1コマンドで済まないものか。

ssh hostname [command]

ご存じない人もいるかも知れないが、sshコマンドには、ホスト名の後にコマンドを指定すると、ログインした後対話シェルに入らず、コマンドの結果だけを表示して終了する仕様である。
manを引くと
NAME
     ssh - OpenSSH SSH client (remote login program)

SYNOPSIS
     ssh [-1246AaCfgKkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec] [-D  [bind_address:]port] [-e escape_char] [-F configfile]
         [-i identity_file] [-L  [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
         [-R  [bind_address:]port:host:hostport] [-S ctl_path] [-w local_tun[:remote_tun]] [bf:{[user@]hostname [command]}]
というように、最後にcommandがoptionalながら指定できる。
例えば、$ ssh username@example.com cat /proc/cpuinfoのようにうつと、リモートのCPUの情報が表示された後、現在のシェルに戻ってくる。

では単純に…??

例として、
gateway.example.com
インターネットから自由にアクセスできるゲートウェイサーバー
remote.example.com
NATの内側にいる目的のリモートサーバー
そして、これら2つのサーバーは信頼できるものであり、localhost -> gatewayと、gateway -> remoteの間はパスフレーズなしのssh鍵認証設定がされているものとする。


では単純に$ ssh gateway.example.com ssh remote.example.comとすればよいかというと、これがそううまくはいかない。
何故なら、先ほど説明したように、$ ssh hostname [command]の形式は対話シェルを原則許可していないからである。
このようなコマンドを打った場合、次のように表示されて、プロンプトは現れない。
$ ssh gateway.example.com ssh remote.example.com
Pseudo-terminal will not be allocated because stdin is not a terminal.

解決策

sshのオプションにある-tオプションを用いる。manをみると、
-t

Force pseudo-tty allocation.  This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services.  Multiple -t options force tty allocation, even if ssh has no local tty.
'pseudo'(シュード)というのは、見せかけの/擬似的という意味で、execute screen-based programs on a remote machine、つまり、シェルのようなスクリーンを占有するアプリケーションを起動できるようになるというわけである。


つまり、$ ssh -t gateway.example.com ssh remote.example.comとすればよい。
毎度打つのは面倒なので、シェルスクリプトにしてもよいし、もっと横着したければ私のように.bashrcにaliasを書いてもよい。
$ echo alias remote=\'ssh -t gateway.example.com ssh remote.example.com\' >> ~/.bashrc
$ source ~/.bashrc
繋ぎに行きたいときは、
[user@local]$ remote
[user@remote]$ 
こんな感じ。

応用例

もちろん、これを応用して$ ssh -t gateway1 ssh -t gateway2 ssh remoteのようにすれば、何段でもsshを跨げるだろう。