著者: | 佐藤裕介 (nuts@cclub.cc.tut.ac.jp) |
---|---|
バージョン: | 2005/11/05 06:30:00 +0900 (JST) |
このテキストでは、 rsync を使ったリモートバックアップ(遠隔バックアッ プ)の方法、特に ssh と cron を利用して、暗号化された経路を経由しての バックアップを自動的に行うための手順を示します。
ここで ssh の認証には、パスフレーズを空にし、かつ実行できるコマンドを 限定した ssh 鍵ペアを作成し使用します。これにより、 ssh-agent や eychain を利用する方法、ホストベース認証を利用する方法よりも安全なバッ クアップ体制が整えられる……はずです。
なお、このドキュメントの内容の正確さについては無保証です。なんせ、備忘 録みたいなものですので……。また、このドキュメントに書かれていることを 実行した結果直接的および間接的に発生した損害について、私(佐藤裕介)は 何ら責任を負いかねます。
バックアップシステムに対して、次のような要求がなされているとします。
追加の要求として、次に挙げるものを想定します。
また、次の条件を『満たせない』場合、このドキュメントの方法は利用できま せん。
次に挙げる内容については省略します。書いてくれる人を募集します。
rsync には ssh と [1] 連携する機能が内蔵されています。
このドキュメントの方法では、この機能を利用してバックアップを行います。 これによって、リモートで rsyncd を動かさないでもバックアップが行えま す。また、 ssh によって暗号化された経路を使い、安全にデータを転送するこ とができます。
また、次の点に注意してくださ。
[1] | 厳密には ssh 以外のリモートシェルプログラム(rsh とか)も使える のですが、実際には ssh を使うことがほとんどのようです。 |
このドキュメントでは、次のような手法を用いてバックアップを行います。
[2] | ホストベース認証よりも上述の方法の方が安全だと判断したためです。 ホストベース認証では、公開鍵に command オプションを指定する ような、秘密鍵を盗まれた場合の被害を低減する方法がありません。 一方、パスフレーズが空の鍵ペアを使う方法では、鍵に from オ プションを付加することで、ホストベース認証と同じような効果(攻 撃にはリモートの名前解決処理に細工が必要)を追加で得ることがで きます。 また、ホストベース認証を行うには、ローカルにある ssh-keysign コマンドが setuid root されていなければなりませ ん。自分が管理者ならいいのですが、そうでない場合はいちいち作業 をお願いしなければならず、面倒です。 |
以下の作業では、バックアップに root アカウントを使う [3] ことを想定し ています。一般ユーザの権限だけで十分だ、という場合は、「root アカウント 向けの準備」の項は飛ばして読んでください。
また、以下の例では次のような環境を想定しています。
ローカルについて:
リモートについて:
[3] | root アカウントと同じファイルの読み書き権限を持ったアカウントを 作成して、そちらを使うという方法も考えられますが、セキュリティ 上の目立った利点は考えられません(rsyncd を動かす場合と異なり、 この方法では chroot ができない)。 |
デフォルトでは、 root アカウントは ssh 経由でのログインが許可されていな いはずです。これはセキュリティの観点から見て妥当であると言えますが、こ のままでは rsync でのバックアップもできません。
攻撃された際の被害を最小限に抑えながら rsync でのバックアップを可能にす るため、「root の ssh ログインでは公開鍵に指定したコマンドライン [4] 実行のみ許す」という設定を /etc/ssh/sshd_config ファイルで行います。
リモートの /etc/ssh/sshd_config の PermitRootLogin (デフォルト値 は no )の値に forced-commands-only を指定してください。
[nuts@remote nuts]$ sudo jvim /etc/ssh/sshd_config Password: : #PermitRootLogin no PermitRootLogin forced-commands-only : [nuts@remote nuts]$
[4] | /root/.ssh/authorized_keys ファイルで command="..." オ プションに指定する。詳しくは後述。 |
次に、バックアップの際に用いる鍵ペアを作成します。まず、ローカルで ssh-keygen コマンドに -N "" を指定して実行し、パスフレーズが空 の ssh2 鍵ペアを作成します。
[nuts@local nuts]$ sudo ssh-keygen -t dsa -N "" -f /root/.ssh/rsync Generating public/private dsa key pair. Your identification has been saved in /root/.ssh/rsync. Your public key has been saved in /root/.ssh/rsync.pub. The key fingerprint is: xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx root@local.example.com [nuts@local nuts]$
これでローカルの /root/.ssh/ に鍵ペア rsync (秘密鍵)、 rsync.pub (公開鍵)ができました。
次に、出来上がった公開鍵をリモートの /root/.ssh/authorized_keys に 追加します。既に存在するものを上書きしてはならず、また root アカウント の ssh 接続は上記のように許可されていないので [5] 、次のようにします。
リモートで:
[nuts@remote nuts]$ mkdir -m 700 tmp [nuts@remote nuts]$
ローカルで:
[nuts@local nuts]$ sudo scp /root/.ssh/rsync.pub nuts@remote.example.com:~/tmp Password: (ローカルのパスワードを入力) Password: (リモートのパスワードを入力) rsync.pub 100% |*****************************| 613 00:00 [nuts@local nuts]$
リモートで:
[nuts@remote nuts]$ sudo sh -c 'cat ~nuts/tmp/rsync.pub >> /root/.ssh/authorized_keys' Password: [nuts@remote nuts]$ rm -rf ~/tmp [nuts@remote nuts]$
[5] | リモートから ssh root@local.example.com 'cat /root/.ssh/rsync.pub' >> /root/.ssh/authorized_keys のように はできない、ということ。一般ユーザであればこっちの方が楽。 |
次に、リモートに転送した公開鍵に command="..." オプションを指定 [6] します。その鍵を使って ssh 接続を行うと、 command="..." 以降に 指定したコマンドが強制的に実行されます。
まず、テストのために /bin/ls を指定してみます。
[nuts@remote nuts]$ sudo jvim /root/.ssh/authorized_keys Password: command="/bin/ls" ssh-dss AAA... : [nuts@remote nuts]$
設定したら、ローカルから接続してみます。
[nuts@local nuts]$ sudo ssh -i /root/.ssh/rsync root@remote.example.com .Xauthority .fonts.cache-1 .k5login .profile ref .bash_history .gnupg .lftp .ssh supfile.ports .cshrc .history .login XF86Config.new tmp Connection to remote.example.com closed. [nuts@local nuts]$
指定通り /bin/ls が実行されて、すぐに接続が切断されればテストは成 功です。
[6] | 詳しくは sshd(8) の "AUTHORIZED_KEYS FILE FORMAT" の項を参 照してください。 |
次に、rsync がリモートで rsync を起動する際のコマンドラインがどのような ものかを調べます。
cron で実行したいコマンドライン [7] に -vv オプションを追加したも のを実行します。次のような感じで失敗するはずです。
[nuts@local backup]$ sudo rsync -vv -az -e "ssh -i /root/.ssh/rsync" \ > /home/backup/ root@remote.example.com:/home/backup/ Password: opening connection using ssh -i /root/.ssh/rsync -l root remote.example.com rsync --server -vvulogDtprz . /home/backup/ protocol version mismatch - is your shell clean? (see the rsync man page for an explanation) rsync error: protocol incompatibility (code 2) at compat.c(69) [nuts@local backup]$
この opening connection using ssh ... の後にある rsync から始 まる部分に注目します。 rsync --server -vvulogDtprz . /home/backup/ です。ここからオプション -vv を取り除いたものを、リモートの /root/.ssh/authorized_keys に指定します。
[nuts@remote nuts]$ sudo jvim /root/.ssh/authorized_keys Password: command="rsync --server -ulogDtprz . /home/backup/" ssh-dss AAA... : [nuts@remote nuts]$
[7] | それを実行すると、パスワードの入力を要求される以外は、自動化し た際と同じようにバックアップが行われるようなコマンドライン。もち ろんローカルで実行します。 |
元々、 rsync は内部で次のような処理を行っているようです。
前節のような公開鍵を使って rsync を実行すると、次のようになるはずです。
では、これが上手くいくか実際にやってみましょう。なお、次のコマンドライ ンに -vv オプションを指定しているのは、ちゃんと通信が行えているかど うかの確認のためです。別になくても構いません。
[nuts@local nuts]$ sudo rsync -vv -az -e "ssh -i /root/.ssh/rsync" /home/backup/ \ > root@remote.example.com:/home/backup/ Password: opening connection using ssh -i /root/.ssh/rsync -l root remote.example.com rsync --server -vvulogDtprz . /home/backup/ : (バックアップしているファイルの名前がずらずらと出力される) : total: matches=0 tag_hits=0 false_alarms=0 data=355683537 wrote 311046900 bytes read 79920 bytes 586478.45 bytes/sec total size is 355683632 speedup is 1.14 [nuts@local nuts]$
あとはリモートに一般ユーザでログインして、実際にバックアップが成功して いるか確認してください。
rsync 用の鍵で、指定した以外のコマンドが実行できたりしないか確認します。
[nuts@local nuts]$ sudo ssh -i /root/.ssh/rsync root@remote.example.com Password: (Ctrl-C) Connection to remote.example.com closed. [nuts@local nuts]$
ログインした後反応がなければ大丈夫です。Ctrl-C をタイプすれば通信が中 断されます。
全て成功しているようなら、これをローカルの root の crontab に指定すれ ば自動化は完了です。 rsync のオプションから -vv を抜くのを忘れずに。
[nuts@local nuts]$ sudo crontab -e Password: : 0 6 * * wed /usr/local/bin/rsync -az -e "ssh -i /root/.ssh/rsync" /home/backu p/ root@remote.example.com:/home/backup/ : [nuts@local nuts]$
authorized_keys ファイルには、 command="" 以外にもセキュリティ を高めるのに使えるオプションがくつか存在します [8] 。例えば、 from="" オプションを指定することで、指定したホスト以外からの接続・ コマンド実行を拒否することができます。
まとめて指定してしまいましょう。各オプションの間にはカンマを入れ、スペー スを入れてはいけません。
[nuts@remote nuts]$ sudo jvim /root/.ssh/authorized_keys Password: command="rsync --server -ulogDtprz . /home/backup/",from="local.example.com",no-p ort-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-dss AAA... [nuts@remote nuts]$
設定したら、バックアップが行えるかどうかの確認を忘れずに。一度リモート のバックアップの一部を削除して、再度 rsync する等すれば確認できるでしょ う。
[8] | 詳しくは sshd(8) の "AUTHORIZED_KEYS FILE FORMAT" の項を参 照してください。 |
次のような攻撃方法(と、それが成功した際の被害)が予想されます。
バックアップの消去
バックアップの改竄
また、rsync 自体にセキュリティホールがあった場合は、これを上回る被害が 出る可能性があることもつけ加えておきます。
ssh を利用した処理を自動化したいという場合、大抵は次のような文章を読む ことになると思います。
「パスフレーズを空にした ssh の鍵ペアを利用する。鍵に command="..." オプションを指定すれば、鍵が盗まれても相手はそこに書かれてることし かできないよ」
これを読んだ私はこう思いました [9] 。
実際、リモートに置いた公開鍵に 1. のようなコマンドを指定して、ローカル でそれとペアの鍵を使って rsync を実行すると、rsync が ssh でリモートに login し、するとさらに rsync が起動して ssh を起動する、という訳の分か らない状態になってしまいます。
[9] | root の crontab に rsync を仕掛けたい、という場合に見るべき文書 が無いんです。ssh では通常 root の login は禁止されていると。 /etc/ssh/sshd_config に PermitRootLogin forced-commands-only と書きなさいと。 cron rsync ssh command authorized_keys forced-commands-only とか、「これは書 いてあるだろう」という単語を並べて Google 先生にお伺いを立てて みても、2ちゃんねるのログとかしか引っ掛かりません。 いろいろ調べて rsync に --server とか --sender とかいう オプションを付けるということが分かったとしても、 rsync(1) にそんなオプションは書いてない、で頭を抱えてしまう。rsync が複 雑なのも原因の一つかもしれません。 |