PAMとLDAP認証 2013年5月の適当なメモ

LDAP認証自体については別に新しい話ではありませんので、知っている人は適当にお付き合いください。……読む必要ねぇって言ってんの！

環境: Ubuntu 13.04 + libpam-ldapd (0.8.10-4)

LDAP認証というのは、ローカルで普通に用いる認証の代わりにLDAP上の情報を使って認証をする、というそれだけの話です。

言い換えると、ローカルの認証をLDAPが「乗っ取り」ます。作業としては、通常のLinuxの認証のどこをどう「乗っ取る」かを理解して、対応する設定ファイルを書けば良いわけです。

例えば以下のような解説が仕組みを理解する上で有効です。まず、読みましょう。

* [openLDAP 構築(27) - アカウント管理(1)](http://arinux.net/?eid=31)
* [openLDAP 構築(28) - アカウント管理(2)](http://arinux.net/?eid=32)

で、ま、私の理解をもとにざっくり言うと、__/etc/passwd__, __/etc/shadows__, __/etc/group__ に記載された情報を、LDAPからも取得できるようにすることでLDAPがその部分を肩代わりする==「乗っ取る」、となります。

各ファイルとLDAPのスキーマの個別のフィールドに対応関係があります。具体的には以下のような対応ですね

* /etc/passwd <-> possixAccount
* /etc/shadow <-> shadowAccount
* /etc/group <-> posixGroup

このうち、 possixAccountとshadowAccountは、LDAP上では同じエントリとして存在しているかもしれません。構造上、posixGroupはLDAP上でも別エントリとして管理されていると思われます。QNAP(というLDAPサーバを兼ねられるNAS製品)でもそうなってます。

LDAP認証に用いる基本的な仕組みは昔から変わっておりませんが、それを実現するLinux上の実装やパッケージはいくつもあります。

今回は libpam-ldapd を使いました。

/etc/nsswitch.conf (Name Service Switch なのでNSSの魔女という意味ではない) に書かれたモジュールから情報を取得しようと試み、できたらログインでき、出来なかったらログインできません。仮に両方に同じユーザ名があれば、どちらかのパスワードでログインできます。

ローカル認証で /etc/passwd, /etc/shadow, /etc/group をOSがチェックするタイミングで、LDAP認証では代わりにLDAP上のエントリを参照します。今回のケース (libpam-ldapd) では、nslcdというデーモンがLDAPに対応する値を読みに行き、認証を行います。

なお、LinuxにはName Service Cache Daemon (nscd)というデーモンが走ってることがあります。参考まで、apt-cache show nscdの結果はこちらになります:

> Embedded GNU C Library: Name Service Cache Daemon A daemon which handles passwd, group and host lookups for running programs and caches the results for the next  query. You should install this package only if you use slow services like LDAP, NIS or NIS+.

本件では必要ではないこのサービスが、今回の設定時に変な動作を誘発することがあるようです (後述します)。

# nslcd の設定

libpam-ldapd をインストールする際にどのサーバを使うか、(group, passwd, shadow等) どの設定をLDAPからも取得できるようにするかを決めます。

相手となるLDAPがlocalhostに存在するのであれば、IPCで完結するldapiが良いでしょう。また、LDAP上のユーザでログイン出来るようにするには group, passwd, shadow に関する設定を有効にします。nsswitch.conf には以下のように書かれるはず

    passwd:         compat ldap
    group:          compat ldap
    shadow:         compat ldap

＃ Web上で昔の例を見ると compat ではなく files となってます。違いは man nsswitch.conf に書かれています。

ここから先では、LDAPサーバが外部にあり、そのホストと(TCP/IPで)連携する必要があることを前提にしています。パッケージインストールの時点でLDAPサーバのUriを指定できますが、UriだけではLDAPは動作しないことも多々ありますかんね。

passwd, shadow, groupでLDAPのアクセス先が違うケース (顕著なのはposixGroupが別ディレクトリにある可能性でしょうか。QNAPはそうなってます) では、例えば以下のような感じで設定を記述します。

    base passwd ou=people,dc=..
    base shadow ou=people,dc=..
    base group ou=group,dc=..
    filter group  (objectClass=posixGroup)

これが、Linux デフォルトの認証方法 (nsswitchで言う compat もしくは files) で /etc/passwd, /etc/shadow, /etc/group へのアクセスの代わりになる設定になります。

＃ なお、ここでは base で始まる行が3つありますが、subtree search 等を駆使して、1つの base 行を書けば良いケースの方が多い気がします。

今回ググる上で散見したので書いておくと、この方法 (libpam-ldapd) を用いた場合、ldap.conf に nss\_base\_* という設定を書く必要はありません。そもそもその流儀は何のパッケージの場合で使うんでしょうかね。

libpam-ldapdの場合、LDAPアクセスの設定は全て /etc/nslcd.conf に含められます。ハマったときに nss\_base\_* を試したりもしましたが、/etc/nslcd.conf の内容がしめやかに利用されて効果なしです。libpam-ldapdではなくlibpam-ldapが使ってたりするんじゃないかなぁ、と思ってますが、今回の探査の範囲外です。全体像が見えない状態だとこういう素っ頓狂なところで困るので怖いです。全容を把握したいですね。

# LDAPアクセスのパケット

デバッグ時にはLDAPのやりとりにSSL接続は使わない方が良いでしょう (あるいはWireshark等でSSLを解読しつつ見るか、です)。平文でLDAPサーバのパスワードがやり取りされるのも見えて教育の一環になります。私は、なりました。

SSLを使わない状態でLDAPサーバ側でtcpdumpをすれば、実際に何がやりとりされているかを見れます。一度、設定を間違えて objectClass=Groupと書いてしまってグループ情報が取れないという問題に悩まされましたが、tcpdumpの結果上でもパケットで全ての情報が出てくるので、ミスっている場合には検出が楽。このあたりはインフラ業の人は年中やってるでしょうね。ただし最終的にはそのままでは大変まずいです。

＃ 今回対向側をQNAPにしたせいで、サーバ側のログが満足に読めなくてどーしたもんか、と思う瞬間はありました。クリティカルではなかったんですが。

# グループの扱い

sudo グループが LDAP上にあると、"sudo"というグループに対するIDは論理的に2つ出来る可能性があります。一方コマンドラインで sudo と打った場合、標準のUbuntu 13.04の/etc/sudoersでは、どっちのsudoグループでもsudoer権限を得ます。これは潜在的には厄介です。

変更するにはまずローカルのsudoグループのgid (ここでは27とします) を調べた上で、visudoで

   # %sudo	ALL=(ALL:ALL) ALL
   %#27	ALL=(ALL:ALL) ALL

とかして、LDAP上のsudoのgroupNumberを別の番号に設定しておくことで衝突を避けられます。ちなみに一度 %#27の#を除いてしまった状態でvisudoを閉じたらsudoが帰らぬ人になりました。リカバリモード使ってがんばりましょう。

# nscd は危険です

nscdのキャッシュによってか、不思議な現象がいくらか散見されて混乱を招きました。

最も焦ったのは、以下のケース

* ローカル/etc/passwd等にはユーザは記載されていない
* LDAPにはそのユーザはいる
* この状態で、nslcdが認証エラーを吐いてログインを許さない (認証後にエラー、ではない)

Ubuntu 13.04 の現時点のnslcdではsyslogdへのログ表示がリッチではありません。一言こう書かれるだけです

    May 21 17:35:00 hanairo nslcd[23217]: [3c9869] <authc="testuser"> uid=testuser,(DNだよ): lookup failed: Invalid credentials

testuserのパスワードは間違いなく正しく打っているのにぃ。

これが 0.9.0 以降のnslcdなら log という設定を nslcd.confに書くことが出来るようになっているそうで、それによってDEBUGログが読めるはずなんですが……

> log SCHEME [LEVEL]
> This option controls the way logging is done. The SCHEME argument may either be  
> none, syslog or an absolute file name. The LEVEL argument is optional and
> specifies the log level. The log level may be one of: crit, error, warning,
> notice, info or debug. The default log level is info. All messages with the
> specified loglevel or higher are logged. This option can be supplied multiple
> times. If this option is omitted syslog info is assumed.

そもそもnslcdはまだ活発に開発されているかのようで、Ubuntu 13.04の現状使っている 0.8.1 では上の項目がありません。というか0.9.0のリリースが2013-04-05で、この界隈ってそんなにバージョン上げまくるモチベーション今でもあるの、と少し驚きました。log出力の貧弱さを考えればもっと早くやってよ、という気分を他の利用者は感じてたのでは……

で、nscdが危うい、という件は以下のスレッドを参考にしました。ドンピシャで解決してびっくりしたんですが、果たしてnscdのせいなのかnslcdが悪いのか

http://lists.arthurdejong.org/nss-pam-ldapd-users/2011/msg00014.html

nscdが必要なケースではnslcdをリブートするときにnscdもリブートすることで症状が良くなることがありました。nscd側のことに詳しくないのでここでは触れませんが、組み合わせて困った場合にはキャッシュ周りの不整合だろうと予測つけるのが良いのかもしれません。

そもそも本家のインストールガイドではnscdについてもせめて止めてテストしろ、とは書いてあります。FAQ臭い。

http://arthurdejong.org/nss-pam-ldapd/setup

怖いのはnslcdそのものはLDAPサーバへアクセスしてることなんですよね。tcpdump見てて「なぜgroupを見に行かない……？」という問題とセットでウンウン唸って、nscd止めたらさっくり全部うまくいった、という不思議体験はポルナレフに匹敵します。ありのままに以下略

# 参考リンク

この界隈は実装が複数種類ある中、利用した環境については書かないメモ記事が多々あるので注意です。この記事もですけど。

* http://serverfault.com/questions/284307/libpam-ldap-or-libpam-ldapd
* http://wiki.debian.org/LDAP/PAM
* http://wiki.debian.org/LDAP/NSS
* http://arthurdejong.org/nss-pam-ldapd/setup
* [openLDAP 構築(27) - アカウント管理(1)](http://arinux.net/?eid=31)
* [openLDAP 構築(28) - アカウント管理(2)](http://arinux.net/?eid=32)

# 雑多なコメント

あんまり関係ないですが、手元でldapsearchは多用してますけどldapmodifyは全く使ってません。GUI環境でてくてくやってます。

古い分野なんですがそれでも妙にハマるしドキュメントもちょっと散乱気味でしょうか。でも今回は割と問題がスルっと消えていくことが多くて良い感じでした。

ローカルユーザがいない状態だとホームディレクトリが用意できてません。お、おう……

全体的にid管理やパーミッションに色々課題があるなぁ、という感じ。

ググるのもありですが、man nslcd.conf を見る回数も相当多いという比較的健全な設定作業でした。pam.dの類はパッケージがきっちり書いてくれてるおかげもあって読んだはいいが変更はしてません。nsswitch.confもLDAP認証パッケージを入れた後のままです

    passwd:         compat ldap
    group:          compat ldap
    shadow:         compat ldap

compatを殺したい欲望が強いんですが、我慢しました。どこまでをローカル、どこまでをLDAPにするのがふつーなんですかね。LDAPさえ理解してればどっちでも相当程度出来るんですよ。問題は障害時にどう波及していくか、という話で (LDAP止まったら全サービス止まるってやばいですよね。ログインできないとか)

全体的には20年ほど昔のお話でした。そんなのきーたに書くな。