前提
リモートホストのsudoersで
- !requiretty指定不可
- NOPASSWD指定不可
という条件下で、rsyncの--rsync-pathオプションを使ってリモート側をsudoで実行したいという話です。
実現案
試行錯誤の末、以下のスクリプトで一応実現できました。
ただし、一瞬ですがパスワードを含んだファイルがリモートホストに存在しますので、
その瞬間にroot権を持つ別のユーザがそのファイルを読むとパスワードが漏れてしまうという問題があります。
rsync_sudo_with_password.sh
#!/bin/sh
host=${Your_Remote_Host_here}
src=${Your_Source_Directory_Here}
dest=${Your_Destination_Directory_Here}
read_password() {
prompt=${1:-Password:}
stty -echo
read -p "$prompt" password
stty echo
echo "$password"
}
password=`read_password "[sudo] password for $host:"`
ssh ${host} "umask 0077 && cat <<EOF > .password.sh && chmod +x .password.sh
#!/bin/sh
echo $password
EOF"
rsync -avz --rsync-path="SUDO_ASKPASS=.password.sh sudo -A rsync" ${src} ${host}:${dest} &
ssh ${host} rm .password.sh
wait
試行錯誤の経緯
上記のスクリプトに至るまでの試行錯誤の経緯を説明します。
rsyncではなくsshでsudoする場合は、リモートホストに.password.shを作成する必要はなくて、以下のコマンドで可能です。
ssh ${host} "cat <<EOF | sudo -S -p '' whoami
$password
EOF"
しかし、rsyncの--rsync-pathオプションで同じことをしてもうまく動きません。
# No, this does not work!
rsync -avz --rsync-path="cat <<EOF | sudo -S -p '' rsync
$password
EOF
" ${src} ${host}:${dest}
苦肉の策として、冒頭のスクリプトでは以下の手順を用いています。
- パスワードを標準出力に出力するスクリプト.password.shをリモートに作成。
- 他のユーザから見られないようにumask 0077を設定してから作成します。
- echoではなくcatを使っているので、誰かがpsを実行してもパスワードを見られることはありません。
- rsyncの--rsync-pathでは、SUDO_ASKPASS環境変数を指定してsudo -Aを実行する
- rsyncはバックグラウンドで実行して、開始直後にsshで接続して.password.shを削除する。
- waitでrsyncの実行完了を待つ。
改良版
.password.shという固定のファイル名だと狙われやすいので、
pwgenを使ってランダムな名前のディレクトリを生成してその中に.password.shを作成するという方式にしてみたのが以下のバージョンです。
rsync_sudo_with_password.sh
#!/bin/sh
host=${Your_Remote_Host_here}
src=${Your_Source_Directory_Here}
dest=${Your_Destination_Directory_Here}
read_password() {
prompt=${1:-Password:}
stty -echo
read -p "$prompt" password
stty echo
echo "$password"
}
password=`read_password "[sudo] password for $host:"`
random_dir=`pwgen -s 32 1`
ssh ${host} "umask 0077 && mkdir $random_dir && cat <<EOF > $random_dir/.password.sh && chmod +x $random_dir/.password.sh
#!/bin/sh
echo $password
EOF"
rsync -avz --rsync-path="SUDO_ASKPASS=$random_dir/.password.sh sudo -A rsync" ${src} ${host}:${dest} &
ssh ${host} rm -rf $random_dir
wait
OSXではpwgenはHomebrewでインストール可能です。
brew install pwgen
ご意見募集
果たしてこの方式は、十分安全と言えるのかご意見をお聞きしたいところです。さらなる改良案や全く別の解決策もお待ちします。