利用例1では一台のホストだけでLDAPを利用することを説明してきました。それではあえてLDAPを使うこともありませんが、LDAPを使うことで多数のホストで統一したアカウント情報を提供するようにすることができます。つまりNISのように複数のホストのアカウント情報を管理することができます。
LDAPはそもそもTCP/IP上のプロトコルなので、LDAPをネットワーク上で使うことは問題なくできます。ただし、LDAP上を流れる時はデータはそのまま流れるのでパケットダンプなどされるとパスワード情報なども簡単に盗み見されてしまいます。これはTLS(Transport Layer Security)/SSL(Secure Socket Layer)を使うようにすれば安全にネットワーク上にデータをやりとりできるようになります。最初は簡単のためにそのような危険のない安全なネットワーク上で複数のホストを管理する方法について説明します。
一番簡単な方法は一台のLDAPサーバを用意してそれを複数のクライアントで参照するようにすることです。そのためにはまずクライアント側すべてにnss_ldapやpam-ldapをインストールする必要があります。
# apt-get install libnss-ldap libpam-ldap Reading Package Lists... Done Building Dependency Tree... Done The following NEW packages will be installed: libnss-ldap libpam-ldap 0 packages upgraded, 2 newly installed, 0 to remove and 1 not upgraded. Need to get 0B/49.7kB of archives. After unpacking 125kB will be used. Selecting previously deselected package libnss-ldap. (Reading database ... 29754 files and directories currently installed.) Unpacking libnss-ldap (from .../libnss-ldap_122-1_i386.deb) ... Selecting previously deselected package libpam-ldap. Unpacking libpam-ldap (from .../libpam-ldap_43-2_i386.deb) ... Setting up libnss-ldap (122-1) ... Setting up libpam-ldap (43-2) ...
すべてのクライアントホストでLDAPサーバを参照するように/etc/libnss-ldap.confや/etc/libpam-ldap.confを設定します。ここでLDAPサーバのIPアドレスを192.168.0.1とするとリスト1およびリスト2のようになります。またrootbinddnで指定した識別名(DN)のパスワードを/etc/ldap.secretに書き、このファイルはルートが所有してパーミッションが0600(rootのみが読み書き可能)にしておきます。
# Your LDAP server. Must be resolvable without using LDAP. host 192.168.0.1 # The distinguished name of the search base. base dc=example,dc=jp rootbinddn cn=Manager,dc=example,dc=jp
# Your LDAP server. host 192.168.0.1 # The distinguished name of the search base. base dc=example,dc=jp rootbinddn cn=Manager,dc=example,dc=jp pam_crypt local # echo rootbinddnの識別名(DN)のパスワード > /etc/ldap.secret # chown root /etc/ldap.secret # chmod 0600 /etc/ldap.secret
さらに/etc/nsswitch.confでpasswdやgroup、shadowに対してldapを使うようにします(リスト3)。
# /etc/nsswitch.conf # # Example configuration of GNU Name Service Switch functionality. # If you have the `glibc-doc' and `info' packages installed, try: # `info libc "Name Service Switch"' for information about this file. passwd: compat ldap group: compat ldap shadow: compat ldap hosts: files dns networks: files protocols: files services: files ethers: files rpc: files netgroup: nis
またpasswd(1)でパスワードを変更できるようにPAMの設定をします(リスト4)。
password sufficient pam_ldap.so password required pam_unix.so nullok obscure min=4 max=8
ホームディレクトリやドットファイルも自動で作成されるように/etc/pam.d/loginや/etc/pam.d/sshにリスト5のような行を追加します。
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
これでリモートのLDAPサーバを利用してアカウントなどが作れるようになっています。
なお、このままでは情報が必要になるたびにLDAPサーバに聞きにいくためにあまりパフォーマンスが得られません。glibcのnscd(Name Service Cache Daemon)を使えばキャッシュしてくれるのである程度無駄な通信を減らすことができます。
# apt-get install nscd Reading Package Lists... Done Building Dependency Tree... Done The following NEW packages will be installed: nscd 0 packages upgraded, 1 newly installed, 0 to remove and 1 not upgraded. Need to get 35.8kB of archives. After unpacking 139kB will be used. Get:1 http://http.debian.or.jp potato/main nscd 2.1.3-18 [35.8kB] Fetched 35.8kB in 0s (182kB/s) Selecting previously deselected package nscd. (Reading database ... 29778 files and directories currently installed.) Unpacking nscd (from .../nscd_2.1.3-18_i386.deb) ... Setting up nscd (2.1.3-18) ... Stopping Name Service Cache Daemon: nscd. Starting Name Service Cache Daemon: nscd.
これでnscdが有効になります。もしnscdが変なキャッシュをもっていて誤動作しているような場合は/etc/init.d/nscd restartとしてnscdを再起動します。
一台のLDAPサーバでたくさんのクライアントを使うとLDAPサーバのパフォーマンスがボトルネックになってしまうことがあります。また、一台だけのLDAPサーバがダウンするとクライアント全部が使えなくなってしまうという問題もあります。
このような問題に対処するために、OpenLDAPではレプリカを作ることでサーバの複製を作ることができるようになっています。レプリカというのは複製のことで、これを使うことで複数のLDAPサーバで同じ情報を持つことができるようになります。レプリカを設定することで負荷分散ができますし、また非常時の時のバックアップにもなります。
OpenLDAPでレプリカを作る時は一つのslapdがマスターサーバとなり、その他のslapdがスレーブサーバとなります。更新はすべてマスターサーバでおこなわれ、更新がおこなわれるとその変更点はslurpdを使ってスレーブのslapdに送られます(図1)。
| slapd(master) slapd(slave) ldap client | <-- search -- | --- result --> | | <-- update -- | --- updateref-> | <-------------------update----------- | ---------------------OK-------------> | | | [slapd.replog] | | | v | slurpd ---(update)---> | <----OK-------
レプリカを設定するにはマスターサーバ、スレーブサーバ両方の設定が必要です。
まず、スレーブサーバ側でマスターサーバから送られてくる更新情報を書きこむための識別名(DN)を決めます。一番簡単なのはスレーブサーバ側でrootdn、rootpwを設定してそれを使うことですが、rootdnでなくても全てのエントリに書きこむ権限をもっている識別名(DN)ならどれを使っても構いません。
マスターサーバ側ではreplica行とreplogfile行を設定します。replica行のhostにスレーブサーバのホスト名を、binddnに先程きめたスレーブサーバ側で更新をおこなう識別名(DN)を、bindmethodにはsimple、credentialsにbinddnに指定した識別名(DN)のパスワードを設定します。replogfile行はslapdからslurpdにわたすファイルの名前です。このファイルにはパスワードなどの情報も含まれるので、アクセス権限がでていないディレクトリ以下に置くようにしておくべきです(リスト6)。
replica host=slave binddn="cn=replica,dc=example,dc=jp" bindmethod=simple credentials=パスワード replogfile /usr/local/var/openldap-slurp/slapd.replog
スレーブサーバ側では更新情報を書きこむ識別名(DN)の設定をおこないます。これはrootdnやrootpwを設定するかアクセス制御により全てのエントリに書きこめるような識別名(DN)を設定することでおこないます。そのように設定した識別名(DN)をupdatedn行に指定しておきます。またupdateref行に更新リクエストがきた時にマスターサーバへリダイレクトする設定をしておきます(リスト7)。
rootdn cn=replica,dc=example,dc=jp rootpw パスワード updatedn cn=replica,dc=example,dc=jp updateref ldap://ldap-master.example.jp/dc=example,dc=jp
このように設定したあと最初にマスターサーバの情報をスレーブサーバにコピーしておく必要があります。次のような手順でコピーします。
これでレプリカとして動かすことができます。このようにしておけばマスターサーバでもスレーブサーバでもLDAPサーバと指定すれば同じ情報を得ることができます。マスターサーバが更新されればレプリカの設定によりその情報はスレーブに伝えられるので、マスターでもスレーブでも同じ情報を持つようになっています。
ファイアウォールでまもられたLAN環境でならこのような運用でもNISと同じような感じで使えるのでほぼ問題ないはずです。ただし、このままではパスワードなども平文のままネットワーク上をやりとりされるので安全ではありません。ユーザのパスワードもrootbinddnのパスワードも簡単に盗みみることができてしまいます。従って、完全に信頼できるネットワークでなければLDAPの経路のセキュリティを確保する必要があります。これにはいくつかの方法があります。
一番、簡単にできるのがこれでしょう。sshのポートフォワーディングを使えばその経路を簡単に暗号化することができます。この方法ならばTLS/SSLをサポートしていないOpenLDAP 1.2.x系のホストが残っていても同様に対処することができるというメリットがあります。
クライアント側からサーバ側にsshでトンネルをはりにいくような方法は以下のようにします。
sshでトンネルをはるためのユーザを決めます。このためのユーザを作ってもいいでしょう。SSH-1の場合そのユーザのRSA鍵を作ります。トンネルをはるのはスクリプトから起動することになるのでパスフレーズ(passphrase)は空にしておきます。これで~/.ssh/identityと~/.ssh/identity.pubができています。
# adduser --system ldap Adding system user ldap... Stopping Name Service Cache Daemon: nscd. Adding new user ldap (102) with group nogroup. Starting Name Service Cache Daemon: nscd. Creating home directory /home/ldap. # cd /home/ldap # sudo -u ldap -s % ssh-keygen -C ldap@client Generating RSA keys: .............oooooO.....oooooO Key generation complete. Enter file in which to save the key (/home/ldap/.ssh/identity): Created directory '/home/ldap/.ssh'. Enter passphrase (empty for no passphrase): Your identification has been saved in /home/ldap/.ssh/identity. Your public key has been saved in /home/ldap/.ssh/identity.pub. The key fingerprint is: 1024 55:24:10:4f:b8:ba:33:5b:d0:d2:13:fe:fb:7c:e7:5b ldap@earlgrey
サーバ側も同様にユーザを作り~/.sshディレクトリを作ります。なおシェルが/bin/falseだとsshで接続できてもコマンドが実行できないので/bin/shにしておきます。
# adduser --system ldap Adding system user ldap... Adding new user ldap (105) with group nogroup. Creating home directory /home/ldap. # mkdir /home/ldap/.ssh # chown ldap /home/ldap/.ssh # chsh ldap Changing the login shell for ldap Enter the new value, or press return for the default Login Shell [/bin/false]: /bin/sh
そこにクライアント側で作成した~/.ssh/identity.pubをサーバ側の~/.ssh/authorized_keysとして置きます。複数クライアントがある場合は~/.ssh/authorized_keysに追加していくことになります。この際、必要ないコマンドなどが実行されないようにリスト8のようにオプションをつけておきます。
no-X11-forwarding,no-agent-forwarding,command="sleep 365d" 1024 35 122034260334159733787263796718142619865194367063834800630383047290005947883966563027618745261171454338973720150940511165189629457659805971864894449394036935584524788337405828807714614108951301214443859164612816772096509669051022267827621270699152318164600590897529790281724040207400184500785876614545050298813 ldap@client
これでクライアント側からサーバ側にsshセッションがはれるようになっているはずです。
% ssh ldap@server The authenticity of host '192.168.0.1' can't be established. Key fingerprint is 1024 65:7b:2f:7b:4e:cb:fa:5f:ff:ad:94:5e:b4:5a:30:6c. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '211.123.26.5' to the list of known hosts.
うまくいけばcommandで指定したsleep 365dがサーバ側で動いているはずでこのまま止まるはずです。Ctrl-Cでとめます。うまくいくのが確かめられれば以下のコマンドを実行します。
% ssh -f -L 10389:localhost:389 ldap@server
これでバックグラウンドでトンネルセッションがはられます。このようにするとクライアント側のポート10389にアクセスしにいくとサーバ側のポート389(つまりldap)につながることになります。試しに次のようにして検索してみましょう。
% ldapsearch -x -h localhost -p 10389 -b 'dc=example,dc=jp' 'uid=*'
これでクライアントのポート10389からサーバのポート389への経路はSSHで暗号化されるので、libnss-ldap.confやpam_ldap.confの設定をhostとして127.0.0.1、portに10389を使うように修正すれば(リスト9、リスト10)LDAPのやりとりがのぞきみされることはなくなります。
# Your LDAP server. Must be resolvable without using LDAP. host 127.0.0.1 port 10389 # The distinguished name of the search base. base dc=example,dc=jp rootbinddn cn=Manager,dc=example,dc=jp
# Your LDAP server. host 127.0.0.1 port 10389 # The distinguished name of the search base. base dc=example,dc=jp rootbinddn cn=Manager,dc=example,dc=jp pam_crypt local
SSH-2の場合は~/.ssh/identityおよび~/.ssh/identity.pubのかわりに~/.ssh/id_dsaおよび~/.ssh/id_dsa.pubを作成します。
% ssh-keygen -t dsa -C ldap@client Generating public/private dsa key pair. Enter file in which to save the key (/home/ldap/.ssh/id_dsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/ldap/.ssh/id_dsa. Your public key has been saved in /home/ldap/.ssh/id_dsa.pub. The key fingerprint is: 89:7a:e0:cb:a2:8d:8f:93:2e:f8:76:e5:d9:04:d3:6f ldap@client
このようにしてできた~/.ssh/id_dsa.pubをSSH-2でログインする先の~/.sshにauthorized_keys2に追加していきます。SSH-1の~/.ssh/identity.pubがSSH-2では~/.ssh/id_dsa.pubに、SSH-1の~/.ssh/authorized_keysがSSH-2では~/.ssh/authorized_keys2になっているとみなせばあとは同じように使うことができます。リスト8で設定したようなcommandなどの鍵のオプションは行頭に追加します(リスト11)。
no-X11-forwarding,no-agent-forwarding,command="sleep 1d" ssh-dss AAAAB3NzaC1kc3MAAACBAMZARb1hnqnHhl4qpGTLiz7Z+EiimOMNQUGu+vs7cqjSfGeAWBxvrGKyUh6Wj/XeeQQuIyG16diHgTYw0UX64O4bvFaVKJy3URpDA1ipRkLR53+FypiVu+lkaDAhfleK7k8hPzMoE0dkkBQgWKe3Wep0U/tIpV/RPBfq6/jx+vPBAAAAFQC2xjLbWNH3qTEoEX9GefvboB5KoQAAAIEAjQJRSj5NEOl3qRKksl7utX15cZsoqLqGmYP0hakOJfZeAIcmfUbFqLDIFCujU00p4uneM7cFPpcTJ5rx/TAswUfCfjhE10Opn0IR8vq2ADduRvJsdXYBkor6qu6DvgZz5UrJcVOpJO958/kJ6Jgdkqyc6nNV0K1d5OEUuMyJ31sAAACAGQvqK/T8hK6HCziefARytvQl6sPv/z4y5FYoIAekOptT/AqxUF+weqtwTsko4G2WnqAooY/R4pK7M08NraeyFvNnltDwnbXL7JHcqe4ewB8HDH3GH1ywK8hzieT/Wra/GDZK7dMUm62DoztvxPAjGCpzQ57PGWyiKotoLz86mIg= ldap@client
OpenLDAP 2.0.x(LDAPv3)ならばSSL/TLS(Secure Socket Layer/Transport Layer Security)を使えばセキュアな通信経路を確立することができます。OpenLDAP 2.0.xでSSL/TLSを使うためにはOpenLDAP 2.0.xをconfigureする時に、OpenSSLのヘッダやライブラリがみつかるようにしておく必要があります。configureはこれらを見つけると自動的に--with-tlsを指定した時と同じようにSSL/TLSの機能を組みこんでくれます。
OpenLDAPでSSL/TLSを使うためにはopensslを使って設定する必要があります。ここではdemoCAを使った簡単な設定の仕方だけを紹介しておきます。
Debianではopensslパッケージをインストールします。
# apt-get install openssl Reading Package Lists... Done Building Dependency Tree... Done The following NEW packages will be installed: openssl 0 packages upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Need to get 282kB of archives. After unpacking 466kB will be used. Get:1 http://http.debian.or.jp stable/non-US/main openssl 0.9.4-5 [282kB] Fetched 282kB in 0s (1901kB/s) Selecting previously deselected package openssl. (Reading database ... 7968 files and directories currently installed.) Unpacking openssl (from .../openssl_0.9.4-5_i386.deb) ... Creating directory /etc/ssl Setting up openssl (0.9.4-5) ...
このパッケージには/usr/lib/ssl/misc/CA.plというスクリプトが含まれています。これでまずローカル用のCA(Certificate Authority/認証局)を作ります。
# cd /etc/ssl # /usr/lib/ssl/misc/CA.pl -newca CA certificate filename (or enter to create) [リターン] Making CA certificate ... Using configuration from /usr/lib/ssl/openssl.cnf Generating a 1024 bit RSA private key .................++++++ ....................................++++++ writing new private key to './demoCA/private/cakey.pem' Enter PEM pass phrase:[認証局のパスワード] Verifying password - Enter PEM pass phrase:[認証局のパスワード] ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:JP State or Province Name (full name) [Some-State]:Tokyo Locality Name (eg, city) []:Suginami Organization Name (eg, company) [Internet Widgits Pty Ltd]:example.jp Organizational Unit Name (eg, section) []: Common Name (eg, YOUR name) []:CA Email Address []:ca@example.jp # ls certs/ demoCA/ openssl.cnf private/
これで demoCAというのが作成されます。ここで次のようなsymlinkをはっておきます。
# pwd /etc/ssl # cd demoCA # ln -s /etc/ssl/demoCA/cacert.pem /etc/ssl/demoCA/`openssl x509 -noout -hash < ./cacert.pem`.0 # ls cacert.pem certs/ crl/ ea0cd014.0@ index.txt newcerts/ private/ serial
次にLDAPの設定ファイルのあるディレクトリにうつり、鍵を作成します。ここでCommon Nameには、slapdを動かすホスト名(クライアントがサーバに指定するホスト名)と一致させておく必要があるのに注意してください。これが一致しないとSSL/TLSのコネクションを確立できません。
# cd /usr/local/etc/openldap # mkdir cert # cd cert # openssl req -new -nodes -keyout key.pem -out newreq.pem Using configuration from /usr/lib/ssl/openssl.cnf Generating a 1024 bit RSA private key ...............................................................++++++ ...................................++++++ writing new private key to 'key.pem' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:JP State or Province Name (full name) [Some-State]:Tokyo Locality Name (eg, city) []:Suginami Organization Name (eg, company) [Internet Widgits Pty Ltd]:example.jp Organizational Unit Name (eg, section) []: Common Name (eg, YOUR name) []:ldap.example.jp Email Address []:ldap@example.jp Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:[リターン] An optional company name []:[リターン] # ls key.pem newreq.pem
このようにしてできたnewreq.pemは次のようにopensslを使うと中身を確認することができます。
# openssl req -in newreq.pem -text
次にこのnewreq.pemをdemoCAで認証します。
# cd /etc/ssl # openssl ca -policy policy_match -out newcert.pem -infiles /usr/local/etc/openldap/cert/newreq.pem Using configuration from /usr/lib/ssl/openssl.cnf Enter PEM pass phrase:[認証局のパスワード] Check that the request matches the signature Signature ok The Subjects Distinguished Name is as follows countryName :PRINTABLE:'JP' stateOrProvinceName :PRINTABLE:'Tokyo' localityName :PRINTABLE:'Suginami' organizationName :PRINTABLE:'example.jp' commonName :PRINTABLE:'ldap.example.jp' emailAddress :IA5STRING:'ldap@example.jp' Certificate is to be certified until Nov 10 18:00:09 2002 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated # ls certs/ demoCA/ lib/ newcert.pem openssl.cnf private/
以上で認証された鍵newcert.pemができました。これもopensslをつかって中身を見ることができます。
# openssl x509 -in newcert.pem -text
このようにしてできたnewcert.pemをOpenLDAPの管理ディレクトリに置きます。
# mv newcert.pem /usr/local/etc/openldap/cert # cd /usr/local/etc/openldap/cert/ # ls key.pem newcert.pem newreq.pem
このnewcert.pemが正しいものかどうかは次のようにして確認できます。
# openssl verify -CApath /etc/ssl/demoCA/ newcert.pem newcert.pem: OK
後はこれらをslapd.confに設定すればいいだけです(リスト12)。
TLSCipherSuite HIGH:MEDIUM:+SSLv2 TLSCertificateFile /usr/local/etc/openldap/cert/newcert.pem TLSCertificateKeyFile /usr/local/etc/openldap/cert/key.pem
ちなみにTLSCipherSuiteで指定したものでどのような暗号が使われるかもopensslコマンドで調べることができます。
# openssl ciphers -v HIGH:MEDIUM:+SSLv2
slapd.confを変更したらslapdを再起動します。次のように起動するとldaps://というURLでアクセスできるようになります。
# /usr/local/libexec/slapd -h "ldap:/// ldaps:///"
このように起動しておくと次のようにしてldapsで接続できます。
% ldapsearch -x -H ldaps://ldap.example.jp/ -b 'dc=example,dc=jp' 'uid=*'
ここでldaps URLのホスト名の部分は、サーバのホスト名でかつnewreq.pemを作った時のcommonNameでなければなりません。
slapdを起動する時に -hオプションをつけていなくてもslapd.confにTLSの設定がしてあればStartTLSリクエストを出して接続することもできます。StartTLSリクエストは-Zオプションで有効になります。この時も-hで指定するサーバのホスト名とnewpem.pemを作った時のcommonNameは一致している必要があります。StartTLSを使い場合はポートはldapsポート(636)ではなくてデフォルトのldap(389)を使い最初にTLSが使えるかどうかのネゴシエーションをしてからTLSを使った通信を開始します。
% ldapsearch -x -h ldap.example.jp -Z -b 'dc=example,dc=jp' 'uid=*'
また、-Zオプションの場合StartTLSリクエストが拒否されると通常の接続をこころみますが、-ZZオプションを使うとStartTLSリクエストが拒否されると接続に失敗することになります。セキュアなコネクション以外で継いでは問題ある場合はこちらを使った方がいいでしょう。
% ldapsearch -x -h ldap.example.jp -ZZ -b 'dc=example,dc=jp' 'uid=*'
Debianのlibnss-ldapでは--disable-sslされてビルドされているのでこのままでは使えません。--enable-sslしてビルドしたlibnss-ldapを使う必要があります。またpotatoのlibnss-ldap自体はかなり古いためにsidのlibnss-ldapのソースをもってきてリビルドした方がいいでしょう。そのようなlibnss-ldapを作ればリスト13のようなlibnss-ldap.confにするとldapsを使うようになるのでセキュアな通信路を使ってLDAPのやりとりができます。libpam-ldapも同様に--disable-sslされているために--enable-sslにしたlibpam-ldapが必要になります。
# Your LDAP server. Must be resolvable without using LDAP. uri ldaps://ldap.example.jp/ # The distinguished name of the search base. base dc=example,dc=jp rootbinddn cn=Manager,dc=example,dc=jp