nss_ldap
や courier-authlib の authldap で
ActiveDirectoryを参照していると、以下のような一見不要なDNS問い合わせが
大量に発生し、
Feb 8 10:15:29 hostname named[3184]: client 172.16.0.1#33596: query: ForestDnsZones.ad.example.jp IN AAAA Feb 8 10:15:29 hostname named[3184]: client 172.16.0.1#33596: query: ForestDnsZones.ad.example.jp IN A Feb 8 10:15:29 hostname named[3184]: client 172.16.0.1#33596: query: DomainDnsZones.ad.example.jp IN AAAA Feb 8 10:15:29 hostname named[3184]: client 172.16.0.1#33596: query: DomainDnsZones.ad.example.jp IN A Feb 8 10:15:29 hostname named[3184]: client 172.16.0.1#33596: query: ad.example.jp IN AAAA Feb 8 10:15:29 hostname named[3184]: client 172.16.0.1#33596: query: ad.example.jp IN Aさらにこれらのアドレスが解決できない場合 (Windows系とUNIX系のDNSを分離している等)、 解決できないLDAP問い合わせが発生して長時間待たされたり、 設定は間違っていないのにアカウントが索けない、場合があります。
$Keywords: nss_ldap, ActiveDirectory, OpenLDAP, chase referrals, ForestDnsZones, DomainDnsZones, courier-authlib, spurious DNS query, nss_ldap slow $
$Id: ForestDnsZones-ldap.html,v 1.4 2011-03-10 20:33:31+09 kabe Exp $
たとえば ActiveDirectory 側で "ad.example.jp" ドメインをこしらえると、 アカウントは LDAP的には CN=Users,DC=ad,DC=example,DC=jp 以下に格納されます。
OUを自分で作ると OU=uchi_no_ou,DC=ad,DC=example,DC=jp になるのが普通なので、
両方を参照したい場合は、LDAP問合せの BASEDN 設定は 最上位の "DC=ad,DC=example,DC=jp" (CN=Usersなし) にするのが普通です。
[-] DC=ad,DC=example,DC=jp | r--[+] CN=Builtin r--[+] OU=uchi_no_ou r--[+] CN=Users
で、このBASEDNが最上位の設定で ActiveDirectoryに訊くと、
以下のように ref:
の参照がくっついてきます。
CN=Users をつけると、くっついてきません。
% ldapsearch -x -D 'CN=ldapbind,CN=Users,DC=ad,DC=example,DC=jp' -w 'passwd' -H ldap://activedirectory/ '(CN=user)' # extended LDIF # # LDAPv3 # base <> with scope sub .... # search reference ref: ldap://ForestDnsZones.ad.example.jp/DC=ForestDnsZones,DC=ad,DC=example,DC=jp # search reference ref: ldap://DomainDnsZones.ad.example.jp/DC=DomainDnsZones,DC=ad,DC=example,DC=jp # search reference ref: ldap://ad.example.jp/CN=Configuration,DC=ad,DC=example,DC=jp
LDAPライブラリは、ref:があった場合には順次 ldap://ForestDnsZones/ にも 問合せをしようとするので、
なお、冒頭で例示したDNSのログは named(8) のものですが、 通常の設定ではDNS queryのログは残りません。(量が多いから。) 見たい場合はnamedの設定を変えます。
nss_ldap.confに "referrals no" を追加します。 マニュアルには記載が無い (というかマニュアルが無い) ですが、 nss_ldap のChangeLog には書いてあったりします。 以下のように nss_ldap.conf を加工してみたり。
nss_ldap.conf: ... # Without CN=Users, it will make AD return referral to # ldap://ForestDnsZones.ad.example.jp/ # ldap://DomainDnsZones.ad.example.jp/ # ldap://ad.example.jp/ # which LDAP client tries to bind and wait for bind_timelimit timeout. # To eliminate referral timeout, do one of: # - make dummy entry in /etc/hosts: "0.0.0.1 ForestDnsZones.ad.example.jp" # - make DNS return nothing for "ForestDnsZones.ad.example.jp" # (you need DNS other than the ActiveDirectory) # - disable referrral tracking in ldap library/nss_ldap.conf as deref never referrals no ...
注: Red Hat 系では /usr/local/etc/nss_ldap.conf ではなく /etc/ldap.conf になっています。
Courier-IMAP + courier-authlib + authldap の設定では
nss_ldap の設定は関係ないので、直接 authdaemonrc
(.
(ドット) で読まれるシェルスクリプト)を加工します。
authdaemonrc: ... ## Squelch referrral and dereference to avoid connecting to # ldap://ForestDnsZones.ad.example.jp/ export LDAPDEREF=never export LDAPREFERRALS=no
環境変数での設定方法は ldap.conf(5) の冒頭を参照。
LDAP_REFERRALS
や LDAPREFERRAL
ではないことに注意!
そのホストの他の OpenLDAPクライアントでも REFERRALS を使うことは無い!と 断言していいなら、 グローバル設定の /etc/openldap/ldap.conf(5)に書き込んでしまう。 上の個別アプリケーション対処は不要になります。
/etc/openldap/ldap.conf: # See ldap.conf(5) for details # This file should be world readable but not world writable. ... REFERRALS no ...
設定変更した場合はサービスも再起動します。ライブラリ設定は デーモンの起動時に1回しか読まれないことが多いため。 crond, postfix, courier-authlib, courier-imap, sshdなど、できる範囲で restartしておきましょう。
LDAPクライアントの管理者が違っていて、 修正してもらえない!言っても理解しない! て場合は、 /etc/hosts や DNSを細工して ForestDnsZones に繋がらないようにします。
UNIX系とWindows系のDNSが別になっているのであれば、以下を設定してみます:
本稿における問題がなくても、外部に変なDNS queryを 飛ばさないようにするためにも 設定しておくのがおすすめ。
/etc/hosts に細工する方法もあります。
/etc/hosts: 0.0.0.1 ForestDnsZones.ad.example.jp 0.0.0.2 DomainDnsZones.ad.example.jp 0.0.0.3 ad.example.jp
0.0.0.0
(INADDR_ANY) だと問題起こすというか
読んでくれないので、
別のデタラメなアドレスを書いておきます。
ルーティングテーブルで即rejectになるようなアドレスがあるなら、
そちらのほうが良い。
マルチドメインでフォレストを組んだ ActiveDirectory に対して
nss_ldapを使って自動的にフォレストを辿りたい場合は、
ref: ldap://ForestDnsZones
も解決して
索きなおす必要がありますが、
ほとんどの OpenLDAP クライアントは対応してません。
ref: で飛ばされた別LDAPサーバに対しては、別のアカウントで
ldap_bind
(3)しなければならないこともある
(ActiveDirectoryでは必須)ため、
OpenLDAPにはそれ用のフックである
ldap_set_rebind_proc
(3) が用意されていますが、
ldap_set_rebind_proc
(3) のマニュアル部分は
コメントアウト されているので、
開発者でも存在自体を知る人が少なく、
ほとんどのLDAPクライアントは対応していません。 nss_ldapも対応してません。
何も設定されていない状態だと referrals 参照は Anonymousバインドになるので、 それに対応しているLDAPサーバならともかく ActiveDirectory では 認証エラーになる。
man/man3/ldap_bind.3.gz
には、以下のように
コメントアウトされた状態で説明が載っています。
.\" .SH RE-BINDING WHILE FOLLOWING REFERRALS .\" The .\" .B ldap_set_rebind_proc() .\" call is used to set a routine that will be called back to obtain bind .\" credentials used when a new server is contacted during the following of .\" an LDAP referral. Note that this function is only available when the .\" LDAP libraries are compiled with LDAP_REFERRALS defined and is only .\" used when the ld_options field in the LDAP structure has .\" LDAP_OPT_REFERRALS set (this is the default). If .\" .B ldap_set_rebind_proc() .\" is never called, or if it is called with a NULL \fIrebindproc\fP .\" parameter, an unauthenticated simple LDAP bind will always be done .\" when chasing referrals. .\" .LP .\" \fIrebindproc\fP should be a function that is declared like this: .\" .LP .\" .nf .\" int rebindproc( LDAP *ld, char **whop, char **credp, .\" int *methodp, int freeit ); .\" .fi .\" .LP .\" The LDAP library will first call the rebindproc to obtain the .\" referral bind credentials, and the \fIfreeit\fP parameter will be .\" zero. The \fIwhop\fP, \fIcredp\fP, and \fImethodp\fP should be .\" set as appropriate. If the rebindproc returns LDAP_SUCCESS, referral .\" processing continues, and the rebindproc will be called a second .\" time with \fIfreeit\fP non-zero to give your application a chance to .\" free any memory allocated in the previous call. .\" .LP .\" If anything but LDAP_SUCCESS is returned by the first call to .\" the rebindproc, then referral processing is stopped and that error code .\" is returned for the original LDAP operation.