サーバーの設定ファイルは, デフォルトでは /usr/local/etc/sshd_config にあります。 さまざまな設定が可能ですが, ほとんどはデフォルトのままで良いでしょう。 ただし, 安全性を高めるには RSA クライアント認証以外の認証方法を禁止すべきです。
具体的には, 設定ファイル中, 次の項目を「no」に設定します(図 15)。 そして, RSA クライアント認証のみ「yes」にします(図 16)。
| ||||||||||||
図 15 サーバーの設定 |
| |||
図 16 RSA クライアント認証のみ「yes」にする |
クライアントの設定ファイルは, デフォルトでは /usr/local/etc/ssh_config と ~/.ssh/config です。 /usr/local/etc/ssh_config には全ユーザーに共通する設定, ~/.ssh/config はユーザーごとの設定で, どちらも書式は同じです。 職場*22 の LAN 上の Linux マシンで私が使っている ~/.ssh/config の例*23 を図 17 に示します。
| |||||||||||||||||||||
図 17 クライアントの設定ファイル |
最初の「Host 〜」の行までが, すべての接続先サーバーに共通な設定, それぞれの「Host 〜」から次の「Host 〜」までが, それぞれのサーバーごとの設定です。 1 行目の「Compression yes」は, クライアントとサーバーとの間でやりとりするデータを圧縮する, という設定です。 インターネット経由の通信では, 圧縮により帯域の有効利用が期待できます。 「Host azabu」は, サーバー「azabu」に接続するときの設定で, 「HostName azabu.klab.org」と指定していることから, 「ssh azabu」と実行すると, azabu.klab.org に対してログインします(図 18)。
図 18 「ssh azabu」を実行 |
同様に「ssh asao」と実行すると, ube.gcd.org に対してログインします。 ただし, 「Port 443」と指定しているので, デフォルトのポート 22 番ではなくポート 443 番を使います。
さらに, 図 17 の一番最後の行で 「ProxyCommand /home/sengoku/bin/proxy-klab %h %p」 と指定しているので, ube.gcd.org のポート 443 番に直接接続するのではなく, /home/sengoku/bin/proxy-klab コマンドを介して接続します。
「%h %p」は, proxy-klab コマンドへの引数で, 「%h」は接続先ホスト, 「%p」は接続先ポートで置き換えられます。 この場合であれば, 「ube.gcd.org 443」という意味になります。
図 19 のように, ssh は proxy-klab コマンドの標準入出力に対して ssh プロトコルによる通信を行います。 proxy-klab コマンドは, 標準入力から受け取ったデータを, 実際のサーバーである ube.gcd.org へ中継し, ube.gcd.org から受け取ったデータを標準出力へ送り出します。
図 19 「ssh asao」を実行 |
なぜ, こんなまわりくどいことをするのでしょうか? それは ube.gcd.org など, インターネット上のホストに直接 TCP/IP 接続することができないからです*24。
最近の企業サイトの多くはファイアウォールが設置され, 社内の LAN からインターネット上のホストへ直接 TCP/IP 接続することができないケースが多いのではないかと思います。 そのような職場でも, Web に限りプロキシ経由の接続が認められているところが大多数でしょう。
ここでは Web プロキシのホスト名が proxy.klab.org で, ポート番号が 8080 であると仮定します。 そして, ube.gcd.org のポート 443 番で ssh サーバーが動いているとします。
すると, Web プロキシ経由で ube.gcd.org の ssh サーバーへ接続することが可能です。 例えば, 図 20 のように実行します。 まず, proxy.klab.org のポート 8080 番に接続します (図 20 中の 1 行目)。 プロキシ(この例の場合は,squid)に接続したら, 図 20 のように「CONNECT ube.gcd.org:443 HTTP/1.0」と入力します。 これは https://ube.gcd.org/ に接続するときに, Web ブラウザがプロキシに対して送信する内容と同じです。 つまりプロキシ側から見ると, 普通の https プロトコル(SSL で暗号化したhttp プロトコル) のように見えるわけです。
kamiya:/home/sengoku % telnet proxy.klab.org 8080 Trying 10.10.0.3... Connected to proxy.klab.org. Escape character is '^]'. CONNECT ube.gcd.org:443 HTTP/1.0 HTTP/1.0 200 Connection established SSH-1.99-OpenSSH_2.2.0p1 |
図 20 Web プロキシ経由の接続 |
https プロトコルは SSL で暗号化されているので, その内容についてはプロキシは一切関知しません。 単に Web ブラウザと Web サーバーとの間に双方向の通信路を設定するだけです。 従って https の代わりに ssh プロトコルを流すことも可能なのです。
図 20 の最終行は ube.gcd.org のポート 443 番の ssh サーバーが返したバージョン番号で, この後 ssh プロトコルによる通信が可能です。 従って, proxy-klab コマンドは, 図 20 と同じ動作を行った後, 標準入力から受け取ったデータをそのまま ube.gcd.org のポート 443 番へ送信し, ube.gcd.org のポート 443 番から受け取ったデータを そのまま標準出力へ送れば OK です(図 21)。 proxy-klab コマンドを perl スクリプトで実装した例を図 22 に示します。
図 21 Web プロキシ経由の接続 |
Web プロキシの場合と同様に, telnet プロキシなどそのほかのプロキシの場合でも, 適切な ProxyCommand を書き, インターネット側で適切なサーバーを立ち上げれば, プロキシ経由の ssh 接続が可能です。
#! /usr/bin/perl $PROXY_KLAB = "proxy.klab.org"; $PROXY_KLAB_PORT = 8080; $Verbose = 0; while ($_ = shift) { last if ! /^-(.*)/; if ($1 =~ /^v+$/) { $Verbose += length($&); next; } print<<EOF; Usage: proxy [option...] <host> <port> Options: -v Verbose mode EOF } $HOST = $_; if ($_ = shift) { $PORT = $_; } else { $PORT = 23; } print "Verbose Level: $Verbose\n" if $Verbose; use Socket; ($name, $aliases, $proto) = getprotobyname('tcp'); ($name, $aliases, $type, $len, $thataddr) = gethostbyname($PROXY_KLAB); $that = sockaddr_in($PROXY_KLAB_PORT, $thataddr); socket(S, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; connect(S, $that) || die "connect: $!"; if ($Verbose > 1) { $Rin = &fhbits('STDIN S'); } else { $Rin = &fhbits('S'); } &login; &connect; exit 0; # login 処理 sub login { &receive(0.1); &send("CONNECT $HOST:$PORT HTTP/1.0\r\n\r\n"); do { &receive(0.1); } until (/HTTP\/[\d\.]+ 200.*\n\n/); $Raw =~ m/HTTP\/[\d\.]+ 200.*[\r\n]+/; $Raw = $'; } # connect sub connect { local($rout); print "CONNECT\n" if $Verbose; $Rin = &fhbits('STDIN S'); syswrite(STDOUT,$Raw,length($Raw)); while ((select($rout=$Rin,undef,undef,undef))[0]) { if (vec($rout,fileno(S),1)) { return if sysread(S,$_,1024) <= 0; # EOF syswrite(STDOUT,$_,length); } if (vec($rout,fileno(STDIN),1)) { return if sysread(STDIN,$_,1024) <= 0; # EOF syswrite(S,$_,length); } } } # send(str); # str を送る sub send { undef $Buffer; undef $Raw; while( $_ = shift ) { print if $Verbose > 2; syswrite(S,$_,length); } } # receive(s); # s 秒入力が途絶えるまで待つ sub receive { local($timeout) = shift; local($rout); while ((select($rout=$Rin,undef,undef,$timeout))[0]) { if (vec($rout,fileno(S),1)) { &abort if sysread(S,$_,1024) <= 0; # EOF $Raw .= $_; tr/\r\000\012\021\023\032/\n/d; $Buffer .= $_; print if $Verbose > 1; } if (vec($rout,fileno(STDIN),1)) { &abort if sysread(STDIN,$_,1024) <= 0; # EOF s/\n/\r/g; syswrite(S,$_,length); } } $_ = $Buffer; } sub fhbits { local(@fhlist) = split(' ',$_[0]); local($bits); for (@fhlist) { vec($bits,fileno($_),1) = 1; } $bits; } sub abort { exit(1); } |
図 22 perl スクリプトで書いた proxy-klab コマンド |
(ライターから)
本稿は日経Linux 2000 年 12 月号に掲載された、 実践で学ぶ、一歩進んだサーバ構築・運用術, 第 9 回「ssh (前編)」を日経BP 社の許可を得て転載したものです。
Copyright(C)2000 by 仙石浩明 <sengoku@gcd.org>
無断転載を禁じます