メモ: ssh-keysignはHostbased認証を使うときのみsetuidする

鍵交換方式でSSHを使うなら、ssh-agentもssh-keysignも有効にしておく必要があります。

作業メモ: setuid/setgidされているコマンドを見てみる - 虎塚

・・・などと書いたのだけれども、調べたらUSO-800だったので、訂正します。

  • ssh-keysignは、ユーザ認証の方法にHostbased認証を使う場合のみ、有効にします。

# ssh-agentをsetuidすべき状況を特定していないので、そちらは保留です。

間違えた原因は、2つのユーザ認証方法

  • 公開鍵認証
  • Hostbased認証

を混同していたからでした。どちらも、

  1. サーバからクライアントの公開鍵を使って暗号化したデータを投げて
  2. クライアントからクライアント自身の秘密鍵を使って復号したデータを返す

というチャレンジレスポンスの形式は同じです。

しかも、公開鍵認証で、クライアントが秘密鍵パスフレーズで守っていない場合は、ユーザがタイプする認証時のコマンドが、両者でそっくりになります。

(公開鍵認証で利用する鍵ペアを生成する際に、パスフレーズを与えなければ、作成された秘密鍵は暗号化されません。そのため、公開鍵認証のたびにパスフレーズを聞かれることがなくなります。よくないとされていますが)

というわけで誤解していましたが、次の表で示すように、両者は別物です。

公開鍵認証 Hostbased認証
認証の対象 ユーザ クライアント
秘密鍵の生成方法 ユーザが手動で生成する SSHインストール時に自動生成される
秘密鍵の格納場所 クライアントマシンの{USER_HOME}/.ssh/以下 クライアントマシンの/etc/ssh/以下
公開鍵の格納場所 サーバマシンの{USER_HOME}/.ssh/以下 サーバマシンの/etc/ssh/以下

以下では、「ssh-keysignはsetuidされるべきか否か」に結論を出すための観点で考えてみます。

Hostbased認証の目的は、クライアントマシンの真正性を証明することです。そのため、rootの領域にある秘密鍵を使用します。この鍵は、個々のユーザではなく、クライアントマシンと紐づいています。

クライアント秘密鍵は、「クライアントの証明書」なので、接続先のサーバが変わろうとも1つのものを使い続けます。というか、使っている途中で変えてはいけません。使用中に変更してしまうと、サーバから別のクライアントになったとみなされてしまいます。

さて、そのクライアント秘密鍵は、たいてい/etc/sshディレクトリ以下にあり、パーミッションが600になっています。つまり、所有者であるrootだけが、読み込みと書き込みができます。

これでは困ります。ユーザ権限のプロセスが、秘密鍵を直接読むことができません。

そこでssh-keysignの出番です。sshssh-keysingを内部的に呼び出すため、setuidされたssh-keysignはrootとして実行されるので、クライアント秘密鍵を読むことができる、らしいです。

というわけで、Hostbased認証を使わないのであれば、ssh-keysignのsetuidを無効にしてよいでしょう。

オマケ

理屈は分かった気がするものの、ssh-keysignが呼び出されているコードを確認するのが途中なので、メモを。

{openssh-5.8p2}/ssh.cの780行目あたりの

if (options.rhosts_rsa_authentication ||
            options.hostbased_authentication) {
...(略)

で始まる処理が、key_load_private_cert関数をせっせと呼んで、RSAやらDSAやらの形式の秘密鍵を読み込もうとしています。この関数は、authfile.cにあります。

…というところで、続きはまた今度。