実践で学ぶ、一歩進んだサーバ構築・運用術

第 11 回 ssh (後編)


他のコマンドと ssh の組み合わせ

ssh は rsh と置き換え可能ですから, rsh と組み合わせて使うコマンドは当然 ssh と組み合わせて使うこともできます。 ssh を /usr/bin/rsh とは別にインストールして, ssh と rsh を使い分けることもできますが, ssh 接続に失敗したとき自動的に rsh へ切り替える機能*12 を ssh は持っていますから, ssh を /usr/bin/rsh としてインストールして 完全に置き換えてしまう方がお勧めです。

こうすると, 内部で rsh を呼び出す rdist や rsync コマンドなどでも, 意識せずに ssh を利用できます。

tar

昔,cp コマンドには,-a オプションがありませんでした。 シンボリック・リンクなどを含むディレクトリをそのままコピーするには, cp コマンドではなく tar コマンドなど*13 を使って, 図 15 などのようにコピーするのが普通でした*14


tar cf - dir | (cd /some/where/.; tar xpf -)
図 15 tar コマンドを使ってディレクトリごとコピー

tar コマンドを使うこの方法の良いところは, これをそのままリモート・ホストへのディレクトリ・コピーで 応用できる点です(図 16)。


tar cf - dir | rsh remotehost "cd /some/where/.; tar xpf -"
図 16 tar コマンドを使ってリモート・ホストへディレクトリをコピー

ssh を /usr/bin/rsh にインストールしている場合は, 図 16 の手順のままで ssh を使ったリモート・ホストへディレクトリをコピーできます。 ssh を rsh とは別にインストールしている場合でも, 図 16 の「rsh」を「ssh」に置き換えるだけで済みます。

rdist

rdist コマンドも ディレクトリをリモート・ホストへコピーするためのコマンドですが, リモートとローカルのディレクトリを比較して, 異なる部分だけを転送する点が tar と異なります。 2 つのマシンの特定のディレクトリの内容を同一に保ちたいときなど, 毎回ディレクトリ全体をコピーするのでなく, 変更された部分だけをコピーできるので便利です。

昔のバージョンの rdist は rsh の機能を内蔵していたのですが, 1994 年 2 月以降(Version 6.1beta.2 以降), rdist は内部で rsh を呼び出すように変更されました。 従って,ssh をrsh と置き換えてインストールしている場合は, 何の変更もなく rdist で ssh が使えます。 rsh とは別に ssh をインストールしている場合は, rdist 実行時に「-P /usr/bin/ssh」などと ssh を使用するためのオプションを指定する必要があります。

どちらの場合も, 環境変数をたくさん使っている場合, その個数に注意する必要があります。 rdist は rsh(ssh)を呼び出す際に環境変数を引き継ぐのですが, その個数には上限があります。 rdist は Version 6.1.4 では, src/setargs.c の MAXUSERENVIRON で上限が設定されています。 デフォルトではこれが 40 になっているようです。

MAXUSERENVIRON で設定した以上の個数の環境変数を使っている場合, ssh-agent の実行で設定した環境変数 SSH_AGENT_PID, および SSH_AUTH_SOCK が ssh に引き継がれなくなってしまいます。 私は環境変数を 100 個近く使っている*15 ため, MAXUSERENVIRON の値を 200 に設定して, rdist を make し直しました。

rsync

rsync は rdist 同様, 2 つのマシンの特定のディレクトリの内容を同一に保つことができます。 rdist がクライアントからサーバーへのコピー専用であるのに対し, rsync はサーバーからクライアントへコピーするときも使えます。

rsync も内部で rsh を呼び出すので, ssh を rsh と置き換えてインストールしている場合は, 何の変更もなく rsync で ssh が使えます。 rsh とは別に ssh をインストールしている場合は, rsync の実行時に「-e /usr/bin/ssh」などとssh を使用するためのオプションを 指定する必要があります。

pppd

pppd コマンドは, IP 的に直接繋がっていない 2 つのホストの間に, IP パケットを流すことができるトンネルを設定するコマンドです。 プロバイダへダイヤルアップして PPP 接続するときに使われる*16 ので, ダイヤルアップ専用のコマンドと思っている人も多いかも知れませんが, 電話回線だけでなく ssh 接続を含む任意の通信路に IP パケットを流すことができます。

従って pppd と sshd を組み合わせて使えば, ssh 接続のクライアント側とサーバー側の内部 LAN 同士で 直接 IP パケットを送受信することが 可能になります(図 17*17。 いわゆる VPN(仮想プライベート・ネットワーク)ですが, セキュリティ的にはあまり望ましい形態ではありません。 片方の LAN に侵入されれば他方の LAN にまで影響がおよびます。 もともと ssh にはクライアント側とサーバー側が 一蓮托生になる性質を持っているのですが, VPN はその究極の姿と言えるでしょう。

pppd と ssh を用いた VPN
図 17 pppd と ssh を用いた VPN

セキュリティの基本は, 必要最小限のアクセスのみを許可し, それ以外のアクセスを排除することによって 侵入のリスクを最小化することにあります。 必要の無いパケットまで相互に流通させてしまう VPN は, 本当に必要なのかを十分に検討した上で使うべきか否か判断すべきでしょう。 もし ssh のポート・フォワードだけで用が足りるのであれば, VPN は使うべきではありません。

VPN は暗号化を行うから安全, というイメージを抱く人が多いのですが, VPN を構成する LAN の全てが完璧に守られていて はじめて VPN も安全と言えるのです。 だれもが LAN からインターネットへ Web ブラウザなどで手軽にアクセスすることが当たり前になってしまった現在では, LAN の規模が大きくなればなるほど安全ではなくなります。 安全でない LAN 同士を VPN で結べば, よりいっそう安全でなくなるのは当然と言えるでしょう。

ssh-agent の再利用

連載 3 回にわたって ssh を解説しましたが, いかがだったでしょうか。 まだ書き足らないところがあるほど奥の深い ssh ですが*18, とりあえず今回はこれでおしまいということにして, 最後に 1 つ便利なスクリプトを紹介します。

ssh-agent はパスフレーズを覚えてくれている便利なデーモンですが, 環境変数を設定しないと利用できないのは不便です。 もちろん環境変数ですから, おおもとのプロセスで設定すれば子プロセスに引き継がれていくのですが, ログアウトしてしまった後でもう一度使いたい, と思うことはよくあることです。 もちろん使わないときは, ssh-agent デーモンを終了させるべきなのですが, 毎日使うマシンであれば ssh-agent デーモンを動かし続けたいと思うのが 人情でしょう。

そんなとき, コマンド一発で ssh-agent を利用するための環境変数を設定することができたら, と思って作ったのが図 18 に示す ssh-env スクリプトです。 ssh の複数のバージョンに対応しているため冗長になっていますが, ps コマンドを使って ssh-agent のプロセス ID を探し, それに対応する UNIX ドメイン・ソケット探して 環境変数を設定するためのコマンドを出力します。


#!/usr/bin/perl $user = getlogin || (getpwuid($<))[0] || die; open(PS,"ps auxw |") || die; while(<PS>) { if (/^$user\s+(\d+).*[\s\(\[]ssh-agent([\s\)\]]|$)/) { $pid = $1; last; } } close(PS); if (! $pid) { if (@ARGV == 1 && $ARGV[0] eq "-csh") { exec "ssh-agent"; } else { die "Can't find ssh-agent.\n"; } } loop: for ($i=1; ; $i++) { die "Can't find socket.\n" if $i > 20; $j = $pid - $i; $sock = "/tmp/ssh-$user/ssh-$j-agent"; last if -S $sock; $sock = "/tmp/ssh-$user/agent-socket-$j"; last if -S $sock; while (</tmp/ssh-*/agent.$j>) { $sock = $_; last loop if -S $sock; } } while (@ARGV > 0) { if ($ARGV[0] eq "-sh") { shift; print "SSH_AUTH_SOCK=$sock;\nSSH_AGENT_PID=$pid;\n"; exit 0; } if ($ARGV[0] eq "-csh") { shift; print "setenv SSH_AUTH_SOCK $sock;\nsetenv SSH_AGENT_PID $pid;\n"; exit 0; } if ($ARGV[0] eq "-tty") { shift; $tty = 1; next; } if ($ARGV[0] eq "-d") { shift; $debug++; next; } last; } if (@ARGV == 0) { print "Agent pid $pid\n"; exit 0; } $ENV{'SSH_AGENT_PID'} = $pid; $ENV{'SSH_AUTH_SOCK'} = $sock; #$ENV{'SSH_AUTHENTICATION_SOCKET'} = $sock; if ($tty) { LOOP: foreach $p ("p", "q", "r", "s") { foreach $q (0..9, "a".."f") { if (open(PTY,"+>/dev/pty$p$q")) { $tty = "/dev/tty$p$q"; $success = 1; last LOOP; } } } die "Can't open pty.\n" if ! $success; print "tty: $tty command: ".join(" ",@ARGV)."\n" if $debug; open(TTY,"+>$tty") || die; if (!fork) { close(PTY); open(STDIN,"<&TTY"); open(STDOUT,">&TTY"); open(STDERR,">&TTY"); exec @ARGV; } close(TTY); while(<PTY>) { print; } wait; exit $?; } exec @ARGV;
図 18 ssh-env スクリプト

~/.cshrc に, 図 19 に示す alias 設定を入れておけば, コマンド・プロンプトで「ssh-env」と入力するだけで, 既に動いている ssh-agent デーモンを再利用できます。 もし,ssh-agent デーモンが動いていなければ新たに立ち上げてくれます。


alias ssh-env 'eval `perl $HOME/bin/ssh-env -csh`'
図 19 ssh-env スクリプトを使うための alias 設定

また,このスクリプトを使えば, cron などから呼び出すプログラムから ssh-agent を利用することも可能になります。 例えば crontab で図 20 のように設定します。 ssh-env スクリプトが環境変数を設定した上で rdist コマンドを呼び出すので, rdist が呼び出す ssh にもその環境変数が引き継がれ, パスフレーズを入力する必要無くssh 接続できます。


33 4 * * *   $HOME/bin/ssh-env rdist azabu
図 20 cron で ssh を使う
*12
rsh,rlogin,rcp コマンドを /usr/libexec などに移して, ssh を make するとき configure に, --with-rsh=/usr/libexec/rsh オプションを指定します。
*13
tar の代りに cpio コマンドを使う方法もあります。
*14
cp に -a オプションがサポートされた現在でも, 指が覚えていてつい tar コマンドを使ってしまう, という人が多いのではないでしょうか。
*15
1989 年に作った ~/.cshrc をいまだに使い続けていますから, 10 年以上の歴史がある私独自の環境変数があったりします。
*16
RedHat 系の Linux でしたら, ネットワーク設定ツール netcfg を使ってダイヤルアップ接続の設定を行うと, 自動的に pppd コマンドが使われる設定になります。
*17
具体的な方法は, VPN HOWTO(http://www.linux.or.jp/JF/JFdocs/VPN-HOWTO.html など)を参照してください。
*18
書き尽くそうと思えば,軽く本 1 冊くらいの分量になるでしょう。

(ライターから)


本稿は日経Linux 2001 年 2 月号に掲載された、 実践で学ぶ、一歩進んだサーバ構築・運用術, 第 11 回「ssh (後編)」を日経BP 社の許可を得て転載したものです。

Copyright(C)2001 by 仙石浩明 <sengoku@gcd.org>
無断転載を禁じます

| home | up |

sengoku@gcd.org