2011/05/02

sshでHostbasedAuthenticationを有効にする場合の落とし穴

以前、「ssh で HostBased 認証を行うには ssh-keysign に setuid する必要がある」として、HostBasedAuthentication(以下、ホストベース認証)の設定方法をまとめました。

にも関わらず、ホストベース認証を有効化しようとすると、相変わらず落とし穴にはまってしまうことが少なくありません。以下、自分が陥った落とし穴をまとめてみました。

ホストベース認証を有効にする場合、loginされる側(以下サーバ側)では、原則以下の3手順が必要となります。

  1. sshd_configでHostbasedAuthenticationをyesに設定する
  2. ssh_known_hostsへ、loginする側(以下クライアント側)の公開鍵を登録する(クライアント側でもsshdが起動している場合にはssh-keyscanコマンドの利用が便利)
  3. shosts.equiv、または ~root/.shosts へクライアントのホスト名を登録する

一方クライアント側では以下の2手順が必要になります。

  1. ssh_configでEnableSSHKeysignをyesに設定する
  2. ssh_config、または~/.ssh/configでHostbasedAuthenticationをyesに設定する

以下、陥りがちな落とし穴について解説します。


1. 設定ファイルの置かれているディレクトリ

サーバ側、クライアント側両者に関係する落とし穴です。

サーバ側で起動するsshdコマンドやクライアント側で利用するsshコマンドは、
システムワイドの設定ファイルを参照しますが、
このファイルが置かれるディレクトリはOSやコンパイル時の設定等に依って異なります。

例えばFreeBSD 8.2やUbuntu 11.04へ同梱されているsshパッケージでは、システムワイドな設定ファイルは/etc/sshへ置かれています。一方、MacOS X 10.6に含まれているsshパッケージでは、/etcへ置かれています。

また、FreeBSDやMacOS Xを利用している場合でも、portsなどのパッケージ管理ツールを使ってインストール行った場合には、それぞれ設定ファイルの置かれるディレクトリが異なります。

例えば「依存関係解決の為、パッケージ管理ツールが最新版のsshをインストールしていた」などの理由により各種コマンドが更新され、その結果参照する設定ファイルが異なっていた、ということは皆無でありません。特に、起動時に絶対パス指定が必須なsshdコマンドと異なり、相対指定が可能なsshコマンドの場合には見落としがちです。

設定ファイルを変更しても、変更が反映されていないと感じる場合には、どの設定ファイルが参照されているのか確認してみると良いでしょう。ssh の場合には -v を、sshd の場合には -d を指定することで、参照する設定ファイルが表示されます。以下は、sshが参照している設定ファイルに関する表示例です。

debug1: Reading configuration data /Users/n-miyo/.ssh/config
debug1: Reading configuration data /etc/ssh_config


2. 設定の順序

sshの設定は、コマンドライン指定値、ユーザ独自の設定値(一般的には~/.ssh/configでの設定値)、最後にシステムワイドなssh_configの順番で探索され、最初に見つかった設定値が採用されます。各種設定ファイル内に於いても、ファイル先頭行から探索が行われ、最初に見つかった設定値が採用されます。即ち、先勝ちモデルです。

sshdでの設定も同様で、sshd_configの中で、ファイル先頭業から先勝ち優先モデルに基づき探索が行われます。

独自設定を行う場合には、設定ファイル内の上部で同じ設定がなされていないことを確認する、または、ファイル先頭付近で設定を行うと良いでしょう。特に ssh_config、または ~/.ssh/config でホスト名を指定した設定を行う場合には、その設定が「Host *」指定よりも前で行われていることを確認しましょう。「Host *」よりもファイル終端側で設定を行っても、その設定は反映されません。


3. shosts.equivで指定するホスト名

サーバ側の設定に関係する落とし穴です。

ホストベース認証では、root以外のユーザによるログインを許可する場合、接続を許可するクライアントのホスト名を、サーバ側のシステムワイドな設定ファイルであるshosts.equivへ列記する必要があります。

shosts.equivへ書きこむホスト名は、sshd_configで設定したUseDNSの値によって異なります。

sshd_configでUseDNSをyesに設定してている場合、ホスト名には、IPアドレスの逆引き結果である正式ホスト名、またはIPアドレスを指定します。もしサーバがホスト名解決に/etc/hostsを利用している場合、そこへ記された正式ホスト名を書く必要があります。一方サーバがNISやDNSで名前解決を行っている場合、それらのシステムから返されるホスト名を書かなければなりません。何れの場合でも、正式ホスト名の代わりに、別名(alias名)を書いた場合、認証に失敗します。

例えば、名前解決に/etc/hostsを利用しているサーバに於いて、/etc/hostsへ以下の記述があったとします。

10.0.0.1 foo.example.jp foo

この場合、shosts.equivで指定するホスト名はfoo.example.jpです。fooを指定しても認証は成功しません。

一方、sshd_configでUseDNSがnoの場合、ホスト名には必ずIPアドレスを書く必要があります。ホスト名や別名、即ち上記の例では、foo.example.jpやfooを書いても認識されません。

クライアントが送ってきたホスト名と、sshdが認識したホスト名が異なった場合、UseDNSがyesに設定されているsshdは次のようなエラーメッセージを出力します。

May  2 07:56:38 lidia sshd[29264]: userauth_hostbased mismatch: client sends foo, but we resolve 10.0.0.1 to foo.example.jp

一方、sshd_configでUseDNSがnoになっている場合、次のようなエラーメッセージが出力されます。

May  2 07:58:06 lidia sshd[54965]: userauth_hostbased mismatch: client sends foo.example.jp, but we resolve 10.0.0.1 to 10.0.0.1

システムがどのように名前解決を行っているかを知る際の参考になるでしょう。


4. ホストベース認証利用時によるrootのloginの許可

サーバ側の設定に関係する落とし穴です。

ホストベース認証でrootによるloginを許可する場合、shosts.equivは参照されません。許可ホスト名は ~root/.shosts で指定する必要があります。

これはrshの仕様である「rootからのloginでは、hosts.equivは参照しない」を踏まえたものですが、ssh関連のマニュアルページには明確な記載がなく、見落としがちなポイントです。

~root/.shostsの指定に当たって注意すべき点は2点です。

第一に、ホスト名を指定に於いては、shosts.equiv同様、sshd_configのUseDNSの値に注意しなければなりません。UseDNSがyesの場合には、正式ホスト名、IPアドレスの何れも指定することが可能です。一方UseDNSがnoの場合には、IPアドレスのみが指定できます。何れの場合においても、別名を利用することは出来ません。

第二に、~root/.shosts はレギュラーファイルでなければならず、所有者がrootでなければならず、且つ、ファイル所有者のみに書き込み許可がなされていなければなりません。symbolic linkであったり、他者が書き込みできるパーミションになっている場合には、このファイルは無視され、結果的に認証が失敗することになります。

またsshd_configの設定にも注意が必要です。

まずrootでログインすることになるため、PermitRootLoginをyesへ設定する必要があります。加えて、~root/.shostsの参照を許可するため、IgnoreRhostsをnoに設定しなければなりません。

結果、ホストベース認証によるrootのloginを許可するためには、sshd_configに対し、最低限以下の記述が必要になります。

HostbasedAuthentication yes
IgnoreRhosts no
PermitRootLogin yes


5. EnableSSHKeysign の設定と ssh-keysign コマンドのパーミション

クライアント側の設定に関係する落とし穴です。

原則ホストの秘密鍵はrootでしか読み取りができないパーミションに設定されています。sshコマンドも例外でなく、一般ユーザによって起動されたsshコマンドは、このファイルを読み取ることが出来ません。その制限を解決するコマンドがssh-keysignです。

ssh-keysignを利用するには、システムワイドなssh_config内でEnableSSHKeysignをyesに設定する必要があります。この設定は、~/.ssh/configで行っても反映されません。加えて、この設定はホストに特化した設定としてではなく、システム全体で有効になるように記載しなければなりません。即ち、全てのHost指定がなされるよりも前で行うか、Hostに*を指定した箇所で行う必要があります。

また、FreeBSDやMacOS Xでは、ssh-keysignコマンドは、デフォルトでrootへsetuidされていません。次のようなコマンドで明示的にrootへsetuidを行う必要があります。この設定を行わない場合、ssh_configでEnableSSHKeysignを設定しても実質機能しません。

# chown root /usr/libexec/ssh-keysing
# chmod u+s /usr/libexec/ssh-keysign


6. ssh_config、~/.ssh/config で指定するホスト名

クライアント側の設定に関係する落とし穴です。

ssh_config や ~/.ssh/config ではホスト名に特化した設定を行うことが可能です。例えば、ホストbar.example.jpへログインする際、必ずホストベース認証を行いたい場合には、以下のように書くことが出来ます。

Host bar.example.jp
 PreferredAuthentications hostbased

ここでHostに続けて指定するホスト名は、sshコマンド実行時の引数に指定するホスト名と完全に合致している必要があります。例えば、bar.example.jpへbarという別名が割り当てられている環境に於いて、

% ssh bar

と指定しても、PreferredAuthentications hostbasedの設定はは有効になりません。この設定を有効にするには、

% ssh bar.example.jp

と指定する必要があります。

ssh_configや~/.ssh/configファイルのホスト名は、空白で区切ることにより複数個指定することが可能です。同一ホストへ別名が付されている場合には、それらを列挙しておくと便利でしょう。

Host bar.example.jp bar
 PreferredAuthentications hostbased


7. 最後に

sshに纏わるトラブルは、サーバ/クライアント双方の設定、認証に使われる鍵、名前解決の仕組み、rsh時代からの慣例などが複雑に絡みあい、問題解決に時間のかかってしまうことが少なくありません。更に、ファイアウォール等によるポート制限などが加わった場合、問題の切り分け自体が困難を伴います。

問題が生じてしまった場合、以下の手法を活用すれば、問題解決の糸口がつかめるかも知れません。

  1. sshd は -d オプションによりデバッグモードで実行させ、且つ -p オプションにより別ポートで待受させる
  2. ssh は -v オプションによりログメッセージを出力させる設定にした上で、-p オプションにより sshd で指定した待ち受けポートへ接続させる
  3. まずは同一ホストでサーバとクライアントの両者を立ち上げ、名前解決に関する問題が原因でないことを突き止める
  4. 安全なネットワークへ実験環境を構築し、ファイアウォールなどのアクセス制限を一旦解除する

ホストベース認証に纏わる問題切り分けの参考になれば幸いです。

0 件のコメント:

コメントを投稿