そろそろLDAPにしてみないか?

第6回 OpenSSHの公開鍵をLDAPで管理

この記事を読むのに必要な時間:およそ 5.5 分

公開鍵,秘密鍵の作成

次のように,秘密鍵と公開鍵を作成します。今回はDSA形式を選択しています。

図4 公開鍵,秘密鍵の作成

% ssh-keygen -t dsa
Generating public/private dsa key pair. 
Enter file in which to save the key (/home/nomo/.ssh/id_dsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/nomo/.ssh/id_dsa. 
Your public key has been saved in /home/nomo/.ssh/id_dsa.pub. 
The key fingerprint is: 
c3:ca:8b:58:8b:1a:6c:84:8b:8b:bd:06:e1:1e:20:4f nomo@rx8 

この操作で作成される~/.ssh/id_dsaが秘密鍵,~/.ssh/id_dsa.pubが公開鍵です。秘密鍵は途中で入力されるパスフレーズにより暗号化された状態で保存されます。後者の公開鍵は文字通り公開するものなので,他人に見せても問題ありません。

次にLDAPサーバ側での操作です。本連載の第2回でUNIXアカウントをLDAPサーバ側に登録しました。同じユーザツリーの中に公開鍵情報を登録してみましょう。

次のように,公開鍵用の属性とオブジェクトクラスを追加します。変更部分はldapPublicKeyというオブジェクトクラスとsshPublicKeyという公開鍵用の属性です。この中にはid_rsa.pubやauthorized_keys2の中に1行で記録されている鍵情報をそのまま登録します。

リスト2 ユーザ用エントリ(sshuser.ldif)

dn: uid=sshuser,ou=People,dc=example,dc=com
objectClass: account
objectClass: posixAccount
objectClass: ldapPublicKey
uid: sshuser
cn: sshuser
userPassword: sshuser
loginShell: /bin/bash
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/sshuser
sshPublicKey: ssh-dss AAAAB3NzaC1kc3MAAACBAJ5sBOzM/PCkETefX7yzrs+oEVOp3hwuBSpL96pbkfoyQ5jvMABT6aGzXqQUTZu00Gke+G+CJeOg3rw9K7+ghrNuB4Rv33l1LdILjTTMFqDsvMo02Un6DKv/EvAW++rarKDDU5DMJOEPqkOWTsPb683WP77fHcBxKsALVtVAFTMzAAAAFQDVPmzJd39IYvKMWQsJQvzPefUX8wAAAIEAliBMDP2SFtPoAZMAbCtAwWtQmXh7C/+CJwrQEJMDYb1Pp+7jaOk+7AgsGMTA2abtSsPDvvhlrNXOyqx+EMYxibwnX4dnGS7NQAsQhqUmvqzzKfySD/UvJ6GQYtB9FMpju0L/qH5B5jtdfwggXTaGRXuadnzAZ7rrOOMvosqyhc8AAACBAInNQo10pbrnkp9grL+Db2/Rp1JXVajN02isPzfpS7uX9rohAlyTVLAjlwLwTGrp6CFwG4/t9e7jxlIo4Wm2r7LXgLr9u7+dg+oMENJpYkt/0NtLBq40dICE8yhha58cQau5z98Ajc6dO9yvB2Bp6C3oDIiumPq/e2IMGjYYrtcP nomo@rx8

ではこのエントリをLDAP上に登録します。

図5 変更部分のLDAPへの反映

% ldapadd -x -D "cn=Manager,dc=example,dc=com" -w secret -f sshuser.ldif

次にsshdプロセスがLDAPサーバを検索できるよう,/usr/local/etc/sshd_configを修正しておきます。リスト3のようにLDAP関連のオプションを有効にしておきましょう。

リスト3 sshd_configの修正部分

UseLPK yes
LpkServers  ldap://10.0.100.10
LpkUserDN   ou=people,dc=example,dc=com
LpkGroupDN  ou=group,dc=example,dc=com

準備ができたら,sshdプロセスを起動させ,クライアントから接続を行ってみます。

図5 sshdプロセスの起動

# /usr/local/sbin/sshd

図6 クライアントからの接続試験

% ssh sshuser@10.0.100.11
Enter passphrase for key '/home/nomo/.ssh/id_dsa': 
Last login: Fri Nov  9 23:30:14 2007 from 10.0.100.1
-bash-3.00$

このように,サーバ側にauthorized_keys2ファイルを置いていない状態でもうまく認証,接続できれば成功です。正常な場合の検索プロセスは次のようになります。

  1. sshサーバがユーザ名(sshuser)を受け取る
  2. LpkUserDNやLpkGroupDN以下からsshuserのエントリを検索
  3. もし見つかれば,sshPublicKey属性を取得し,その値を公開鍵として扱う
  4. あとは通常通り認証

うまくいかない場合はLDAPサーバのログと照らし合わせたり,sshd_configsyslog関連の設定を変更して試してみてください。その際のログはリスト4のようになります。filter="(&(objectClass=posixAccount)(objectClass=ldapPublicKey)(uid=sshuser))"という検索フィルタによって公開鍵情報が読み込まれていることがわかるはずです。

リスト4 LDAPによる公開鍵認証が成功した場合のログ

Nov 10 02:40:53 localhost slapd[31307]: conn=2 fd=10 ACCEPT from IP=10.0.100.11:32831 (IP=0.0.0.0:389) 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=0 BIND dn="" method=128 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=0 RESULT tag=97 err=0 text= 
Nov 10 02:40:53 localhost slapd[31307]: conn=3 fd=11 ACCEPT from IP=10.0.100.11:32832 (IP=0.0.0.0:389) 
Nov 10 02:40:53 localhost slapd[31307]: conn=3 op=0 BIND dn="" method=128 
Nov 10 02:40:53 localhost slapd[31307]: conn=3 op=0 RESULT tag=97 err=0 text= 
Nov 10 02:40:53 localhost slapd[31307]: conn=3 op=1 SRCH base="dc=example,dc=com" scope=2 deref=0 filter="(&(objectClass=shadowAccount)(uid=sshuser))" 
Nov 10 02:40:53 localhost slapd[31307]: conn=3 op=1 SRCH attr=uid userPassword shadowLastChange shadowMax shadowMin shadowWarning shadowInactive shadowExpire shadowFlag 
Nov 10 02:40:53 localhost slapd[31307]: conn=3 op=1 SEARCH RESULT tag=101 err=0 nentries=0 text= 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=1 SRCH base="ou=people,dc=example,dc=com" scope=2 deref=0 filter="(&(objectClass=posixAccount)(objectClass=ldapPublicKey)(uid=sshuser))" 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=1 SRCH attr=sshPublicKey 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=1 SEARCH RESULT tag=101 err=0 nentries=1 text= 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=2 SRCH base="ou=people,dc=example,dc=com" scope=2 deref=0 filter="(&(objectClass=posixAccount)(objectClass=ldapPublicKey)(uid=sshuser))" 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=2 SRCH attr=sshPublicKey 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=2 SEARCH RESULT tag=101 err=0 nentries=1 text= 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=3 SRCH base="ou=people,dc=example,dc=com" scope=2 deref=0 filter="(&(objectClass=posixAccount)(objectClass=ldapPublicKey)(uid=sshuser))" 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=3 SRCH attr=sshPublicKey 
Nov 10 02:40:53 localhost slapd[31307]: conn=2 op=3 SEARCH RESULT tag=101 err=0 nentries=1 text= 
Nov 10 02:40:58 localhost slapd[31307]: conn=2 op=4 SRCH base="ou=people,dc=example,dc=com" scope=2 deref=0 filter="(&(objectClass=posixAccount)(objectClass=ldapPublicKey)(uid=sshuser))" 
Nov 10 02:40:58 localhost slapd[31307]: conn=2 op=4 SRCH attr=sshPublicKey 
Nov 10 02:40:58 localhost slapd[31307]: conn=2 op=4 SEARCH RESULT tag=101 err=0 nentries=1 text= 
Nov 10 02:40:59 localhost slapd[31307]: conn=2 fd=10 closed 
Nov 10 02:40:59 localhost slapd[31307]: conn=3 fd=11 closed 

メンテナンス

公開鍵情報を1か所で管理できるのが今回の一番のメリットですが,SSHサーバとLDAPサーバ間のネットワークに障害が発生してしまった場合,公開鍵を参照できず,すべてのユーザがサーバにログインできない,という事態も考えられます。これに関しては途中の経路を冗長化させるなり,LDAPサーバをHAクラスタで運用することで回避できるのですが,定期的にLDAPサーバに接続し,公開鍵情報をファイルとしてダウンロードさせておくのもひとつの手でしょう。

ページの都合上,エラー処理などとくに行っておらず恐縮ですが,リスト5のスクリプトを参考にしてください。このスクリプトはNet::LDAPモジュールを利用して,authorized_keys2ファイルを自動的に作成します。

動作確認ができればcrontabなどに登録し,定期的にスクリプトを走らせるようにしてください。

リスト5 公開鍵ファイルを定期アップデートするためのスクリプト

#!/usr/bin/perl
use Net::LDAP;

$ldap = Net::LDAP->new ("localhost");
$rs = $ldap->search (base   => "dc=example,dc=com",
                     filter => "(&(homeDirectory=*)(sshPublicKey=*))");

@entries = $rs->entries;
foreach $entr ( @entries ) {
    $pubkey = $entr->get_value("sshPublicKey");
    $home = $entr->get_value("homeDirectory");
    $keyfile = "$home/.ssh/authorized_keys2";
    if ( -f $keyfile ) {
        print "updating $keyfile\n";
        open(OUT, ">$keyfile");
        print OUT "$pubkey\n";
        close(OUT);
    }
}

まとめ

今回のポイントは以下の通りです。

  • OpenSSHにLDAP認証用のパッチを当てる必要がある
  • 公開鍵用の情報は標準スキーマに登録されていないため独自で定義する

サーバ数が1台や2台など小規模な環境の場合,従来より構成が複雑になってしまい,かえってトラブルを招くこともあるかもしれませんが,大規模な環境には効果抜群です。

スキーマの追加方法などもわかりましたので,これからはさらにさまざまなソフトウェアをLDAP対応させることができますね!

著者プロフィール

中満英生(なかみつひでお)

大学時代に出会ったSolarisがきっかけでUNIXの世界へ。その後ホスティングプロバイダ,データセンターで実務経験を積む傍ら,雑誌記事の執筆や技術セミナーの講師を務める。サーバ設定の他,セキュリティに関する著作や技術者エッセイも執筆経験あり。