rsync + cron + ssh でセキュアな自動リモートバックアップ (2006/11/21)

現時点でできる限りのセキュリティを考慮に入れた自動リモートバックアップシステムを rsync + cron + ssh で作成してみました.各条件は,次のものとします.

[local.jp, local]
  バックアップしたいディレクトリ.
    /etc       : 設定ファイル等.
    /home      : NFSで提供しているユーザデータ.
    /usr/local : NFS共有データ.
  バックアップしたくないディレクトリ.
    /home/data : あまり重要でないデータなどが膨大.
[remote.jp, remote]
  バックアップ用のディレクトリは /backup.

local, remote共に同じLAN上にいるものとします.セキュアなリモートバックアップのために,sshの公開鍵認証,暗号化通信を用います.もちろんremoteでNFSマウントしたものに対して,バックアップを行ってもよいのですが,NFSマウントしたディレクトリに対してremoteのrootでもroot権限を与えなくてはならない欠点があります.そこで,sshを利用することにしました.

rootアカウント用のsshのRSA秘密鍵,公開鍵をlocal上で作成します.

local# ssh-keygen -t rsa -N "" -f /root/.ssh/rsync

local上では,秘密鍵/root/.ssh/rsyncと公開鍵/root/.ssh/rsync.pubが作成されます.

一方,remoteでは,rootでのsshでのアクセスをコマンド限定で許可します.そして,sshデーモンを再起動させます.

remote# vi /etc/ssh/sshd_config
...
#PermitRootLogin no
PermitRootLogin forced-commands-only
...
remote# /etc/init.d/ssh restart

local上で作成した公開鍵をremote上に持ってきて,/root/.ssh/rsync.pubにコピーします.この公開鍵を/root/.ssh/authorized_keysに追加します.

remote# cat /root/.ssh/rsync.pub >> /root/.ssh/authorized_keys

公開鍵には,コマンドを指定する必要があります.このコマンドを次のようにして調べます.-vvオプションは,デバッキング用のオプションです.この時点では,エラーで終了するはずです.

local# rsync -vv -az -e "ssh -i /root/.ssh/rsync" \
 /etc root@remote:/backup/
opening connection using ssh -i /root/.ssh/rsync -l root \
 remote rsync --server -vvlogDtprze.iLs . /backup/
...

この結果より,ssh のコマンドで指定するべきは"vv"を除いた"rsync --server -logDtprze.iLs . /backup/"ということが分かります.(追記 2008/10/20) "-logDtprz"から"-logDtprze.iLs"に修正しました.

実はこの部分は気にいらない点の一つです.一度実行してみないとコマンドが分からないし,rsyncのこの仕様が今後維持されるかどうか分からないためです.

調べたコマンドauthorized_keysに追加します.また,アクセスをlocal.jpに制限します.その他いろいろのオプションを追加します.このオプションの詳細は,sshのmanのAUTHORIZED_KEYS FILE FORMATで確認できます.各オプションの間にはカンマを入れ,カンマの間にはスペースを入れません.

remote# vi /root/.ssh/authorized_keys
command="rsync --server -logDtprze.iLs . /backup/",\
 from="local.jp",no-port-forwarding,no-X11-forwarding,\
 no-agent-forwarding,no-pty ssh-rsa \
...

以上の操作を持って,実際に転送できるかどうかを確かめます.

local# rsync -az -e "ssh -i /root/.ssh/rsync" \
 /etc root@remote:/backup/
...
local# rsync -az -e "ssh -i /root/.ssh/rsync" \
 /usr/local root@remote:/backup/
...
local# rsync -az --exclude="/home/data" \
 -e "ssh -i /root/.ssh/rsync" \
 /home root@remote:/backup/
...

ここで,--exlude="/home/data"がきちんと動作するかどうかが心配だったのですが,転送元の処理であるため,きちんと動作するようです.これで,それぞれのバックアップディレクトリ/backup/etc, /backup/local, /backup/homeができます.最初は,/backup/usr/localとしたかったのですが,別のRSA秘密鍵と公開鍵のペアを作成しないといけないので,あきらめました.

なお,rsync用の秘密鍵でrootで遠隔ログインができないかどうか確かめておきましょう.

一ヶ月に一度は,転送元にないファイルを消す,すなわち,転送元と転送先を完全に一致させるrsyncの--deleteオプションを使いたいと思いました.しかし,

local# rsync -az --delete -e "ssh -i /root/.ssh/rsync" \
 /etc root@remote:/backup/
 ...
としても,コマンドプロンプトが返ってきません.そこで,
local# rsync -vv -az --delete -e "ssh -i /root/.ssh/rsync" \
 /etc root@remote:/backup/
opening connection using ssh -i /root/.ssh/rsync -l root \
 remote rsync --server -vvlogDtprze.iLs --delete . /backup/
 ...
で確かめると,sshで実行されるコマンドに--deleteを加える必要があります.そこで,--delete用のRSA秘密鍵と公開鍵を作るところから始めます.

local# ssh-keygen -t rsa -N "" -f /root/.ssh/rsync-delete
...
remote# cat /root/.ssh/rsync-delete.pub \
 >> /root/.ssh/authorized_keys
remote# vi /root/.ssh/authorized_keys
...
command="rsync --server -logDtprze.iLs --delete . /backup/",\
 from="local.jp",no-port-forwarding,no-X11-forwarding,\
 no-agent-forwarding,no-pty ssh-rsa \
...

これで,--deleteオプションも秘密鍵rsync-deleteを利用すれば可能になりました.ここで,次のようにバックアップ用のスクリプトの作成をしました.

local# cat $SCRIPTDIR/backup.sh
#!/bin/sh
# auto-backup script using rsync
PATH=/usr/bin:/usr/sbin:/bin:/sbin

if [ `date +%d` = "01" ] ; then
  rsync -az --delete -e "ssh -i /root/.ssh/rsync-delete" \
    /etc root@remote:/backup/
  rsync -az --delete --exclude="/home/data" \
    -e "ssh -i /root/.ssh/rsync-delete" /home root@remote:/backup/
  rsync -az --delete -e "ssh -i /root/.ssh/rsync-delete" \
    /usr/local root@remote:/backup/
elif [ `date +%w` = "1" ] ; then
  rsync -az -e "ssh -i /root/.ssh/rsync" /etc root@remote:/backup/
  rsync -az --exclude="/home/data" \
    -e "ssh -i /root/.ssh/rsync" /home root@remote:/backup/
  rsync -az -e "ssh -i /root/.ssh/rsync" /usr/local root@remote:/backup/
elif [ `date +%w` = "3" -o `date +%w` = "5" ] ; then
  rsync -az --exclude="/home/data" \
    -e "ssh -i /root/.ssh/rsync" /home root@remote:/backup/
  rsync -az -e "ssh -i /root/.ssh/rsync" /usr/local root@remote:/backup/
fi

月の始めに転送元と転送先のディレクトリを一致させます.月曜日に/etc, /home, /usr/localに関して更新があったものをバックアップします.水曜日と金曜日に,/home, /usr/localに関して更新があったものをバックアップします.これを,localの/etc/cron.daily/からシンボリックリンクを張ります.

local# cd /etc/cron.daily
local# ln -s $SCRIPTDIR/backup.sh backup

確か/etc/cron.daily/のファイル名にドットを含むものは実行されなかったので,注意しましょう.

しかし,この方法はこれからも利用できるかどうかが不安です.結局,同じLAN上にあることもありeSATAの外付けHDDでバックアップする予定です.


梅原 大祐 / UMEHARA Daisuke umehara@kit.ac.jp
Last modified: Thu Jun 23 02:15:06 JST 2011
Total Access Count