LoginSignup
21

More than 5 years have passed since last update.

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

Posted at

前提

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

ご意見募集

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21