ITを基礎からやってくブログ

とにかく基礎からやってくんです。基礎が大事なんです。

シェルスクリプト内に書いたsshコマンドの接続先でsshを実行する

ssh接続のテストをシェルでしようと思って考えていたときにわかったこと。

ssh接続のテストというのは、hostAからhostBへのssh接続がうまくいくかどうかのテストという意味で、 これをhostA、hostBとは別のマシンhostLocalから行いたいということ。

hostLocal --(ssh)--> hostA --(ssh)--> hostB

単純に考えると

ssh <UserName>@<IP1> "ssh <UserName>@<IP2> 'date;hostname;id'"

でいけるかな、と思うのだけど、実際には-tオプションが必要。これがないと2つめのsshでエラーになる。

ssh -t <UserName>@<IP1> "ssh <UserName>@<IP2> 'date;hostname;id'"

-tオプションとは何か?

$ man ssh
(中略) -t Force pseudo-tty allocation. This can be used to execute arbi‐ trary 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.

強制的に擬似端末を割り当てるということらしい。
どうやらsshコマンドは末尾に"コマンド"を書く構文の場合、リソース節約のために擬似端末を割り当てない動作をするようだ。
そのため-tオプションで強制的に擬似端末を割り当ててやることで、接続先でのsshもうまく動作する。

以下記事にも解説あり。

sshで多段ログイン - 技術メモ帳

sshで踏み台経由時のショートカット - Qiita

二つめの記事のコメントによると、一般的には多段SSHにはProxyCommandを指定することが多いようだ。
しかしこの場合hostBへの接続でも認証がhostLocalで行われるとのことなので、ssh接続試験がしたいという今回の目的に限っては-tオプションのほうがよい。

パスワード入力をexpectで捌く場合のサンプルスクリプトは以下。
これを応用すれば対象ホストがたくさんあっても自動化できる。
expectのパッケージはローカルにだけ入っていれば動作する。

まあ、各種試験用ツールを使えばもっといい感じにできるとは思うものの。。

#!/bin/bash

IP1="192.168.X.XX"
IP2="192.168.X.YY"

echo -n "Enter Password for $IP1:"
read -s PASS1
echo ""
echo -n "Enter Password for $IP2:"
read -s PASS2
echo ""

expect -c "
set timeout 5
spawn ssh -t root@$IP1 \"ssh root@$IP2 'date;hostname;id'\"
expect \"'s password:\"
send \"$PASS1\n\"
expect \"'s password:\"
send \"$PASS2\n\"
interact
"