仕事でとあるサーバーから別のサーバーにあるシェルスクリプトを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でコマンドを実行できるし、更にシェルスクリプトを実行することも可能だということが分かった。
また、長いことモヤモヤしていた所ではあったので、何故ダメなのかって所が分かってよかった。