funini.com 自由研究 LDAP

LDAP on Debian

Debianクラスターのユーザー管理のためにLDAPを使うことになりました。
前にVineでさんざんはまってるから今回も…と思ったらやっぱりはまりました。 LDAPまわりが面倒な原因は、 あたりでしょうか。とても嫌です。
Debianユーザーの方は、このマニュアルを上から順に丁寧に真似れば動くと思います。

LDAP入門 (ldif)

ldapでは、全部の要素は「オブジェクト」として管理されています。 オブジェクトは何行かのテキストで定義されていて、dn=ではじまる最初の一行で識別できます。
例えばこんな感じ。
dn: uid=kei,ou=People,o=funini
uid: kei
userPassword: (ひみつ)
loginShell: /bin/tcsh
homeDirectory: /home/kei
objectClass: posixAccount
...
これはどういう風に読むかというと… で、それぞれのou=Peopleとかo=funiniとかが別に定義されています。 あと、ouとかoとかは「オブジェクトを構成する要素」として存在していないといけない。
dn:の次の行からはじまるのは、実際の属性です。(パスワードとか) 子オブジェクトは親オブジェクトが持っている属性を引き継ぎます。 また、objectClass:という行で、その他のオブジェクトを継承することができます。 例えばここではposixAccountというのを引き継いでいます。 posixAccountというobjectClassには、ホームディレクトリの場所とかユーザーIDとかシェルとかの情報が 定義されていて、このuid=keiというオブジェクトもその中身がちゃんと埋められていなければなりません。 そうすることで、このオブジェクトをunixのログイン情報として使えるようになります。
こういう風にオブジェクトの関係をテキストファイルに書いたのを、ldifと呼びます。冗長ではあるけど、XMLよりは書きやすいでしょう。LDAPに入っているのは、こういうたくさんのldifで書かれたオブジェクトです。

認証までの道のり

色々と混乱しやすいので、ここでは「どのパッケージが何をするものか」簡単にまとめます。これら全てを正しく設定して、はじめて認証が成功します。
slapd
LDAPはデータベースで、サーバーとクライアントがあります。通常はサーバーは一台、クライアントはたくさんになるでしょう。Debianの場合、サーバーにはslapdというパッケージに入っていて、サーバーを操作するコマンドは「slapなんとか」という名前です。これらのコマンドは直接ファイルを操作するため、原則サーバーが動いているマシンで、サーバーが停止している時のみ用いることができます。
サーバーを操作する時には、LDAPのパスワードは必要ありません。設定ファイルは/etc/slapd.confです。データベースの実体は/var/lib/ldapにあるので、これらのファイルをクリアすれば、データベースを初期化できます。(その場合の動作の保証はしませんが…)
よく使うコマンドはこんな感じです。
ldap-utils
サーバーがあるマシンにおいてでも、サーバー自体を直接いじることはあまりなくて、通常はldapのクライアントを介して操作します。これはldap-utilsというパッケージに入っています。コマンド名はldapaddやldapdeleteなどといった、「ldapなんとか」となっています。これらのクライアントの設定ファイルは/etc/ldap/ldap.confです。
nss-ldap
LDAPを使うのは、ログインとかSSHとかsuの認証です。これらでLDAPを用いるのに用いられる基本的な方法は、このnss-ldapを用いる方法です。nss-ldapを導入すると、nsswitch.confでldapというオプションを用いることができます。nsswitch.confは認証を切り替える最も基本的なファイルで、nisの設定は主にここで行います。特にデーモンなどは立っていないので、設定の変更は即座に反映されます。nss-ldap自体の設定ファイルは/etc/libnss-ldap.confです。
一つ注意する点は、この方法を用いる場合には、ldifのユーザー情報のパスワードの欄がCRYPT形式になっていなければならない点です。このため、nss-ldap単独で認証を行うのは希で、通常はlibnss-ldapに加えてlibpam-ldapを用いて認証を行います。ただ、この方法はlibpam-ldapよりはまりどころが少ないので、サーバーがちゃんと動いていることの確認として一度試してみるといいかもしれません。
libpam-ldap
PAMは、Linuxの新しい認証システムです。設定は/etc/pam.dにあり、様々な認証ポリシーを適用することができます。sshやsuといったソフトも、基本的にpamに対応しています。PAMを用いる設定では、nsswitch.confよりきめ細かい設定が出来ます。自由度が高い分、はまりどころも多くなっています。なお、これも設定は即座に反映されます。
libpam-ldapパッケージは、pamで用いることができる、LDAP用の認証モジュールです。設定ファイルは/etc/pam_ldap.confです。(他のDistributionでは/etc/ldap.confとなっているものもあります) 実際にpamに組み込む設定は、/etc/pam.d以下で行います。各ソフト共通の設定は/etc/pam.d/common-authと/etc/pam.d/common-accountに書かれているので、これらにpam_ldapを記述するのが普通の方法でしょう。

LDAPサーバーを立てる

debianでは、パッケージのインストール時に様々な設定が対話的に行われます。慣れるまでは、一度変な設定をするとどこが書き換えられるのか分からなくて、けっこう困ります。一応dpkg-reconfigure (パッケージ名)で呼び出せますが、一つずつ設定ファイルを自分で書くのがおすすめです。
slapd
aptでさくっとインストール。
# apt-get install slapd
slapd.confを書きます。
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema

schemacheck     on
pidfile         /var/run/slapd/slapd.pid
argsfile        /var/run/slapd/slapd.args
loglevel        0
modulepath	/usr/lib/ldap
moduleload	back_bdb
sizelimit 500
tool-threads 1

backend		bdb
checkpoint 512 30
database        bdb

suffix          "o=santa"
rootdn          "cn=root,o=santa"
rootpw		{CRYPT}m66BJOZilrzn2

directory       "/var/lib/ldap"

dbconfig set_cachesize 0 2097152 0

dbconfig set_lk_max_objects 1500
dbconfig set_lk_max_locks 1500
dbconfig set_lk_max_lockers 1500
index           objectClass eq
lastmod         on

access to attrs=userPassword,shadowLastChange
        by dn="cn=admin,o=santa" write
        by anonymous auth
        by self write
        by * none

access to dn.base="" by * read

access to *
        by dn="cn=admin,o=santa" write
        by * read
だらだら長いですが、標準設定から書き換えたのはオレンジ色のとこだけです。
suffixは、このLDAPサーバーに入るオブジェクト全てが継承するオブジェクト(ルートオブジェクト)です。通常はドメイン名(dc=なんとか、の繰り返し)を用いるようですが、今回は簡単にo=santaという風にo(organization)を用いました。これは各自に環境で変えましょう。
データベースには、全てのデータを扱うことができるrootアカウントが必要です。他のユーザーはLDAPの中に書きますが、rootだけはslapd.confに書きます。(そうでないとサーバーに追加できるユーザーがいないから) rootpwは平文でもOKですが、実際運用するときはこのようにCRYPT暗号化(ハッシュ化)しましょう。このCRYPT化したパスワードの作り方は、
$ slappasswd -h {CRYPT}
New password : (パスワードを入力)
とするとよいです。たぶんMD5も使えます。
それと別に、パスワードまわりを扱える(パスワード変更とか)アカウントを作っておくのが普通みたいです。ここではcn=admin,o=santaとしました。このアカウントのパスワードはこの設定ファイルに書くのではなく、LDAP内のオブジェクトとして作ります。
Debianのapt(dpkg)はインストール時に色々質問して、ルートオブジェクトとルートユーザー名を作ってくれて、LDAPサーバーも立ち上げてくれるようです。でも僕はその後でルートオブジェクトとかを変えてしまったので、LDAPに追加しなければいけません。そこで一度LDAPを止めて、新しいルートオブジェクト(ほか)を作成します。
# /etc/init.d/slapd stop
入れるldifはこんな感じ。
init.ldif
dn:o=santa
objectClass: organization
o:santa

dn: cn=admin,o=santa
objectClass: person
cn: admin
sn: admin
userPassword: {CRYPT}12I1Q4IqrllgM
今はサーバーが止まっているので、slapaddで追加できます。
# slapadd < init.ldif
slapcatで確認しましょう。追加したのと同じオブジェクトが入っていればOKです。
# slapcat
...
良さそうなら、LDAPサーバーを立ち上げます。
# /etc/init.d/slapd start
ldap-utils
次にコマンドラインでLDAPを操作するための、LDAPクライアントをインストールします。
# apt-get install ldap-utils
こっちも設定しちゃいましょう。設定ファイルは/etc/ldap/ldap.confです。
BASE	o=santa
HOST	127.0.0.1
SSL経由とか、ポートを指定したい時はHOSTの代わりにURIを設定します。
これで設定はおしまいです。
エントリ作ったり消したり。
ldapaddとかldapdelete, ldapsearchを使って、オブジェクト作ったり消したりしてみましょう。(この節は飛ばしてもOKです)
まずは追加。slapaddとは違って、動いているサーバーに対して行います。LDAPプロトコルを用いるので、rootとかadminとかで認証する必要があります。
ユーザーkeiをkei.ldifファイルに書いてみます。
dn: uid=mai,ou=People,o=santa
uid: kei
cn:  kei
objectClass: posixAccount
objectClass: posixGroup
userPassword: hoge
loginShell: /bin/tcsh
uidNumber: 10001
gidNumber: 10001
homeDirectory: /tmp
これを追加します。
$ ldapadd -D "cn=root,o=santa" -v -x -W -f ~/kei.ldif 
検索してみます。
$ ldapsearch -C -x -D "cn=admin,o=santa" -W "uid=kei,ou=People,o=santa"
...
# kei, People, funini
dn: uid=kei,ou=People,o=santa
uid: kei
...
消してみます。
$ ldapdelete -D"cn=root,o=santa" -v -x -W  "uid=kei,ou=People,o=santa"


☆以下のようなエラーが出たときは、ホストを探せてません。
ldap_bind: Can't contact LDAP server (81)
まずはサーバーが立ち上がっているか確認して、さらに/etc/openldap/ldap.confでホストの設定を確認するか、ホスト名を-hで指定しましょう。-h localhostみたいに。

☆ldapはデータベースで、対話式にデータを足したり消したりできます。 一度ファイルに書き出した場合はコマンドラインから操作する方が楽ですが、 いくつかGUIツールもあって、そっちの方がわかりやすいです。
GUIツールとしては以下のものを紹介しておきます。

認証の設定をする

まずはlibnss(nsswitch)を用いた設定を書いて、そのあとlibpam(pam)を用いた設定を書きます。libnssだけでは色々不便な点があるので、おそらくlibpamを用いることになるでしょう。
認証に用いることができるエントリ
認証ですが、posixAccountを継承すれば基本的に認証に用いることができます。 ベースdnがo=santaの場合、
dn: uid=kei,ou=People,o=santa
uid: kei
objectClass: posixAccount
...
というエントリを書くと、認証できるようになります。
これはposixAccountを継承しなくちゃいけないので、色々と必要になるエントリがあります。全部書くとこんな感じ。
dn:uid=kei,ou=People,o=santa
uid: kei
cn: Kei Takahashi
objectClass: account
objectClass: posixAccount
objectClass: top
userPassword: hogehoge
loginShell: /bin/bash
uidNumber: 10001
gidNumber: 10001
homeDirectory: /tmp
Debianでは、keiというユーザーはkeiというグループに属することになっています。 そのためにはposixGroupに対応するエントリも作らないといけないんですが、以下のように書くと一つのエントリでユーザーとグループが出来ます。
dn: uid=kei,ou=People,o=santa
uid: kei
cn:  kei
objectClass: posixAccount
objectClass: posixGroup
userPassword: hoge
loginShell: /bin/tcsh
uidNumber: 10001
gidNumber: 10001
homeDirectory: /tmp
ここでちょっと問題になるのがパスワードです。パスワードには平文、MD5、Cryptなどが使えますが、SambaやApopと連携させるには、平文のパスワードを用いる必要があります。一方、libnss-ldapを用いて認証を行うには、ここにしCrypt化したパスワードを書く必要があります。平文でパスワードを入力した場合、LDAPのパスワードが漏れた場合、全てのユーザーの平文パスワードが盗まれてしまうので、注意して下さい。
先ほども書きましたが、crypt化したパスワードを作るには、slappasswdコマンドを用います。
$ slappasswd -h {CRYPT}
New password : (パスワードを入力)

なお、Sambaを用いる場合は、smbldap-toolsを用いるのがすごく楽です。 エントリを作ったり、パスワード変更したりとか、ldifを書くことなく、コマンドだけでできます。これについては(vineについての情報ですが)ここにあります。
nss-ldap
ここからいよいよ認証に用いる設定です。まずはインストール。
# apt-get install libnss-ldap
設定ファイル書きます。
/etc/libnss-ldap.conf
base o=santa
uri ldap://127.0.0.1/
ldap_version 3
rootbinddn cn=admin,o=santa
あと、adminのパスワードを/etc/libnss-ldap.secretに(平文で)書きます。 これのパーミッションは400にします。

これが終わったら、nsswitch.confを書き換えます。
/etc/nsswitch.conf
passwd:         compat ldap
group:          compat ldap
shadow:         compat ldap
これで認証の準備は出来ました。
先ほども書いたとおり、エントリのパスワードがCryptで暗号化されていれば、ログインに用いることができます。コンソールやsu, sshなどで試してみて下さい。
pam-ldap
では本命のPAMを用いた設定です。なお、libpam-ldapだけで認証を行うことはできません。必ず先にlibnss-ldapをインストールし、正しく設定した後でここに進みましょう。
(そういう意味で、先ほどのcryptパスワード + nsswitch.confを用いたログインをしてみるのをおすすめします)

まずはインストール。
# apt-get install libpam-ldap
次に、/etc/pam_ldap.confを設定します。
/etc/pam_ldap.conf
host 127.0.0.1
base o=santa
ldap_version 3
rootbinddn cn=admin,o=santa
さらに、/etc/pam.d/common-*を編集します。これらは、/etc/pam.d/以下の各アプリケーションについての設定に自動的に挿入(include)されます。
/etc/pam.d/common-auth
auth	sufficient	pam_ldap.so
auth	required	pam_unix.so nullok_secure
/etc/pam.d/common-account
auth	sufficient	pam_ldap.so
account	required	pam_unix.so
終わったら、suとかssh localhostとかで実験してみましょう。

遠隔ホストからの認証

離れたホストからの認証を受け付ける時に、平文のパスワードが流れるのではいかにもまずいので、暗号化をする必要があります。このためには の二つがあります。
(…でも方法まだ調べてません。たぶんフラグをいくつか立てるだけでいいと思うんだけど。)