OpenLDAPをcache兼anonymous proxyとして使う方法

基本的には、 OpenLDAP documentationThe Proxy Cache Engine で説明されている設定に加えて、anonymous proxyとなるように設定するだけです。

slapdの設定 (slapd.conf)

# moduleload back_ldap
moduleload pcache

include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/nis.schema
# schema for MS ActiveDirectory
#  include /etc/openldap/schema/ad.schema

conn_max_pending 1000
#logfile /var/log/openldap/slapd.log
pidfile  /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
#
#
loglevel stats
sizelimit unlimited
limits * size.pr=0 size.prtotal=none

# anonymous readonly access
readonly on
access to * by * read

#
# LDAP proxy
#
database ldap
conn-ttl     3600
idle-timeout 600
suffix "dc=work,dc=hanabusa,dc=net"
rootdn "dc=work,dc=hanabusa,dc=net"
uri    "ldap://ldap1.work.hanabusa.net ldap://ldap2.work.hanabusa.net"
# use MS Active Directory global catalog
#  uri "ldap://ldap1.work.hanabusa.net:3268 ldap://ldap2.work.hanabusa.net:3268"

# auth with Kerberos
idassert-authzFrom dn.regex:.*
idassert-bind      bindmethod=SASL saslmech=GSSAPI mode=none

# cache config
overlay pcache
pcache          hdb 100000 1 1000 300
pcacheAttrset   0  c cn displayName mail member objectClass telephonenumber
#pcacheAttrset  0  c cn displayName mail member objectClass sAMAccountName sAMAccountType telephonenumber
pcacheTemplate  (cn=) 0 3600
#pcacheTemplate (sAMAccountName=) 0 3600
#pcacheTemplate (&(cn=)(sAMAccountName=)) 0 3600

# hdb config
dbnosync
cachesize  1000
index      objectClass eq
index      cn,sn,mail  pres,eq,sub
#index     sAMAccountName eq
#directory /var/lib/ldap/cache

Kerberos credentialを用意する

上記のslapd.confの設定は、domain controllerに対してLDAP接続する際に Kerberos認証を行うようにしています。 LDAP専用のuserを用意しても構いませんが、 Kerberosを使ったsingle sign on を行っていれば既にcomputer accountが発行されています。 このcomputer accountを使ってLDAPの認証を行ってみます。

まず、klistで/etc/krb5.keytabの中身を確認して、 computer accountが存在することを確認しましょう。 以下のようにklist -kを走らせると、WEBAPP$@WORK.HANABUSA.NET が存在することがわかります。 この hostname + $ のものがcomputer accountです。 (使っている暗号種類の数だけ同じ名前の行が出てきます)

# klist -k
2  host/webapp.hanabusa.net@WORK.HANABUSA.NET
...
2  host/webapp@WORK.HANABUSA.NET
...
2  WEBAPP$@WORK.HANABUSA.NET
...
2  HTTP/webapp@WORK.HANABUSA.NET
...
#

試しに、kinitを使ってcomputer accountに対する Kerberos TGT (Ticket Granting Ticket, 電子的な身分証明書みたいなもの) を取得してみます。 通常、kinitはpasswordを聞いてきますが、"-k" をつけると keytabに保存されている暗号鍵からTGTを生成するため、passwordは聞かれません。

# kinit -k -t /etc/krb5.keytab 'WEBAPP$@WORK.HANABUSA.NET'
#

klistで確かにTGTを取得できていることがわかります。 また、この状態でldapsearchを走らせると、passwordを聞かれずにdomain controllerの LDAP serverへ接続できることも確認できます。

# klist
Ticket cache: FILE:/var/lib/ldap/krb5cc_0
Default principal: WEBAPP$@WORK.HANABUSA.NET

Valid starting     Expires            Service principal
12/31/13 11:22:33  12/31/13 21:22:33  krbtgt/WORK.HANABUSA.NET@WORK.HANABUSA.NET
       renew until 12/31/13 21:22:33
...
# ldapsearch -h ldap1.work.hanabusa.net '(uid=myuid)'
...
#

以上のように /etc/krb5.keytab からTGTを作ってやれば、slapdは domain controllerのLDAP serverへ接続できるようになります。 ただしTGTは有効期限があるためcronなどで定期的に更新してやる必要があります。 例えばActive Directoryの標準は10時間ですので、それより短い間隔で更新します。 たいていの Linux distribution では /etc/cron.hourly に script file を置くと勝手に1時間ごとに実行してくれるので、これを使うのが手軽でしょう。

設定として、まず最初に slapd に対して環境変数 KRB5CCNAME で credential cache (TGTを保管するfile) の場所を指示してやります。 これは /etc/sysconfig/slapd (RHEL7系の場合) などに書いてやります。 cronでそのcredential cacheに対してTGTを取得するようにすればokです。 最後にOS起動時にもTGTを取得させるように、 /etc/rc.d/rc.localなど起動時に実行されるfileから cron scriptを呼び出すようにしておきます。

/etc/sysconfig/slapd (RHEL>=7)

KRB5CCNAME=/var/lib/ldap/krb5_cc_ldap
...

/etc/sysconfig/ldap (RHEL<=6)

export KRB5CCNAME=/var/lib/ldap/krb5_cc_ldap
...

/etc/cron.hourly/update_slapd_cc.sh

#!/bin/sh

# Load LDAP config (KRB5CCNAME)
source /etc/sysconfig/slapd
[ -z "${KRB5CCNAME}" ] || KRB5CCNAME=/var/lib/ldap/krb5_cc_ldap

# Obtain TGT and save it into new credential cache file ( ${KRB5CCNAME}.new )
if kinit -k -t /etc/krb5.keytab -c "${KRB5CCNAME}.new" 'WEBAPP$@WORK.HANABUSA.NET'; then

  # Change owner of credential cache to slapd run user
  chown ldap:ldap "${KRB5CCNAME}.new"

  mv "${KRB5CCNAME}.new" "${KRB5CCNAME}"
fi

/etc/rc.d/rc.local (distributionごと適切なfile)

...
/etc/cron.hourly/update_slapd_cc.sh
...

MicrosoftのActive DirectoryをLDAP serverとして使う場合

LDAP schema

OpenLDAPに含まれるschemaにはActive Directoryで使われている sAMAccountNameなどが含まれていないため、 標準設定のままでは (sAMAccountName=myaccount) のような問い合わせをしても 何も返ってきません。

Active Directory用のschemaを作る必要があるのですが、 1から調べてつくるとそれなりに大変なので、 LISM projectで公開されている ad.schema を使わせてもらいます。 ad.schema を /etc/openldap/schema へ保存して、slapd.confに以下を追記します。

include /etc/openldap/schema/ad.schema

複数のdomainが存在する場合

複数のdomainが存在する場合、基本的にはdomainごとにsuffixとuriを書くというのが正攻法のはずです。

# for work.hanabusa.net
database ldap
suffix   "dc=work,dc=hanabusa,dc=net"
uri      "ldap://ldap1.work.hanabusa.net/"
idassert-authzFrom dn.regex:.*
idassert-bind      bindmethod=SASL saslmech=GSSAPI mode=none
overlay pcache
...

# for hobby.hanabusa.net
database ldap
suffix   "dc=hobby,dc=hanabusa,dc=net"
uri      "ldap://ldap1.hobby.hanabusa.net"
idassert-authzFrom dn.regex:.*
idassert-bind      bindmethod=SASL saslmech=GSSAPI mode=none
overlay pcache
...

ただ、domainが多いと保守がめんどくさいこともあって、Active Directoryの場合は TCP 3268 の global catalog service を使うのが楽ちんでしょう。 TCP 3268 でLDAP問い合わせをするとすべてのdomainまとめて検索可能です。 以下のようにsuffixを"dc=hanabusa,dc=net"のみにして、 uriで3268を指定します。

# for *.hanabusa.net
database ldap
suffix   "dc=hanabusa,dc=net"
uri      "ldap://ldap1.work.hanabusa.net:3268"
idassert-authzFrom dn.regex:.*
idassert-bind      bindmethod=SASL saslmech=GSSAPI mode=none
overlay pcache
...

Test用のLDAP database作成

LDAP cacheを作るついでにapplication serverのtest用databaseも用意しておくと便利です。 slapd.confの末尾に以下を追記します。

## for test LDAP database
database   hdb
suffix     "dc=test,dc=hanabusa,dc=net"
directory  /var/lib/ldap/test
index      objectClass eq
index      cn,sn,mail  pres,eq,sub
#index     sAMAccountName eq

Test用dataの流し込み

# slapadd -s -f /etc/openldap/slapd.conf -b dc=test,dc=hanabusa,dc=net -l testusers.ldif
# chown -R ldap:ldap /var/lib/ldap/test

testusers.ldifには以下のような内容を書き込みます。

dn: dc=test,dc=hanabusa,dc=net
objectClass: dcObject
objectClass: organization
dc: test
o: test domain

dn: ou=testusers,dc=test,dc=hanabusa,dc=net
objectclass: organizationalUnit
ou: testusers

dn: cn=test01,ou=testusers,dc=test,dc=hanabusa,dc=net
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: test01
sn: test01
sAMAccountName: test01
displayName: Test User 01
mail: someone01@example.com
telephonenumber: 012-345-678
objectSid: 

dn: cn=test02,ou=testusers,dc=test,dc=hanabusa,dc=net
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: test02
sn: test02
sAMAccountName: test02
displayName: Test User 02
mail: someone02@example.com
telephonenumber: 012-345-678
objectSid: 

動作確認

ldapsearchで作成したtest01, test02 userを取得できれば正しく動いています。

$ ldapsearch -h localhost -b dc=test,dc=hanabusa,dc=net -x '(sAMAccountName=test01)'
...

参考情報


更新 : 2014-06-24
ご意見、ご感想は、花房 真広 <webmaster@hanabusa.net>まで。メールする前にtop pageの注意書を読んでください。