WheezyでLDAP認証、SSHログイン

■vmplayer上のWheezyにslapdを導入
 ※ディスクを8GB⇒16GB、不要なUSB等は削除、ネットワークはNAT一本。
  インストールでは、Debianデスクトップとプリンタサーバのチェックを外した。

 [2013-02-17] Debian インストーラ 7.0 リリース候補 (Release Candidate) 1
 http://www.debian.org/devel/debian-installer/

■まずはOSの準備。この後よりsshで作業。
 ※「gcc*」はやりすぎた。結構時間がかかる。
  コンソールなので、VMwareToolsは入れなくても良い。

# apt-get update && apt-get upgrade
# apt-get install -y sudo vim chkconfig linux-headers-`uname -r` gcc* apt-file
# apt-get purge -y nano ;dpkg -l grep ^ii | grep "bluetooth\|nfs" | awk '{print $2}' | apt-get purge -y `xargs`
# tar zxvf /media/cdrom0/VMwareTools-8.8.4-743747.tar.gz && cd vmware-tools-distrib && ./vmware-install.pl
# usermod -a -G sudo labunix
# echo -e "auto eth0\nallow-hotplug eth0\niface eth0 inet static\naddress 192.168.1.1\nnetmask 255.255.255.0\nbroadcast 192.168.1.255\n" | \
  tee -a /etc/network/interfaces
# sudo -u labunix ssh-keygen -t rsa
# shutdown -r now && exit

□gccの箇所は以下で充分。

$ cat /proc/version | sed s/")"/"\n"/g | grep gcc
 (gcc version 4.6.3 (Debian 4.6.3-15
$ sudo apt-get install -y sudo vim chkconfig linux-headers-`uname -r` gcc-4.6* apt-file

■空いた時間に、日本LDAPユーザ会のユーザ会によるセミナー資料から、PDFを取得。
 GUIではxpdfを使うが別のマシンで閲覧する。

$ w3m -dump_source http://www.ldap.jp/doc/ | grep "href=.*pdf" | \
  awk -F\" '{print $2}' | sed s/"\?.*"//g | \
  sed s%^%"http://www.ldap.jp/doc"%g | for n in `xargs`;do wget "$n";done

$ wc -c *.pdf
 3896 20070423nakamitsu.pdf
 3891 20070423odagiri1.pdf
 3891 20070423odagiri2.pdf
 3896 20070423sekiguchi.pdf
 3881 20070423takeda.pdf
 3886 20071006oscldap.pdf
 3876 ldap-jp200703.pdf
 3911 osc2007-fukuoka-ldap.pdf
 3881 osc2007do-ldap.pdf
 3901 osc2007kansai_ldap.pdf
 3911 osc2008-tokyo_spring.pdf
 3901 osc2009_tokyo_fall.pdf
 3911 osc2009_tokyo_spring.pdf
 3901 osc2010_tokyo_fall.pdf
 3911 osc2010_tokyo_spring.pdf
58445 合計

■まずは導入前の準備
 必要なのは大きく以下の4つ。

 LDAPサーバの管理者パスワード
 LDAPの待ち受けIP(ポートは389/636から変更したい場合のみ)
 LDAP形式のドメイン名
 LDAPのバージョン(通常は3)

■後で変更する場合は、「dpkg-reconfigure [package-name]」で。
 ※先に決めておくべきものは以下で確認しておく。
  ホスト名(CNAMEかAレコードかはともかく)を含めるかどうかは、
  ドメイン名の考え方、DNSの設計に依存する。

■ホスト名「hostname -s」を含めない場合

$ hostname -f | sed s/`hostname -s`// | sed s/"^\|\."/",dc="/g | sed s/^,//g
dc=openldap,dc=local

$ hostname -f | sed s/`hostname -s`// | sed s/"^\|\."/",dc="/g | sed s/^,/"cn=manager,"/g
cn=manager,dc=openldap,dc=local

■ホスト名を含める場合

$ hostname -f | sed s/"^\|\."/",dc="/g | sed s/^,//g
dc=vmwheezy,dc=openldap,dc=local

$ hostname -f | sed s/"^\|\."/",dc="/g | sed s/^,/"cn=manager,"/g
cn=manager,dc=vmwheezy,dc=openldap,dc=local

■slapdとldap-utils、libnss-ldap、libpam-ldap導入
 一言で言うと以下。

 LDAPサーバ
 LDAPクライアント
 LDAPユーザ・グループの名前解決モジュール(認証する際にどこを見るか)
 LDAP-PAM連携モジュール

$ echo "slapd ldap-utils libnss-ldap libpam-ldap" | \
  for n in `xargs`;do apt-cache show ^$n\$ | grep ^Description-[ej]; done
Description-ja: OpenLDAP サーバ (slapd)
Description-ja: OpenLDAP ユーティリティ
Description-en: NSS module for using LDAP as a naming service
Description-en: Pluggable Authentication Module for LDAP

$ sudo apt-get install slapd ldap-utils libnss-ldap libpam-ldap

■導入確認。
 ※「olcRootDN: cn=admin,dc=openldap,dc=local」とそのパスワードが
  「ldap*」コマンドで使う管理者アカウントになる。

$ sudo ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config -W olcDatabase={1}hdb
Enter LDAP Password:
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
# extended LDIF
#
# LDAPv3
# base <cn=config> with scope subtree
# filter: olcDatabase={1}hdb
# requesting: ALL
#

# {1}hdb, config
dn: olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=openldap,dc=local
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymou
 s auth by dn="cn=admin,dc=openldap,dc=local" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=openldap,dc=local" write b
 y * read
olcLastMod: TRUE
olcRootDN: cn=admin,dc=openldap,dc=local
olcRootPW: {SSHA}XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

■バックエンドのDBは上記「olcDbDirectory: /var/lib/ldap」にあるとおりHDB。
 待ち受けポートは389

$ ls /var/lib/ldap
DB_CONFIG  __db.002  __db.004  __db.006  dn2id.bdb     log.0000000001
__db.001   __db.003  __db.005  alock     id2entry.bdb  objectClass.bdb

$ netstat -an | grep 389
tcp        0      0 0.0.0.0:389             0.0.0.0:*               LISTEN
tcp6       0      0 :::389                  :::*                    LISTEN

■libnss-ldapの設定
 ローカルの/etc/passwdや/etc/groupで見つからない場合にldapに問い合わせを行う設定にする。

$ grep compat /etc/nsswitch.conf
passwd:         compat
group:          compat
shadow:         compat

$ sudo cp /etc/nsswitch.conf /etc/nsswitch.conf.org
$ sudo sed -i s/compat/"& ldap"/g /etc/nsswitch.conf
$ grep compat /etc/nsswitch.conf
passwd:         compat ldap
group:          compat ldap
shadow:         compat ldap

■libpam-ldapの設定
 「dc=openldap,dc=local」は環境に合わせて変更する。

$ grep -v "^#\|^\$" /etc/libnss-ldap.conf | sed s/"[0-9]*\.[0-9]*"/"XXX."/g | sed s/"\.\$"//g
base dc=openldap,dc=local
uri ldapi:///XXX.XXX.XXX
ldap_version 3
rootbinddn cn=manager,dc=openldap,dc=local

$ grep "base_passwd\|base_shadow\|base_gshadow\|base_group" /etc/libnss-ldap.conf
# nss_base_passwd       ou=People,
#nss_base_passwd        ou=People,dc=padl,dc=com?one
#nss_base_shadow        ou=People,dc=padl,dc=com?one
#nss_base_group         ou=Group,dc=padl,dc=com?one
#nss_base_passwd ou=aixaccount,?one
#nss_base_group ou=aixgroup,?one

$ sudo cp /etc/libnss-ldap.conf /etc/libnss-ldap.conf.org
$ sudo sed -i s%"#nss_base_passwd.*ou=People.*one"%"&\nnss_base_passwd\tou=People,dc=openldap,dc=local?sub"% /etc/libnss-ldap.conf
$ sudo sed -i s%"#nss_base_shadow.*ou=People.*one"%"&\nnss_base_shadow\tou=People,dc=openldap,dc=local?sub"% /etc/libnss-ldap.conf
$ sudo sed -i s%"#nss_base_group.*ou=Group.*one"%"&\nnss_base_group\tou=Group,dc=openldap,dc=local?sub"% /etc/libnss-ldap.conf

$ grep ^nss_base /etc/libnss-ldap.conf
nss_base_passwd ou=People,dc=openldap,dc=local?sub
nss_base_shadow ou=People,dc=openldap,dc=local?sub
nss_base_group  ou=Group,dc=openldap,dc=local?sub

$ sudo mv /etc/pam_ldap.conf /etc/pam_ldap.conf.org
$ sudo mv /etc/pam_ldap.secret /etc/pam_ldap.secret.org

$ sudo ln -s /etc/libnss-ldap.conf /etc/pam_ldap.conf
$ sudo ln -s /etc/libnss-ldap.secret /etc/pam_ldap.secret

$ ls -l /etc/pam_ldap.*[ft] | sed s/".*\:[0-9][0-9] "//g
/etc/pam_ldap.conf -> /etc/libnss-ldap.conf
/etc/pam_ldap.secret -> /etc/libnss-ldap.secret

■PAMの設定(確認のみ)
 debianの場合、「pam_ldap.so」を参照するよう自動的に設定される。

$ grep ldap /etc/pam.d/*
/etc/pam.d/common-account:account       [success=1 default=ignore]      pam_ldap.so
/etc/pam.d/common-auth:auth     [success=1 default=ignore]      pam_ldap.so use_first_pass
/etc/pam.d/common-password:password     [success=1 user_unknown=ignore default=die]     pam_ldap.so use_authtok try_first_pass
/etc/pam.d/common-session:session       optional                        pam_ldap.so
/etc/pam.d/common-session-noninteractive:session        optional                        pam_ldap.so

■LDIFで使う「objectClass」の確認

$ grep -i objectclass /etc/ldap/schema/c*.schema | grep -i "unit"
/etc/ldap/schema/core.schema:objectclass ( 2.5.6.5 NAME 'organizationalUnit'

$ grep -i objectclass /etc/ldap/schema/[cn]*.schema | grep -i "person\|account\|group"
/etc/ldap/schema/core.schema:objectclass ( 2.5.6.6 NAME 'person'
/etc/ldap/schema/core.schema:objectclass ( 2.5.6.7 NAME 'organizationalPerson'
/etc/ldap/schema/core.schema:objectclass ( 2.5.6.9 NAME 'groupOfNames'
/etc/ldap/schema/core.schema:objectclass ( 2.5.6.10 NAME 'residentialPerson'
/etc/ldap/schema/core.schema:objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames'
/etc/ldap/schema/cosine.schema:objectclass ( 0.9.2342.19200300.100.4.5 NAME 'account'
/etc/ldap/schema/nis.schema:objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount'
/etc/ldap/schema/nis.schema:objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount'
/etc/ldap/schema/nis.schema:objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup'
/etc/ldap/schema/nis.schema:objectclass ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup'

■ユーザ、パスワードを入れる為のOUの作成

$ echo '
dn: ou=People,dc=openldap,dc=local
objectclass: organizationalUnit
objectclass: top
ou: People

dn: ou=Group,dc=openldap,dc=local
objectclass: organizationalUnit
objectclass: top
ou: Group' | sudo tee ug_init_ou.ldif

$ sudo ldapadd -f ug_init_ou.ldif -x -D "cn=admin,dc=openldap,dc=local" -W
Enter LDAP Password:
adding new entry "ou=People,dc=openldap,dc=local"

adding new entry "ou=Group,dc=openldap,dc=local"

■パスワードを得る
 ※以下のような安易なパスワードを用いないこと。
  暗号化方式のデフォルトはSSHA

$ sudo slappasswd -s ldapuser
{SSHA}GdBQ6gFNZgi5ncTyoCRS1McGSd5s/u/I

■ローカルで表現すると、以下になる。
 ※これは実行しない。

$ sudo groupadd -g 10000 ldapgroup
$ sudo useradd -u 10000 -g ldapgroup -s /bin/bash -m -d /home/ldapuser

■上記をLDIFとして記述すると以下になる。

$ echo '
dn: uid=ldapuser,ou=People,dc=openldap,dc=local
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
uid: ldapuser
userPassword: {SSHA}GdBQ6gFNZgi5ncTyoCRS1McGSd5s/u/I
uidNumber: 10000
gidNumber: 10000
loginShell:/bin/bash
homeDirectory: /home/ldapuser
cn: OpenLdap Div

dn: cn=ldapgroup,ou=Group,dc=openldap,dc=local
objectclass: posixGroup
cn: ldapgroup
gidNumber: 10000
memberUid: ldapuser
' | tee ldapuser_init_cn.ldif

■LDAPアカウントを登録する。

$ sudo ldapadd -f ldapuser_init_cn.ldif -x -D "cn=admin,dc=openldap,dc=local" -W
Enter LDAP Password:
adding new entry "uid=ldapuser,ou=People,dc=openldap,dc=local"

adding new entry "cn=ldapgroup,ou=Group,dc=openldap,dc=local"

■登録した内容を確認する。

$ ldapsearch -x -LLL -b "dc=openldap,dc=local" "(objectClass=account)"
dn: uid=ldapuser,ou=People,dc=openldap,dc=local
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
uid: ldapuser
uidNumber: 10000
gidNumber: 10000
loginShell: /bin/bash
homeDirectory: /home/ldapuser
cn: OpenLdap Div

$ ldapsearch -x -LLL -b "dc=openldap,dc=local" "(objectClass=PosixGroup)"
dn: cn=ldapgroup,ou=group,dc=openldap,dc=local
objectClass: posixGroup
cn: ldapgroup
gidNumber: 10000
memberUid: ldapuser

■ログイン可能なアカウントとして紐付けられているかの確認。

$ getent group | grep ^ldap
ldapgroup:*:10000:ldapuser

$ getent passwd | grep ^ldap
ldapuser:x:10000:10000:OpenLdap Div:/home/ldapuser:/bin/bash

$  getent shadow | grep ^ldap
ldapuser:*:::::::

■もちろん、ローカルアカウントには無い。

$ sudo grep ^ldap /etc/shadow
$ sudo grep ^ldap /etc/group

■ldapcompareで設定が正しく行われたかどうかの確認。

$ sudo ldapcompare -x "uid=ldapuser,ou=People,dc=openldap,dc=local" uidNumber:10000
TRUE

$ sudo ldapcompare -x "cn=ldapgroup,ou=Group,dc=openldap,dc=local" gidNumber:10000
TRUE

■ldapsearchでLDIFを出力して確認

$ ldapsearch -x -L -b ou=People,dc=openldap,dc=local uid=ldapuser
version: 1

#
# LDAPv3
# base <ou=People,dc=openldap,dc=local> with scope subtree
# filter: uid=ldapuser
# requesting: ALL
#

# ldapuser, People, openldap.local
dn: uid=ldapuser,ou=People,dc=openldap,dc=local
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
uid: ldapuser
uidNumber: 10000
gidNumber: 10000
loginShell: /bin/bash
homeDirectory: /home/ldapuser
cn: OpenLdap Div

# search result

# numResponses: 2
# numEntries: 1

$ ldapsearch -x -L -b ou=Group,dc=openldap,dc=local cn=ldapgroup
version: 1

#
# LDAPv3
# base <ou=Group,dc=openldap,dc=local> with scope subtree
# filter: cn=ldapgroup
# requesting: ALL
#

# ldapgroup, group, openldap.local
dn: cn=ldapgroup,ou=group,dc=openldap,dc=local
objectClass: posixGroup
cn: ldapgroup
gidNumber: 10000
memberUid: ldapuser

# search result

# numResponses: 2
# numEntries: 1

■ldapserchで再チェック

$ ldapsearch -h localhost -x -b 'dc=openldap,dc=local' 'uid=ldapuser' | grep -v "^#\|^\$"
dn: uid=ldapuser,ou=People,dc=openldap,dc=local
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
uid: ldapuser
uidNumber: 10000
gidNumber: 10000
loginShell: /bin/bash
homeDirectory: /home/ldapuser
cn: OpenLdap Div
search: 2
result: 0 Success

$ sudo slapcat | sed s/"\(Password\).*"/"\1"/g
dn: dc=openldap,dc=local
objectClass: top
objectClass: dcObject
objectClass: organization
o: openldap.local
dc: openldap
structuralObjectClass: organization
entryUUID: 8567a678-3bbd-1032-9b7a-1fb7218731c5
creatorsName: cn=admin,dc=openldap,dc=local
createTimestamp: 20130417151628Z
entryCSN: 20130417151628.355268Z#000000#000#000000
modifiersName: cn=admin,dc=openldap,dc=local
modifyTimestamp: 20130417151628Z

dn: cn=admin,dc=openldap,dc=local
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword
structuralObjectClass: organizationalRole
entryUUID: 85682922-3bbd-1032-9b7b-1fb7218731c5
creatorsName: cn=admin,dc=openldap,dc=local
createTimestamp: 20130417151628Z
entryCSN: 20130417151628.358638Z#000000#000#000000
modifiersName: cn=admin,dc=openldap,dc=local
modifyTimestamp: 20130417151628Z

dn: ou=Group,dc=openldap,dc=local
objectClass: organizationalUnit
objectClass: top
ou: Group
structuralObjectClass: organizationalUnit
entryUUID: 913fecca-3bbe-1032-8b2b-b3d75d519a9d
creatorsName: cn=admin,dc=openldap,dc=local
createTimestamp: 20130417152357Z
entryCSN: 20130417152357.724346Z#000000#000#000000
modifiersName: cn=admin,dc=openldap,dc=local
modifyTimestamp: 20130417152357Z

dn: cn=ldapgroup,ou=Group,dc=openldap,dc=local
objectClass: posixGroup
cn: ldapgroup
gidNumber: 10000
memberUid: ldapuser
structuralObjectClass: posixGroup
entryUUID: 2b9b16d2-3bbf-1032-8b2d-b3d75d519a9d
creatorsName: cn=admin,dc=openldap,dc=local
createTimestamp: 20130417152816Z
entryCSN: 20130417152816.690922Z#000000#000#000000
modifiersName: cn=admin,dc=openldap,dc=local
modifyTimestamp: 20130417152816Z

dn: ou=People,dc=openldap,dc=local
objectClass: organizationalUnit
objectClass: top
ou: People
structuralObjectClass: organizationalUnit
entryUUID: 07abcc38-3bcb-1032-8be2-cd786f60932a
creatorsName: cn=admin,dc=openldap,dc=local
createTimestamp: 20130417165310Z
entryCSN: 20130417165310.363161Z#000000#000#000000
modifiersName: cn=admin,dc=openldap,dc=local
modifyTimestamp: 20130417165310Z

dn: uid=ldapuser,ou=People,dc=openldap,dc=local
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
uid: ldapuser
userPassword
uidNumber: 10000
gidNumber: 10000
loginShell: /bin/bash
homeDirectory: /home/ldapuser
cn: OpenLdap Div
structuralObjectClass: account
entryUUID: 32b4a4b8-3bcb-1032-8be4-cd786f60932a
creatorsName: cn=admin,dc=openldap,dc=local
createTimestamp: 20130417165422Z
entryCSN: 20130417165422.563192Z#000000#000#000000
modifiersName: cn=admin,dc=openldap,dc=local
modifyTimestamp: 20130417165422Z

■SSHログインチェック
 ※ログイン出来ない場合は、「/var/log/auth.log」を確認。
  認証失敗のほとんどは、LDAPの設定のどこかで連携できていない設定不備。

$ ssh ldapuser@localhost