2009年10月10日土曜日

多段sshとrsyncでデータの同期

boost.pythonの利用例をメモっておこうと思ったけれど、最近分かったsshのポートフォワーディングの使い方を先にメモしておく。
そういう機能があるのは知っていたものの、せいぜいsecureなrlogin程度の使い方しかしていなかった。しかし最近やはり使ってみたくなった。

元々自宅と職場を行き来する中で、自宅マシンと職場マシンでのデータの共有という問題があったのだが、これまではノートPCを持ち歩き、基本的にそれを媒介とすることで目的を果たしていた。
自宅や職場でそのノートとrsyncで同期をとるという方式だ。
しかし、次第にノートを持ち歩くのが億劫になってきた。
持ち歩き用のノートはB5の小さなものだから、それはメインの作業場ではなく、自宅や職場ではより速く大きなディスプレイのマシンがメインの作業場になっている。そうなると持ち歩き用ノートはもはやデータを運ぶためのものでしかない。
かつては自宅でも職場でも出先でも同じノートをメインにしてた事があり、その頃にはメールでもデータでもノートが母艦で、時々他のディスクやマシンにバックアップを取っていた。しかし、今ではメールも基本的にはweb上に置いてあり、ケータイからも読み書きできる。もうメールやWebチェックのためにPCを持ち歩く時代ではなくなっている。
出張その他どこかへ出掛けるのでない限り、もはやノートPCはデータ同期の媒介としてしか持ち運んでいなかった。
また、その目的ならば、もはやポータブルHDDや、大容量化してきたUSBメモリで充分だ。

ポータブルHDDやUSBメモリでも、やはり一々それらに同期してから持っていき、またそれから同期するのが面倒になってきた。
そこで、自宅と職場のPCの間で直接同期(rsync)したくなった。

自宅マシンから職場マシンへの三段sshでのログイン



ここで問題になるのが、自宅PCから職場PCへのアクセスだ。
もちろん、直接入れるようにはなっていない。
その間に二台のゲートウェイが挟まっている。それらをgw1, gw2とすると

homepc -(the internet) - gw1 - gw2 - workpc

という形だ。homepcは自宅のマンションLANの中でプライベートIPを振られているので外から直接アクセスすることができない。

この状況で、幸い(というか厄介事の種になっている訳だが...)gw1, gw2にもsshでログインする権利が与えられている。
ただし、インターネット側から直接はgw1にしか入れない。gw2に入るにはgw1に入ってそこからまたsshしないといけない。また、gw1からはgw2にしかsshできない。
gw2からはworkpcにsshで入れる。

workpcからは、gw1にもgw2にもsshで直接入る事ができる。ただしその他のポートには入れない。

こういう状況では、
homepc$ ssh gw1
でまずgw1に入り、次いでそこから
gw1$ ssh gw2
でgwに入り、さらにそこから
gw2$ ssh workpc
とすることで、自宅からworkpcに入ることができる。

しかしめんどい。
要するに三段越しのsshをしたいわけだが、少し調べると、こうすることで簡単に実現できることが分かった。

homepc$ ssh -t -Y gw1 ssh -t -Y gw2 ssh -Y workpc

ただし、gw1, gw2, workpcのパスワードはその順番で聞かれる。
(このあたりは設定で入力無しやパスフレーズを使うように変更できるようだが、今のところ面倒なのでノータッチ)

"-t"オプションは擬似端末を強制割り当てするものらしい。正直よく分からないが、これがないと文句を言われてしまう。
"-Y"オプションはtrusted X11 forwardingを有効にするもので、これを付けるとworkpcで実行しているXクライアントをローカルマシンに表示することができる。
ネット越しなのでいくらか遅いが、職場マシンのXクライアントを自宅でそのまま使えるのでとても重宝する。なお、-Yオプションは古いssh(私が使っているのはOpenSSH)ではサポートされていない。(untrustedな-Xオプションはあるようだ)

自宅マシンと職場マシンのrsync(三段ポートフォワーディング)



さて、これで自宅マシンから職場マシンに、間に二台のマシンを狭んでの三段sshで入れるようになった。
しかし目的は自宅マシン(homepc)と職場マシン(workpc)の間でのrsyncによる同期だ。

これにはポートフォワーディング機能を使う。
ネット上でも色々漁ってみたが、三段越しのrsyncというのはあまり見付からず、一段越しの例を参考にしてもなかなかうまくいかなかった。
正直sshの仕組みやオプションがよくわかっていなかった。今もそうだが。

結局、残念ながらコマンド一つではまだ実現できていないが、とりあえず次のようにすることでなんとか実現できた。

まず、三段sshと同じ要領で、ポートフォワーディングを三段繋ぐ。

homepc$ ssh -t -L 10022:localhost:10001 gw1 ssh -t -L 10001:localhost:10002 gw2 ssh -t -L 10002:localhost:22 workpc

これでworkpcにsshログインし、同時にhomepcのポート10022がworkpcのポート22(ssh)に、間の二台、gw1とgw2に中継されながらフォワードされる。
つまり、この状態でhomepcのポート10022に接続すると、それはworkpcのポート22に接続することになる。

この状態でhomepcとworkpcの間でrsyncを行なうには、次のようにする。

homepc$ rsync -avuSHx -e 'ssh -p 10022' /homepc/source/ localhost:/workpc/dest/

これで、homepcの/homepc/source/ディレクトリ以下がworkpcの/workpc/dest/にコピー(同期)される。実際にはいつも--deleteオプションも付けてソースにないファイルはデスティネーションからも削除している。
また、実際に行なう前に必ず--dry-runオプションを付けて削除される予定のファイルをチェックしている。
もちろん、引数の順番を逆にすればworkpcからhomepcにコピーすることもできる。

これで何も持ち歩かなくてもデータの同期を取ることができるようになった。しかもこれまでも、きっとできるだろうと思いながらやっていなかった、自宅で職場PCのXクライアントのウインドウを表示して使うことも可能になった。

というわけで、一応三段ポートフォワーディングの説明をしておくと、上記のフォワーディングでは、まず

ssh -t -L 1022:localhost:10001 gw1

の部分で、gw1にsshでログインし、homepcのポート1022がgw1の10001にフォワードされる。
localhost:10001とは、gw1から見たlocalhostという名前(or IP addr)のマシンのポート10001という意味で、localhostとした場合にはもちろんgw1自身だ。
そして、この後に続く

ssh -t -L 10001:localhost:10002 gw2

の部分でgw2にログインし、このコマンドが実行されるgw1のポート10001がgw2から見たlocalhostのポート10002にフォワードされる。
ここまでで、homepcの10022はgw2の10002にフォワードされたことになる。
そして最後に

ssh -t -L 10002:localhost:22 workpc

だが、これはgw2で実行される。そしてgw2のポート10002をworkpcから見たlocalhost、すなわちworkpc自身のポート22(ssh)にフォワードする。
これで、homepcのポート10022へのアクセスはworkpcのポート22へのアクセスを意味する事になった。
rsyncのオプションの

-e 'ssh -p 10022'

の部分は、rsyncでsshを用いそのsshでは10022ポートを用いよという意味だ。
結局rsyncへのパラメータである

localhost:/workpc/dest/

では、localhostの10022ポートを使うことになり、これはworkpcへのssh接続ということになる。

という訳だが、以上はあれこれ試行錯誤した結果の自分なりの解釈なので、間違いがあるかもしれない。一応自分なりに一貫した解釈ができるようになったので良しとする。

職場マシンからマンションLAN内の自宅PC(プライベートIP)へのsshログイン



さてさて、ここまでで一段落、どうにか目的は達成されたが、なんとなくポートフォワーディングの使い方が分かってくるともう少し欲が出てきた。
職場から自宅PCにアクセスしたい。

自宅はマンション内LANでプライベートアドレスを割り当てられているので、簡単にはそれはできない。ゲートウェイにログインできるわけでもない。
しかし、多分やってみればなんとかなるんだろうなとは思っていた。

で、上記のようにsshで自宅からgw1やgw2にリンクを張れるなら、それを職場PCから辿っていけばなんとかなるだろうと思って試してみると、案外簡単にできてしまった。

"-L"オプションで実現しているのはローカルフォワーディングと呼ばれるらしい。
今度は、homepcからsshでgw1に入り、これまでとは逆にgw1へのアクセスをhomepcにフォワードしたい。こういう方向のものをリモートフォワーディングと呼ぶらしい。

結論から書くと自宅のマシンで

homepc$ ssh -t -g -Y -R 10022:localhost:22 gw1

としておいた上で、職場で

workpc$ ssh -t -Y gw1 ssh -Y -p 10022 localhost

とすることで、目的は達成された。
なお、workpcからはgw1へもgw2へもsshで入ることができる。
もしgw2にしか入れなければ、自宅からはgw2まで継いでおけば良い。

勝手に切断されないようにする



最後に、sshのコネクションは、何もパケットが流れないと5分程度で自動的に切断されてしまうらしい。
これを防ぐのにも色々な方法があるようだが、面倒なのでターミナルの一つで

$ tload -d 100

としてそのまま放置することにした。実際ロードを見たいことは多いし。

結局一切~/.ssh/以下の設定ファイルはいじらなかったが、設定ファイルをいじればコマンドラインを簡略化できるらしい。
しかしコマンドラインで書けるものならそうする方が好きなのでこのまま。
ただしaliasで単純な名前を付けておくので、簡単に実行することができるようにはなっている。


ということで、間に挟まったマシンにsshで入れる事が必要だが、おそらく何段挟まっていてもこの方法で同期や双方向のログインができると思う。

0 件のコメント: