ssh接続を経由してdiffを行う

先日、ちょっと仕事の関係で各サーバの設定ファイルの差異を確認することがあったのだが、その際にできないかな?と思って調べていた。
どうやら出来るようなので、3パターン紹介させてもらう。

1.普通のパスワード認証方式の場合

普通のパスワード認証方式の場合、以下のようにコマンドを実行する。

ssh ユーザ名@ホスト名 "cat リモート側のファイルパス" | diff - ローカル側のファイルパス
$ ssh root@192.168.0.20X "cat /etc/ssh/sshd_config" | diff - /etc/ssh/sshd_config
root@192.168.0.20X's password:
1c1
< #     $OpenBSD: sshd_config,v 1.90 2013/05/16 04:09:14 dtucker Exp $ --- > #     $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $
…

このように、ローカルとリモート間のdiffであれば、特に設定も何も必要なくdiffを行う事が可能となっている。
しかし、どうやらこの方法ではリモートとリモートの間でのdiffは難しいようだ。

というのが、この方法だとsshコマンドからの標準出力の内容をdiffで受け付けて確認を行っているため、もう一つ標準出力の内容を受け付けるにはパイプではなく、「<(コマンドの内容)」というような書き方をする必要がある。しかし、このやり方だとパスワードの入力を受付ずに処理が進んでしまう。このため、リモートとリモートの間でdiffを行う場合、後述する方法を使うか、一度ファイルをローカルに落とす必要がある。

2.鍵認証方式の場合

鍵認証方式の場合、以下のようにすることでssh接続経由でdiffを行う事が可能だ。

diff <(ssh ユーザ名@ホスト名 'cat リモート側のファイルパス') ローカル側のファイルパス
$ diff <(ssh root@192.168.0.20X "cat /etc/ssh/sshd_config") /etc/ssh/sshd_config
1c1,2
< #     $OpenBSD: sshd_config,v 1.90 2013/05/16 04:09:14 dtucker Exp $ --- > # Package generated configuration file
…

なお、鍵認証方式であればリモートとリモート間でのdiffも実行可能だ。

diff <(ssh ユーザ名@ホスト名① 'cat リモート側のファイルパス') <(ssh ユーザ名@ホスト名② 'cat リモート側のファイルパス')
$ diff <(ssh root@192.168.0.20X "cat /etc/ssh/sshd_config") <(ssh root@192.168.0.2XX "cat /etc/ssh/sshd_config")
1c1
< #     $OpenBSD: sshd_config,v 1.90 2013/05/16 04:09:14 dtucker Exp $ --- > #     $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $
6c6
…

3.diffの実行機器にsshpassが入っている場合

diffを実行するマシンにsshpassが入っているようであれば、それを用いるとよいだろう。

diff <(sshpass ホスト名①のパスワード ssh ユーザ名@ホスト名① 'cat リモート側のファイルパス') <(sshpass ホスト名②のパスワード ssh ユーザ名@ホスト名② 'cat リモート側のファイルパス')
$ diff <(sshpass -p XXXXXXXX ssh root@192.168.0.20X cat /etc/ssh/sshd_config) <(sshpass -p XXXXXXX ssh root@192.168.0.2XX cat /etc/ssh/sshd_config)
1c1
< #     $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $ --- > #     $OpenBSD: sshd_config,v 1.90 2013/05/16 04:09:14 dtucker Exp $
6c6