PuTTYを使用してSSHでリモートのLinuxにログインして管理するたびに、リモートログインのプロセスが非常に遅い——ユーザー名を入力し終えた後、パスワード入力のプロンプトが出るまでに30秒ほど待たされる。実際に問題を処理する際、特に迅速な対応が必要なときには、この状況は本当に耐え難い。

しかし後で具体的にテストしてみたところ、これはすべてのシステムに共通する問題ではないことが分かった。問題が発生するマシンは主にCentOSに集中しており、同じDebianシステムでは、リモート接続の過程が非常にスムーズで、一切の遅延やもたつきを感じなかった。これはまさかCentOSの問題なのだろうか?

诊断并解决 SSH 连接慢的方法

好奇心から、2つのシステムのSSH接続時の違いを調べてみた

CentOS:

ssh -v ssh_test@192.168.128.137

SSHリモートログイン時に表示される情報は以下の通りです:

OpenSSH_6.0p1 Debian-4, OpenSSL 1.0.1e 11 Feb 2013
...Some sensitive information...
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.3
debug1: match: OpenSSH_5.3 pat OpenSSH_5*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.0p1 Debian-4
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY
...Some sensitive information...
debug1: ssh_rsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Next authentication method: gssapi-keyex
debug1: No valid Key exchange context
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information

debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Next authentication method: publickey
debug1: Trying private key: /home/mitchellchu/.ssh/id_rsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_dsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_ecdsa
debug1: Next authentication method: password

一方、Debianで同じコマンドを使用してテストした結果は次のとおりです:

OpenSSH_6.0p1 Debian-4, OpenSSL 1.0.1e 11 Feb 2013
...Some sensitive information...
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.0p1 Debian-4
debug1: match: OpenSSH_6.0p1 Debian-4 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.0p1 Debian-4
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
...Some sensitive information...
debug1: ssh_ecdsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Trying private key: /home/mitchellchu/.ssh/id_rsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_dsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_ecdsa
debug1: Next authentication method: password

上記から分かるように、CentOSではシステムがpublickey、gssapi-keyex、gssapi-with-mic、およびpasswordを使用して認証を行っている(上記の色付きの行、23行目)。一方、DebianではPublickeyとpasswordの2種類を使用している。CentOSに接続する際、23行目でかなりの時間を費やしていた。そこから下を見ていくと、以下の情報が非常にはっきりと確認できる:

#下面使用的是GSSAPI-KEYEX来进行验证
debug1: Next authentication method: gssapi-keyex
#但是报错:没有可用的Key来交换信息
debug1: No valid Key exchange context
#系统接着又使用下一个验证方法:GSSAPI-WITH-MIC
debug1: Next authentication method: gssapi-with-mic
#但遗憾的是,GSSAPI-WITH-MIC方法也失败。
#原因:不能确定数字主机地址的域
debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information

debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address
# 在尝试几次后,SSH认证终于放弃了这种验证。进入下一个验证:Publickey
debug1: Next authentication method: publickey

この方法以外にも他の方法はあるのか?もちろんある。CentOSは実際にすでに解決策を提供している——SSHリモートログイン時にGSSAPI認証を無効にすることだ。もちろん、もう一つ注意しなければならない問題がある。もしマシンでUseDNSが有効になっている場合は、それも一緒に無効にする必要がある。詳細は最後の説明を参照のこと。

エラーから、ホストのドメインに関連する問題であることがわかる——IPに対応するドメインを確認できないために、この問題が発生するはずだ。GSSAPIは主にKerberosに基づいているため、この問題を解決するにはシステムにKerberosを設定する必要が出てくる。Kerberosを持っていない皆さんにとって、ログイン遅延問題を解決するためだけにKerberosを設定するのは賢明な決定とは思えない——特に本番環境では!最小限の要件で満たすことが王道だ。

まずはGSSAPIの処理方法を紹介する

GSSAPI認証を無効にする方法は2つある:クライアント側とサーバー側

1. クライアント無効

比較的簡単で、影響を受けるのは単一のクライアントユーザーだけであり、以下の方法で実現できる:

ssh -o GSSAPIAuthentication=no your-server-username@serverIP

上記の方法でリモートにログインすれば、GSSAPIAuthenticationを無効にすることができる。

面倒だと思うなら、sshクライアントのファイル /etc/ssh/ssh_config を直接設定して、この問題を恒久的に解決することもできる:

vi /etc/ssh/ssh_config
### 找到ssh_config文件里面的GSSAPIAuthentication yes这行
### 修改为GSSAPIAuthentication no
### 保存ssh_config文件并退出

この変更方法は、このマシン上のすべてのユーザーに影響を与える。影響範囲をそれほど広くしたくない場合、指定したユーザーに対してのみGSSAPIAuthenticationを無効にしたいなら、そのユーザーのホームディレクトリにある.sshディレクトリを見つけ、その下にconfigファイルを追加し、ファイル内に上記の記述を追加すればよい。このファイルがない場合は、直接次のようにしてもよい:

cat >>~/.ssh/config<<EOF
GSSAPIAuthentication no
EOF

catを使用して、入力をそのままファイルにエクスポートする。そうすれば、sshでリモートのターゲットホストに接続する際に、GSSAPI認証は使用されなくなる。

上記のファイルはクライアント側のものであり、サーバー側のものではない。つまり、このファイルを変更するには、クライアントもLinuxである必要がある。

WindowsでPuTTYのようなクライアントツールを使用している場合は、上記の方法は使用しません。PuTTYでは、接続前に以下の設定を試すことができます:

PuTTY Configuration -> Connection -> SSH -> Auth -> GSSAPI -> (取消勾选)Attempt GSSAPI authentication(SSH-2 only)

PuTTYのGSSAPIAuthenticationを無効にしていない場合、接続ウィンドウで右クリック(または:Ctrl + 右クリック)してログを表示すると、PuTTYが自動的にGSSAPI接続を試みるログを見つけることができる:

2014-05-18 23:46:54 Using SSPI from SECUR32.DLL
2014-05-18 23:46:54 Attempting GSSAPI authentication
2014-05-18 23:46:54 GSSAPI authentication request refused

うん、上記で基本的にクライアント側でGSSAPIAuthenticationを無効にする方法を列挙した。

注意:上記の方法は比較的一般的な方法である。

2、すでにKerberosを設定している場合

では、以下のようなクライアント側でこの問題を解決する方法も試してみてください:

リモートホストのホスト名をローカルのhostsファイルに追加します(Linuxは/etc/hosts、Windowsはシステムドライブ:/Windows/System32/drivers/etc/hosts)。LinuxとWindowsのどちらでも次の行を追加できます。

### 注意:下面这样的IP-Addr要替换成你的远程机器的IP地址,HostName,自然是主机名
IP-Addr HostName

追加が完了したら、保存して終了します。

Kerberosを設定していない場合、このhostsファイルを設定するだけでは問題を解決できない。SSHでログインするとき、以下のようなエラーログが表示されるのを確認できるでしょう:

debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mi
debug1: Next authentication method: gssapi-keyex
debug1: No valid Key exchange context
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_0' not found

debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_0' not found

debug1: Unspecified GSS failure.  Minor code may provide more information

debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_0' not found

debug1: Next authentication method: publickey

この間違いは私も最初の頃に犯したことがあるので、注意が必要だ。

3、服务端禁用GSSAPIAuthentication。

直接 /etc/ssh/sshd_config に移動し、GSSAPIAuthentication yes を no に変更すればよい。また、UseDNS も UseDNS no に変更する必要があるかもしれないので注意してほしい(ここは注意が必要で、システムによってデフォルト値が異なる。ここではCentOS 6を例としている):

sudo vi /etc/ssh/sshd_config
### 普通用户权限不够,需要root权限
### 找到GSSAPIAuthentication yes,修改为
### GSSAPIAuthentication no
### 注意,这里你也需要将UseDNS修改为no,CentOS默认是yes,即使这行已被注释,你也需要加上
### UseDNS no
### 有看到人说UseDNS yes不需要修改为UseDNS no,Mitchell测试下来是需要的。
### 保存文件,退出

無効にした後、SSHサービスを再起動して、新しい設定ファイルが正しく適用されるようにする必要がある:

service sshd restart

このとき、再度SSHでこのホストにログインすると、速くなったと感じるのではないでしょうか?

ふぅ~ ようやくこの長文を書き終えた。あれこれ弄りながら文章をまとめるのは、やはり少し大変だった。しかし、これでだいたい問題を整理できたと思う。記事を読んでいるあなたに理解してもらえたら嬉しい。議論は大歓迎だ。

说明

1. GSSAPI:Generic Security Services Application Program Interface。GSSAPI自体はAPIのセットであり、IETFによって標準化されています。その最も主要で有名な実装はKerberosベースのものです。一般にGSSAPIと言えばKerberos実装を暗に指します。

2. UseDNS:OpenSSHサーバー上のDNS参照オプションであり、デフォルトで有効になっている。有効な状態では、クライアントがOpenSSHサーバーへの接続を試みるたびに、サーバーはユーザークライアントのIPに基づいてDNS PTR逆引き(IP逆引きでないとレコードは存在しない)を自動的に行い、IPに対応するHostnameを取得し、その後クライアントのHostnameに基づいてDNS正引きAレコードを参照する。この参照により、IPが接続しているクライアントのIPと一致するかを検証する。しかし、ほとんどのマシンはIPを動的に取得している。つまり、このオプションはこのような状況ではまったく役に立たない——通常の静的IPサーバーであっても、IP逆引きを設定していなければ適用が難しい。これらの状況に該当する場合は、SSHリモートログイン時の認証速度を向上させるためにUseDNSを無効にすることを推奨する。

来源:http://blog.useasp.net/archive/2014/05/19/solved-the-problem-of-ssh-client-such-as-putty-remote-login-linux-very-slowly.aspx