シェルスクリプトでリモート先にコマンドを実行する際のTips

仕事でとあるサーバーから別のサーバーにあるシェルスクリプトをsudo付きで実行したいことがあった。
そして、

$ ssh USER@hostname sudo shellscript
sudo: sudo を実行するには tty がなければいけません。すみません

見事にこのようなエラーが出て、実行ができなかった。
シェルスクリプト&sudoの超あるある案件だ。
これをググると対応方法の中に、sudoersファイルの”Defaults requiretty”をコメントアウトすると良いと書かれている。
どのサイトにもこれはセキュリティ上よくないから!と書かれているが、それをやってる。
確かにvisudoで見てみると、

#
# Disable "ssh hostname sudo <cmd>", because it will show the password in clear.
#         You have to run "ssh -t hostname sudo <cmd>".
#

と書かれている。
ここにはパスワードがクリアで表示されてしまうからダメだと書かれている。
ログインシェルを実行してttyを割当ないと、パスワードをecho offできないからダメらしい。

確かにこちらにもLinuxのシステムコールioctl()で、パスワードのechoをoffにしていることが書かれていた。

http://d.hatena.ne.jp/itotto/20120214/1329191401

なるほどという感じ。そのため、パスワードを表示させないように-tオプションで仮想的に端末を割り当てるように書かれている。

検証

失敗パターン

ssh user01@vagrant.local sudo ls -l
user01@vagrant.local's password:
sudo: sudo を実行するには tty がなければいけません。すみません

成功パターン

ssh user01@vagrant.local -t sudo ls -l
user01@vagrant.local's password:
user01@vagrant.local's password:
[sudo] password for user01:
合計 117580
drwx------ 7 user01 user01      4096  1月  3 00:39 2016 Maildir
-rw-r--r-- 1 user01 user01 117764308 11月 10 18:09 2014 archive.zip

調べている際に下記サイトを見つけたのだけど、わかりやすく書かれていてためになった。

http://language-and-engineering.hatenablog.jp/entry/20110617/p1

そして他にも色々出来そうだということ、対処方法などが見つかったのでTipsとして書いておく。

パスワードを変数に入れてシェルスクリプトで使用する

http://keens.github.io/blog/2015/06/17/shell_scriptwokakutokinikiwotsuketaikoto/

こちらのサイトに記載があったのだけど、readコマンドのオプション-sで入力文字を表示させないようにできるらしい。
これが便利そうに思った。

echo -n "Type your password: "
read -s SSHPASS

これで”Type your password:”の後にパスワードを入力させるプロンプトが出せる。
read で標準入力から SSHPASS へパスワードをセットする。
read -s にするとパスワードが表示されないので、パスワード入力用のプロンプトとして使用できる。
下記では例としてecho “パスワード”と記載しているけれど、基本的には入力させるようにした方が良いと思う。

sshpassでパスワードをワンライナーで読み込む

パスワードを標準入力でsshに渡せるようなのだけど、その際にsshpassコマンドを使用するようだ。

$ sshpass -pパスワード | ssh ユーザー@ホスト名 ls -l

sshpassについて、CentOSでepelがあれば下記でインストール可能だ。
-fでファイルから読み込むこともできるようだ。

$ sudo yum install sshpass

epelはyumの標準レポジトリで追加できる拡張パッケージなので下記でインストールできる。

$ sudo yum install epel-release

標準入力からパスワードをsudoに渡す

標準入力からsudoにもパスワードを渡すことができる。それにはsudo -Sとするとよい。

$ echo "パスワード" | ssh hoge sudo -S cat /var/log/message

複数のコマンドをリモート先で実行する(sudoが必要なパスワードを標準入力で渡す)

もっと良い書き方がありそうだけど、こんな感じでヒアドキュメントで、SSHPASSの変数にセットしたパスワードを読み込ませてリモートでsudoを実行できる。
-tだけで実行できれば問題ないのだけど、SSHした先で更にSSHさせるような場合は-ttを使用しないと怒られる。

$ ssh hoge@hogepiyo.com -tt << EOL
 echo "${SSHPASS}" | sudo -S コマンド1
 echo "${SSHPASS}" | sudo -S コマンド2
 echo "${SSHPASS}" | sudo -S コマンド3
EOL

sudoでrootのHOMEの環境変数を読み込む

sudo -H を使用すると、rootのHOMEの環境変数を読み込んでくれる。

$ ssh hoge@hogepiyo.com sudo -H mysqladmin ping

http://perezvon.hatenablog.com/entry/20091115/1258269745

注意点

但し、注意点として、これらの方法で完璧にパスワードを隠蔽できるわけではなく、sh -xとかpsとかするとパスワードが表示されてしまう。
sttyを使って、echoをoffにしたりする方法もあるようだけど、結果的には同じことで、ASKPASSプログラムを実行できるプログラムの方が望ましいらしい。
特にexpectなどが良いらしいので、不安がある場合はexpectで実行するのが良いと思う。
上記Tipsを使用する場合は、留意していただきたい。

こんな感じでなんとかオプションを駆使すれば、リモート先でsudoでコマンドを実行できるし、更にシェルスクリプトを実行することも可能だということが分かった。
また、長いことモヤモヤしていた所ではあったので、何故ダメなのかって所が分かってよかった。