Debian boxのユーザ認証をLDAPで一元化してみた。

注意:無保証。自分用のメモで誤りや抜けが多いし、あくまで隔離されたネット ワークでの実験で、公開されたネットワークでの運用に耐える設定ではない。

条件等

前提:

  • ドメインはexample.com

  • 既にLDAPサーバが立っている(xxx.xxx.xxx.xxx)

    • ベースはdc=example,dc=com
    • 管理者はcn=admin,dc=example,dc=com (cn=manager,dc=example,dc=comのほうがよかったかもしれない)
  • 次のいずれかを満たすユーザにloginを許す:

    • LDAPデータベース上にアカウント情報がある
    • そのマシンにローカルなUnixアカウントがある(管理用のアカウントなど)

大まかにいって、次の設定をすればよいらしい。

  • パッケージ

    • libnss-ldap
    • libpam-ldap
    • nscd(パフォーマンス向上のため)
  • /etc/nsswitch.conf

    passwd, group, shadowの各エントリにcompatに加えてldapを指定

  • /etc/libnss-ldap.conf

    base, uri, ldap_version, rootbinddnなどを設定

  • /etc/pam_ldap.conf

    • LDAPサーバのURIを設定する

      今回は別のホストでLDAPサーバが動いており、またSSLはまだ使っていない ので、スキームはldapiではなくldapとする。

    • 照会時にLDAPにアクセスするアカウントを指定する (cn=manager,dc=example,dc=com)

  • /etc/pam.d/common-*

    • pam_ldap.soをsufficientとして追加

      LDAPで認証できるようにする。

    • pam_unix.soをrequiredからsufficientに変更

      Unixアカウントを必須ではなく任意にする。

  • サービスアプリケーションごとの設定

    • さしあたってsshdとSamba

OSのセットアップ

libnss-ldapをインストールするとReccomends:にあるlibpam-ldapとnscdもインス トールされる。

% sudo apt-get install libnss-ldap

設定を直したければ、いつでもdpkg-reconfigure libnss-ldapで再設定できる。

libnss-ldapのインストール

LDAP server URI:
-ldapi:///
+ldap://xxx.xxx.xxx.xxx/

Distinguished name of the search base
-dc=example,dc=net
-dc=example,dc=com

LDAP version to use:
 3

LDAP database require login?
 No

Special LDAP privileges for root?
 Yes

Make the configuration file readable/writable by its owner only?
-No
+Yes

LDAP account for root:
-cn=manager,dc=example,dc=net
+cn=admin,dc=example,dc=com

LDAP root account password
 xxx

libpam-ldapのインストール

LDAP server URI:
-ldapi:///
+ldap://xxx.xxx.xxx.xxx/

Distinguished name of the search base:
-dc=example,dc=net
+dc=example,dc=com

LDAP version to use:
 3

Make local root Database admin?
 Yes

LDAP database require login?
 No

LDAP account for root:
-cn=manager,dc=example,dc=net
+cn=admin,dc=example,dc=com

LDAP root account password
 xxx

Local crypt to use when changing passwords
 crypt

/etc/nsswitch.conf

/etc/nsswitch.confを編集し、passwd, group, shadowの各エントリにldapを追加 する。

--- a/nsswitch.conf
+++ b/nsswitch.conf
@@ -4,9 +4,9 @@
 # If you have the `glibc-doc-reference' and `info' packages installed, try:
 # `info libc "Name Service Switch"' for information about this file.

-passwd:         compat
-group:          compat
-shadow:         compat
+passwd:         compat ldap
+group:          compat ldap
+shadow:         compat ldap

 hosts:          files dns
 networks:       files

/etc/pam.d/common-*

/etc/pam.d/common-*を書き換える。順序に注意。 login時に~がない場合は作成するよう、sessionでpam_mkhomedir.soを指定。

--- a/pam.d/common-account
+++ b/pam.d/common-account
@@ -6,4 +6,5 @@
 # the central access policy for use on the system.  The default is to
 # only deny service to users whose accounts are expired in /etc/shadow.
 #
+account   sufficient  pam_ldap.so
 account   required    pam_unix.so

--- a/pam.d/common-auth
+++ b/pam.d/common-auth
@@ -7,4 +7,5 @@
 # (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
 # traditional Unix authentication mechanisms.
 #
-auth      required    pam_unix.so nullok_secure
+auth      sufficient  pam_ldap.so use_first_pass
+auth      sufficient  pam_unix.so nullok_secure

--- a/pam.d/common-password
+++ b/pam.d/common-password
@@ -21,7 +21,8 @@
 #
 # See the pam_unix manpage for other options.
+password  sufficient  pam_ldap.so
 password  required    pam_unix.so nullok obscure md5

 # Alternate strength checking for password. Note that this
 # requires the libpam-cracklib package to be installed.

--- a/pam.d/common-session
+++ b/pam.d/common-session
@@ -6,4 +6,6 @@
 # at the start and end of sessions of *any* kind (both interactive and
 # non-interactive).  The default is pam_unix.
 #
+session   required    pam_mkhomedir.so skel=/etc/skel/ umask=0022
+session   sufficient  pam_ldap.so
 session   required    pam_unix.so

設定をチェック

% grep -v '^#\|^$' /etc/pam_ldap.conf
base dc=example,dc=com
uri ldap://xxx.xxx.xxx.xxx/
ldap_version 3
rootbinddn cn=admin,dc=example,dc=com
pam_password crypt

% grep -v '^#\|^$' /etc/libnss-ldap.conf
base dc=example,dc=com
uri ldap://xxx.xxx.xxx.xxx/
ldap_version 3
rootbinddn cn=admin,dc=example,dc=com

% sudo cat /etc/libnss-ldap.secret
xxx

% sudo cat /etc/pam_ldap.secret
xxx

% (cd /etc/pam.d; grep -v '^#\|^$' common-*; cd -)
common-account: account   sufficient  pam_ldap.so
common-account: account   required    pam_unix.so
common-auth:    auth      sufficient  pam_ldap.so use_first_pass
common-auth:    auth      sufficient  pam_unix.so nullok_secure
common-password:password  sufficient  pam_ldap.so
common-password:password  required    pam_unix.so nullok obscure md5
common-session: session   required    pam_mkhomedir.so skel=/etc/skel/ umask=0022
common-session: session   sufficient  pam_ldap.so
common-session: session   required    pam_unix.so

テスト

うまくいかない場合(ホームディレクトリやシェルがない):

hostname% login: jdoe
password: 
No directory, logging in with HOME=/
Cannot execute /usr/bin/zsh: No such file or directory
hostname% login: 

うまくいった場合:

hostname% login: jdoe
password: 
hostname%

注意点:

  • ユーザが使うシェルなどはあらかじめ用意しておくこと。

  • PAMの設定ファイルの記述は順序に注意。例えばpam_mkhomedir.soは pam_ldap.so やpam_unix.soに先立って書いておかないと、HOMEがないまま login することになる。

うまくいかないときは

% sudo tail /var/log/auth.log

して確認。

資料

日本語でPAMの概要を把握するときに。

本家。

Debianでの設定ファイルの配置などが参考になる。

OpenSSHのLDAP認証

注意:UsePAMを有効にすればPAMを使うようになるのだけど、PAMを使うというこ とはそれが抜け道にもなりかねないので、要注意。(せっかくパスワード認証を 殺していても、PAMの参照先が緩ければ意味がない。)

公開鍵認証をするにはパッチを当てる必要があるらしいので、とりあえずパスワー ド認証で実験。安全なネットワークでない限りやってはいけない。

% sudo vi /etc/ssh/sshd.conf
...
% sudo cat /etc/ssh/sshd.conf
...
PermitEmptyPassword no
...
ChallengeResponseAuthentication yes
...
PasswordAuthentication yes
...
UsePAM yes
...
% 

% sudo /etc/init.d/ssh restart
...
% 

注意点:

気づきにくい落とし穴がある。

  • ChallengeResponseAuthentication yes

  • PermitEmptyPassword no

参考:

openssh-server: Problem with pam_setcred() call
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=315040#10

Problem with "pam_setcred(): Permission denied" error message and normal login fixed by switching

PermitEmptyPassword yes

in /etc/ssh/sshd_config to

PermitEmptyPassword no

SambaのLDAP認証

  • Debian lenny

  • OpenLDAP server (slapd)とSamba server (smbd) は既にセットアップされて 正しく動いているものとする。

事前の準備

必要なパッケージをインストールする。

% sudo apt-get install samba-doc smbldap-tools

説明を読む。

% lv /usr/share/doc/smbldap-tools/README.Debian.gz

OpenLDAP server (slapd)の設定

samba-docに付属するLDAPスキーマをシステムにコピーする。

% sudo cp /usr/share/doc/samba-doc/examples/LDAP/samba.schema.gz \
          /etc/ldap/schema/
% sudo gunzip /etc/ldap/schema/samba.schema.gz

slapdの設定ファイルにsamba-ldap向けの設定を追加する。

% sudo vi /etc/ldap/slapd.conf

diffふうに書くとこんな感じ。

+ include       /etc/ldap/schema/samba.schema

-access to attrs=userPassword,shadowLastChange
+access to attrs=userPassword,shadowLastChange,sambaNTPassword,sambaLMPassword
         by dn="cn=admin,dc=ohmsha,dc=co,dc=jp" write
         by anonymous auth
         by self write
         by * none

README.Debianにはindexの設定もお好みで書いてよしとあるが、indexは後で書く。 先に書いてしまうと接続できなくなる。index対象の要素がまだDBにないせいだろ う。

後でSambaの認証をLDAPに向けたうえでsmbpasswdを使えば適当な値が書き込まれ るので、心配ない。

再起動して設定を反映。

% sudo /etc/init.d/slapd restart

クライアント側のSambaの設定

LDAPを参照するように設定ファイルを編集。

sudo vi /etc/samba/smb.conf

-passdb backend = tdbsam
+passdb backend = ldapsam:ldap://xxx.xxx.xxx.xxx/
 ...
-obey pam restrictions = yes
+obey pam restrictions = no

+ldap admin dn = cn=admin,dc=example,dc=com
+ldap suffix = dc=example,dc=com
+ldap group suffix = ou=Groups
+ldap user suffix = ou=Users
+ldap machine suffix = ou=Computers
+ldap idmap suffix = ou=Users

あとパスワード変更をsmbldap-toolsに任せる設定。

+ldap passwd sync = No
 unix password sync = Yes
 ...
-passwd program = /usr/bin/passwd %u
+passwd program = /usr/sbin/smbldap-passwd -u %u
-passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\s*new\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
+passwd chat = *New\s*\spassword* %n\n *Retype\snew\s*\spassword* %n\n *all*authentication*token*updated*

Windowsから操作するための設定はREADME.Debian参照。

LDAPサーバにアクセスするためにadminのパスワードを登録する。

% sudo smbpasswd -W
Setting stored password for "cn=admin,dc=example,dc=com" in secrets.tdb
New SMB password:
Retype new SMB password:
%

再起動する。

% sudo /etc/init.d/samba restart

smbldap-toolsの設定

クライアント側でsmbldap-toolsの設定をする。

標準のpasswdを使うところをsmbldap-passwdに変えたりしているので、 これをやらないと動かない。

まず設定ファイルの雛形をシステムにコピーする。 中にパスワードを平文で書くので権限に注意。

% sudo cp /usr/share/doc/smbldap-tools/examples/smbldap.conf.gz \
          /etc/smbldap-tools/
% sudo gunzip /etc/smbldap-tools/smbldap.conf.gz
% sudo cp /usr/share/doc/smbldap-tools/examples/smbldap_bind.conf \
          /etc/smbldap-tools/
% sudo chmod 0644 /etc/smbldap-tools/smbldap.conf
% sudo chmod 0600 /etc/smbldap-tools/smbldap_bind.conf

DomainではなくWorkgroup構成なら、どれでもいいので統一の 基準となるSambaサーバを決めて、そのSIDを調べておく。

% sudo net getlocalsid
SID for domain xxx is: S-1-5-21-yyyyyyyyy-yyyyyyyyyy-yyyyyyyyy
%

これを全Sambaサーバで共通のSIDとして使う(Windows Domain を設けるときは話が別)。

ローカルのSID設定はコメントアウトして、net getlocalsid 経由でLDAPに問い合わせるように設定。

-SID="S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxx"
+# SID="S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxx"

-sambaDomain="DOMSMB"
+#sambaDomain="DOMSMB"
 ...
-masterLDAP="127.0.0.1"
+masterLDAP="xxx.xxx.xxx.xxx"
 ...
-suffix="dc=company,dc=com"
+suffix="dc=example,dc=com"

smbldap_bind.confを編集。

% sudo vi /etc/smbldap-tools/smbldap_bind.conf

-slaveDN="cn=Manager,dc=company,dc=com"
+slaveDN="cn=admin,dc=example,dc=com"
-slavePw="secret"
+slavePw="xxx"
-masterDN="cn=Manager,dc=company,dc=com"
+masterDN="cn=admin,dc=example,dc=com"
-masterPw="secret"
+masterPw="xxx"

LDAP DB側の用意

smbpasswdでユーザを追加する。

% sudo smbpasswd -a jdoe
New SMB password: 
Retype new SMB password:
Added user jdoe.

こんなエントリになる。

dn: uid=jdoe,ou=People,dc=example,dc=com
objectClass: account
objectClass: posixAccount
objectClass: sambaSamAccount
objectClass: shadowAccount
objectClass: top
cn: John Doe
gidNumber: 2001
homeDirectory: /home/jdoe
sambaSID: S-1-5-21-yyyyyyyyy-yyyyyyyyyy-yyyyyyyyy-5002
uid: hmorita
uidNumber: 2001
displayName: John Doe,,,
gecos: John Doe,,,
loginShell: /usr/bin/zsh
sambaAcctFlags: [U          ]
sambaNTPassword: ...
sambaPasswordHistory: ...
sambaPwdLastSet: 1251358905
shadowLastChange: 11418
shadowMax: 99999
shadowWarning: 7
userPassword:: ...

試行錯誤の過程でsmbldap-populateしていろいろなエントリを登録 してしまったけれど、必須ではないと思われる。

そしてpopulateでいろいろ登録。

% sudo smbldap-populate -a admin
...
% 

LDAP DBにSambaサーバを登録する。次はfile1.example.comという Sambaサーバがある場合のLDIFエントリ。他のサーバも同様に登録する。

dn: sambaDomainName=FILE1,dc=example,dc=com
objectClass: sambaDomain
sambaDomainName: FILE1
sambaSID: S-1-5-21-yyyyyyyyy-yyyyyyyyyy-yyyyyyyyy
sambaAlgorithmicRidBase: 1000
sambaForceLogoff: -1
sambaLockoutDuration: 30
sambaLockoutObservationWindow: 30
sambaLockoutThreshold: 0
sambaLogonToChgPwd: 0
sambaMaxPwdAge: -1
sambaMinPwdAge: 0
sambaMinPwdLength: 5
sambaNextUserRid: 1000
sambaPwdHistoryLength: 0
sambaRefuseMachinePwdChange: 0

これでどのSambaサーバにも同じアカウントでlogonできるはず。

確認:

file1% sudo pdbedit -d 3 -L
lp_load_ex: refreshing parameters
Initialising global parameters
params.c:pm_process() - Processing configuration file "/etc/samba/smb.conf"
Processing section "[global]"
smbldap_search_domain_info: Searching for:[(&(objectClass=sambaDomain)(sambaDomainName=FILE1))]
smbldap_open_connection: connection opened
ldap_connect_system: successful connection to the LDAP server
smbldap_search_domain_info: Searching for:[(&(objectClass=sambaDomain)(sambaDomainName=FILE1))]
smbldap_open_connection: connection opened
ldap_connect_system: successful connection to the LDAP server
smbldap_search_paged: base => [dc=example,dc=com], filter => [(&(uid=*)(objectclass=sambaSamAccount))],scope => [2], pagesize => [1024]
smbldap_search_paged: search was successfull
init_sam_from_ldap: Entry found for user: jdoe
jdoe:2001:John Doe,,,
...
file1%

トラブルシューティング

  • 共有の競合

    複数のユーザ名で同時に同じリソースにアクセスしようとするとWindowsが エラーを返す場合がある。 そういうときは

    net use
    net use \\server\share /delete
    

    で接続状況を表示させたり、適宜切断したりすればよい。

  • ネットワークパスが見つからない

    「ネットワークパスが見つからない」と言われたら、そのユーザのホームディ レクトリが存在するか確認してみるとよい。

    ls /home
    
  • SambaのSID

    SIDはLDAPのDBに格納するもので、ローカルのsecrets.tdbに格納するもので はない。また、SambaがLDAPを参照するように設定されている場合、net getlocalsidはLDAPを見に行く。net setlocalsidなどとしても変更できない ので注意。

    はまっている人の例(S-1-5-21-yyyを設定できない):

    % sudo net getlocalsid
    SID for domain FILE1 is: S-1-5-21-xxx
    % sudo net setlocalsid S-1-5-21-yyy
    % sudo net getlocalsid
    SID for domain FILE1 is: S-1-5-21-xxx
    

    こうなったらLDAPのほうを見ましょう。

雑感

それにしてもLDAP周りは手間がかかる。今までの振り返り:

  • OpenLDAPサーバ
    仕組みや独特の概念を理解するのに時間がかかる。OSやディストリビューショ ンごとに細かく違うのも足を引っ張る。第一の関門。

  • PAMとNSS
    資料が散らばっていて理解に時間がかかる。OSやディストリビューションご とに細かく違ううえ、順序に依存しているのがつらい。第二の関門。

  • OpenSSHサーバ
    UsePAM = yesだけなので、手間はかからない。ただし ChallengeResponseAuthenticationに注意。

  • Sambaサーバ
    1台なら簡単。ただし2台以上だと、SID周りでつまずくと遠回りしかねない。

試行錯誤に費やした時間を考えると、LDAPの本とSamba+LDAPの本を1冊ずつ手元に 用意しておいて損はなさそう。

資料

LDAP全般:

LDAPに関する鵜飼さんの包括的な記事。知りたいことはたいてい載っている。 古くなった部分はドキュメントを読んでアップデートすればよい。

uidを調整する際の参考に:

Samba+LDAPはこれで十分:

SIDの話: