Posted at

パスワードありsudoでrsyncするシェルスクリプト

More than 5 years have passed since last update.


前提

リモートホストの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


ご意見募集

果たしてこの方式は、十分安全と言えるのかご意見をお聞きしたいところです。さらなる改良案や全く別の解決策もお待ちします。