お世話になっております、SIOS 那賀です。
Scientific Linux 6.1 で OpenLDAP のサーバを立てようとして、はたと止まってしまいました。RHEL5 系まででお馴染みの /etc/openldap/slapd.conf がありません。どうやら RHEL6 からは、以前は slapd.conf に記述していたメタデータも、論理的には DN "cn=config" のノードの下に、物理的には /etc/openldap/slapd.d/ 以下に、LDIF を用いた「dynamic runtime configuration engine」なるデータ構造で格納されるように変更されたようです。それに伴い他のノードと同様、汎用の DIT 操作コマンドを用いて、しかも動的に設定できるようになっています。詳しくは RHEL6 の「移行管理ガイド」の「7.3.1 slapd 設定を変換する」や、本家ドキュメントの「OpenLDAP Software 2.4 Administrator's Guide: Configuring slapd」等を参照してください。
追記 (Mon Dec 12 2011): こちらの記事では slapd.d/ で頑張っていましたが、面倒になってしまい slapd.conf に戻ってしまった記事はこちら→「SIOS OSS Tech: RHEL6.1~系の OpenLDAP (slapd.conf) で SSH 公開鍵配布」。
RHEL6 系の初期 slapd.d/ は何のため?
さて、ここで一旦、少々脇道にそれます。上記のサイトを参照すると、既存の slapd.conf があるならば、slaptest コマンドで変換して slapd.d/ を作れば良いように読めますが、では、新規インストールをした場合にはどうすれば良いのでしょう? アップデートではなく新規で openldap-servers パッケージを入れても、以下のように、ちゃんとデータが構築されているように見えます。
[root@dirserv ~]# find /etc/openldap/slapd.d/
/etc/openldap/slapd.d/
/etc/openldap/slapd.d/cn=config.ldif
/etc/openldap/slapd.d/cn=config
/etc/openldap/slapd.d/cn=config/olcDatabase={-1}frontend.ldif
/etc/openldap/slapd.d/cn=config/olcDatabase={2}monitor.ldif
/etc/openldap/slapd.d/cn=config/olcDatabase={0}config.ldif
/etc/openldap/slapd.d/cn=config/cn=schema
/etc/openldap/slapd.d/cn=config/cn=schema/cn={11}collective.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={10}ppolicy.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={3}duaconf.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={9}openldap.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={0}corba.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={7}misc.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={2}cosine.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={6}java.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={4}dyngroup.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={5}inetorgperson.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={8}nis.ldif
/etc/openldap/slapd.d/cn=config/cn=schema/cn={1}core.ldif
/etc/openldap/slapd.d/cn=config/cn=schema.ldif
/etc/openldap/slapd.d/cn=config/olcDatabase={1}bdb.ldif
しかしこのデータ、アクセスしようにも、rootdn のパスワードが分かりません。RHEL の文書を見ても書かれていないようです。以下のように、ファイルも誰の持ち物でもありません。
[root@dirserv ~]# rpm -qf /etc/openldap/slapd.d/* file /etc/openldap/slapd.d/cn=config is not owned by any package file /etc/openldap/slapd.d/cn=config.ldif is not owned by any package
ということは、インストールの際に動的に作成しているのでしょう。%postinstall のスクリプトを見てみます。
[root@dirserv ~]# rpm -q --scripts openldap-servers
(中略。↓ インストール後のスクリプトにおいて、)
postinstall scriptlet (using /bin/sh):
(中略。↓ slapd.d/ ディレクトリが存在しなければ、)
# generate configuration in slapd.d
if ! ls -d /etc/openldap/slapd.d/* &>/dev/null; then
(中略。↓ slapd.conf.obsolete なるファイルをコピーしてきて、)
[ $fresh_install -eq 0 ] && \
cp /usr/share/openldap-servers/slapd.conf.obsolete \
/etc/openldap/slapd.conf
(中略。↓ config 用のエントリを加えて、)
cat >> /etc/openldap/slapd.conf << EOF
database config
rootdn "cn=admin,cn=config"
#rootpw secret
EOF
(中略。slaptest コマンドで slapd.d/ 形式に変換します。)
slaptest -f /etc/openldap/slapd.conf \
-F /etc/openldap/slapd.d > /dev/null 2> /dev/null
上記のとおり、「#rootpw secret」となっています。パスワードは未設定です。これではアクセスできませんね。
さらに余談として、Ubuntu でも rootdn のパスワードは設定されていないのですが、かわりに、root ユーザで SASL EXTERNAL 認証でアクセスすると、何でもできるように考慮されています。Ubuntu 10.04 サーバガイドの「OpenLDAP Server」の項などを見ると、SASL EXTERNAL の接続でサクサクと rootpw を設定しているのに、なぜ RHEL で同じことができないのかと思えば、そういうことでした。
debian/slapd.init.ldif:
# Frontend settings
dn: olcDatabase={-1}frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: {-1}frontend
(中略)
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
debian/slapd.install:
debian/slapd.init.ldif usr/share/slapd:
debian/slapd.postinst:
create_new_configuration() {
(中略)
init_ldif="/usr/share/slapd/slapd.init.ldif"
(中略)
capture_diagnostics slapadd -F "${SLAPD_CONF}" \
-b "cn=config" -l ${init_ldif} || failed=1
もっとも Ubuntu でも、従来 (2.4.21-0ubuntu5 以前) はこの点が考慮されていなかったらしく、アップデートの際には既存のデータに対して、下記のように sed で内部表現をゴリゴリと書き換えているんですけれどね。
debian/slapd.postinst:
postinst_upgrade_configuration() {
(中略)
# Grant manage access to connections made by the root user via
# SASL EXTERNAL
if previous_version_older 2.4.21-0ubuntu5 ; then
if [ -d "$SLAPD_CONF" ]; then
# Stick the new olcAccess at the begining of the
# olcAccess list (using an index of 0 *and*
# adding it as early as possible in the ldif file)
# to make sure that local root has access to the
# database no matter what other acls say.
sed -i 's/^\(olcDatabase: {-1}frontend\)/\0\nolcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break/' "${SLAPD_CONF}/cn=config/olcDatabase={-1}frontend.ldif"
sed -i 's/^\(olcDatabase: {0}config\)/\0\nolcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break/' "${SLAPD_CONF}/cn=config/olcDatabase={0}config.ldif"
fi
fi
これ同様に sed で書き換えるなり、以下のように slapd.d/cn=config/olcDatabase={0}config.ldif に "olcRootPW" のエントリをねじ込むなりしてサービスを上げ直せば、パスワードを設定することは可能です。これは、いよいよの「rootdn のパスワード忘れちゃった!」の際にも役に立つでしょう。
[root@dirserv ~]# service slapd stop
Stopping slapd: [ OK ]
[root@dirserv ~]# slappasswd -s secret1
{SSHA}QVHYz50xBxpbbEa5qO+5cn7jDktBVXr4
[root@dirserv ~]# echo 'olcRootPW:{SSHA}QVHYz50xBxpbbEa5qO+5cn7jDktBVXr4' >> /etc/openldap/slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif
[root@dirserv ~]# service slapd startx
Starting slapd: [ OK ]
[root@dirserv ~]# ldapsearch -x -D "cn=admin,cn=config" -b "cn=config" -w secret1 "(olcRootDN=*)"
# extended LDIF
#
# LDAPv3
# base <cn=config> with scope subtree
# filter: (olcRootPW=*)
# requesting: ALL
#
# {0}config, config
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to * by * none
olcAddContentAcl: TRUE
olcLastMod: TRUE
olcMaxDerefDepth: 15
olcReadOnly: FALSE
olcRootDN: cn=admin,cn=config
olcRootPW: {SSHA}QVHYz50xBxpbbEa5qO+5cn7jDktBVXr4
olcSyncUseSubentry: FALSE
olcMonitoring: FALSE
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
ではなぜ RHEL6 では、アクセス手段のない slapd.d/ をわざわざ作っているのでしょうか? 実は最新の OpenLDAP の slapd でも、slapd.d/ が無いところへユーザが slapd.conf を置けば、従来と同様に slapd は slapd.conf から設定を読み込んでしまうのです (詳しくは openldap-*/servers/slapd/bconfig.c の read_config() 関数を読んでください)。よって、新規の際の slapd.d/ は、従来の slapd.conf 流の設定をあっさりとは使わせないようにするために、教育的見地からダミーとして置かれているものと見て良いでしょう。
さて、以上のようにデフォルトの slapd.d/ が単なるダミーであることが分かりましたし、本家の文書もRed Hat の文書も共に、slapd.d/ 以下を手で編集するのはイカン、お行儀が悪いと言っておりますので、何ら躊躇することなく slapd.d/ 以下を削除して、自前の slapd.conf から slaptest コマンドで slapd.d/ を新規生成することにしましょう。
閑話休題、やっと本題に入ります。
サーバの設定
まずはいつものように、SELinux と iptables の無効化です。実運用のサーバでは、運用ポリシーに従って、それぞれ適切に設定してください。
[root@dirserv ~]# setenforce permissive [root@dirserv ~]# getenforce Permissive [root@dirserv ~]# service iptables stop iptables: ファイアウォールルールを消去中: [ OK ] iptables: チェインをポリシー ACCEPT へ設定中filter [ OK ] iptables: モジュールを取り外し中: [ OK ] [root@dirserv ~]#
サーバと、操作用のクライアントをインストールします。
[root@dirserv ~]# yum install -y openldap-clients openldap-servers
"Obsolete" のファイルを元に、slapd.conf を作成します。
[root@dirserv ~]# slappasswd -s secret2
{SSHA}Z42Qdb/r/YAw0QRD8vI/SYcLgoxtzF4l
[root@dirserv ~]# cp /usr/share/openldap-servers/slapd.conf.obsolete slapd.conf
[root@dirserv ~]# vi slapd.conf
[root@dirserv ~]# diff -uNr /usr/share/openldap-servers/slapd.conf.obsolete slapd.conf
--- /usr/share/openldap-servers/slapd.conf.obsolete
+++ slapd.conf
@@ -64,9 +64,9 @@
# /etc/pki/tls/certs, running "make slapd.pem", and fixing permissions on
# slapd.pem so that the ldap user or group can read it. Your client software
# may balk at self-signed certificates, however.
-# TLSCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
-# TLSCertificateFile /etc/pki/tls/certs/slapd.pem
-# TLSCertificateKeyFile /etc/pki/tls/certs/slapd.pem
+TLSCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
+TLSCertificateFile /etc/pki/tls/certs/slapd.pem
+TLSCertificateKeyFile /etc/pki/tls/certs/slapd.pem
# Sample security restrictions
# Require integrity protection (prevent hijacking)
@@ -95,14 +95,30 @@
#
# rootdn can always read and write EVERYTHING!
+access to attrs=userPassword
+ by dn="cn=Manager,dc=example,dc=com" write
+ by self write
+ by anonymous auth
+ by * none
+
+access to *
+ by dn.exact="cn=Manager,dc=example,dc=com" write
+ by self write
+ by * read
+
#######################################################################
# ldbm and/or bdb database definitions
#######################################################################
+database config
+rootdn "cn=admin,cn=config"
+rootpw {SSHA}QVHYz50xBxpbbEa5qO+5cn7jDktBVXr4
+
database bdb
-suffix "dc=my-domain,dc=com"
+suffix "dc=example,dc=com"
checkpoint 1024 15
-rootdn "cn=Manager,dc=my-domain,dc=com"
+rootdn "cn=Manager,dc=example,dc=com"
+rootpw {SSHA}Z42Qdb/r/YAw0QRD8vI/SYcLgoxtzF4l
# Cleartext passwords, especially for the rootdn, should
# be avoided. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
(動いているようであれば) サービスを停止し、現在のデータを削除してから、新しいデータを作り、再度起動します。今回はテストなので、インデックスも BDB の設定も、そのまま放置します。実運用では、パフォーマンスやバックアップにも気をつかってあげてください。
[root@dirserv ~]# service slapd stop slapd を停止中: [失敗] [root@dirserv ~]# rm -fr /etc/openldap/slapd.d/* /var/lib/ldap/* [root@dirserv ~]# slaptest -f slapd.conf -F /etc/openldap/slapd.d/ bdb_db_open: warning - no DB_CONFIG file found in directory /var/lib/ldap: (2). Expect poor performance for suffix "dc=example,dc=com". bdb_db_open: database "dc=example,dc=com": db_open(/var/lib/ldap/id2entry.bdb) failed: No such file or directory (2). backend_startup_one (type=bdb, suffix="dc=example,dc=com"): bi_db_open failed! (2) slap_startup failed (test would succeed using the -u switch) [root@dirserv ~]# chown -R ldap.ldap /etc/openldap/slapd.d/* /var/lib/ldap/* [root@dirserv ~]# service slapd start slapd を起動中: [ OK ]
以下は任意ですが、サーバの挙動が分かりやすいように、ログの出力も設定しておきます。slapd は local4 のファシリティで syslog 出力をするのですが、せっかくの RHEL6 系の rsyslog ですので、アプリケーション名 ("slapd") でログを振り分けるようにしてみます。実運用では、ログが溢れないように、ローテートの設定もしておいてください。
[root@dirserv ~]# cp /etc/rsyslog.conf /etc/rsyslog.conf.orig [root@dirserv ~]# vi /etc/rsyslog.conf [root@dirserv ~]# diff -uNr /etc/rsyslog.conf.orig /etc/rsyslog.conf --- /etc/rsyslog.conf.orig +++ /etc/rsyslog.conf @@ -76,3 +76,6 @@ # remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional #*.* @@remote-host:514 # ### end of the forwarding rule ### + +!slapd +*.* /var/log/slapd.log [root@dirserv ~]# service rsyslog reload Reloading system logger... [ OK ]
アクセスできるかどうか、試してみます。
[root@dirserv ~]# ldapsearch -x -D "cn=admin,cn=config" -b "cn=config" -w secret1 "(olcRootDN=*)" [root@dirserv ~]# ldapsearch -x -D "cn=Manager,dc=example,dc=com" -b "dc=example,dc=com" -w secret2
良いようであれば、認証用のデータを入れて行きます。根元から作って行きます。
[root@dirserv ~]# ldapadd -x -D "cn=Manager,dc=example,dc=com" -w secret2 <<EOF dn: dc=example,dc=com dc: example objectClass: dcObject objectClass: organization o: Example Corp. dn: cn=Manager,dc=example,dc=com cn: Manager objectClass: organizationalRole dn: o=Users,dc=example,dc=com o: Linux Users objectClass: organization dn: ou=People,o=Users,dc=example,dc=com ou: People objectClass: organizationalUnit dn: ou=Group,o=Users,dc=example,dc=com ou: Group objectClass: organizationalUnit EOF adding new entry "dc=example,dc=com" adding new entry "cn=Manager,dc=example,dc=com" adding new entry "o=Users,dc=example,dc=com" adding new entry "ou=People,o=Users,dc=example,dc=com" adding new entry "ou=Group,o=Users,dc=example,dc=com"
ちょっと間違うと、途中まで作ったところでエラーになり、そこまでの分が半端に残ります。failure atomic ではありません…、トランザクションがあればいいのにね。今回はテストですので、そんな時は、以下のように根元からガバッと再帰で消してしまってください。
[root@dirserv ~]# ldapdelete -v -x -D "cn=Manager,dc=example,dc=com" -w secret2 -r "dc=example,dc=com"
ユーザ (foo と bar) を追加します。OpenLDAP のクライアント側 (SSSD, pam_ldap, nss-pam-ldapd 等) は、文書にはあまりキチンと書かれていないのですが (せいぜい /usr/share/doc/nss-pam-ldapd-0.7.5/README くらいか)、デフォルトで、クラス "posixAccount" や "posixShadow" を持つノードを、ユーザ情報として取りにきます。ですので、実はツリー構造は割と恣意的に決めてしまっても問題ありません。
[root@dirserv ~]# slappasswd -s secret3
{SSHA}LAs1y8ozcRtUNMVZh3Sj+t8Vn/48HJV3
[root@dirserv ~]# ldapadd -x -D "cn=Manager,dc=example,dc=com" -w secret2 <<EOF
dn: uid=foo,ou=People,o=Users,dc=example,dc=com
objectClass: top
objectClass: posixAccount
objectClass: account
gecos: ldap system users
cn: foo
uid: foo
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/foo
loginShell: /bin/bash
userPassword: {SSHA}LAs1y8ozcRtUNMVZh3Sj+t8Vn/48HJV3
EOF
adding new entry "uid=foo,ou=People,o=Users,dc=example,dc=com"
[root@dirserv ~]# slappasswd -s secret4
{SSHA}8XOqcgEYQjI9vFreV8j6dc6B6Fjovfts
[root@dirserv ~]# ldapadd -x -D "cn=Manager,dc=example,dc=com" -w secret2 <<EOF
dn: uid=bar,ou=People,o=Users,dc=example,dc=com
objectClass: top
objectClass: posixAccount
objectClass: account
gecos: ldap system users
cn: bar
uid: bar
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/bar
loginShell: /bin/bash
userPassword: {SSHA}8XOqcgEYQjI9vFreV8j6dc6B6Fjovfts
EOF
adding new entry "uid=bar,ou=People,o=Users,dc=example,dc=com"
グループ (foo と bar) を追加します。こちらも同様に、クライアントはデフォルトで、クラス "posixGroup" を持つノードを探索に来ます。今回は、昨今の Linux ディストリビューションの構成と同様に、UPG (User Private Group) 式で、ユーザごとに個別に同名のグループを割り当てますが、LDAP 的には、共通のグループを割り当てる方が一般的かも知れません。
[root@dirserv ~]# ldapadd -x -D "cn=Manager,dc=example,dc=com" -w secret2 <<EOF
dn: cn=foo,ou=Group,o=Users,dc=example,dc=com
cn: foo
objectClass: posixGroup
gidNumber: 1000
userPassword: {CRYPT}x
EOF
adding new entry "cn=foo,ou=Group,o=Users,dc=example,dc=com"
[root@dirserv ~]# ldapadd -x -D "cn=Manager,dc=example,dc=com" -w secret2 <<EOF
dn: cn=bar,ou=Group,o=Users,dc=example,dc=com
cn: bar
objectClass: posixGroup
gidNumber: 1001
userPassword: {CRYPT}x
EOF
adding new entry "cn=bar,ou=Group,o=Users,dc=example,dc=com"
一般ユーザから、他人のパスワードが見えないことを確認しておきます。
[root@dirserv ~]# ldapsearch -x -D "uid=foo,ou=People,o=Users,dc=example,dc=com" -b "dc=example,dc=com" -w secret3 "(objectClass=posixAccount)" [root@dirserv ~]# ldapsearch -x -D "uid=bar,ou=People,o=Users,dc=example,dc=com" -b "dc=example,dc=com" -w secret4 "(objectClass=posixAccount)"
認証依頼元の Linux ホストの設定
こちらも同様に、SELinux と iptables の無効化です。実運用のサー (以下テンプレ略)。
[root@linhost ~]# setenforce permissive [root@linhost ~]# getenforce Permissive [root@linhost ~]# service iptables stop iptables: ファイアウォールルールを消去中: [ OK ] iptables: チェインをポリシー ACCEPT へ設定中filter [ OK ] iptables: モジュールを取り外し中: [ OK ] [root@linhost ~]#
RHEL5 系の nss_ldap から、RHEL6 系では PAM は pam_ldap に、NSS は nss_ldap からフォークした nss-pam-ldapd へと分離しており、また、それらを束ねる SSSD 抽象化レイヤ (詳細) が入っていたりと、設定ファイルが多岐に渡り、もはや手作業では手に負えなくなっているので、authconfig コマンドを使用します。
同時に、TLS (389 番ポートでの "STARTTLS" による接続) も設定します。authconfig では、認証局ナシでの TLS 設定ができないので、設定をした後で、ちょっとだけ手を入れる必要があります。
SSSD を用いる手順:
[root@linhost ~]# authconfig --disableforcelegacy --enablemkhomedir --enableldap --enableldapauth --enableldaptls --ldapserver=dirserv.vnat --ldapbasedn="dc=example,dc=com" --update sssd を起動中: [ OK ] oddjobd を起動中: [ OK ] [root@linhost ~]# cat <<EOF >> /etc/sssd/sssd.conf ldap_tls_reqcert = never EOF [root@linhost ~]# cat <<EOF >> /etc/nslcd.conf tls_cacertfile /etc/pki/tls/certs/ca-bundle.crt tls_checkpeer no EOF [root@linhost ~]# service sssd restart sssd を停止中: [ OK ] sssd を起動中: [ OK ]
旧来の (legacy な) 手順:
[root@linhost ~]# authconfig --enableforcelegacy --enablemkhomedir --enableldap --enableldapauth --enableldaptls --ldapserver=dirserv.vnat --ldapbasedn="dc=example,dc=com" --update nslcd を起動中: [ OK ] oddjobd を起動中: [ OK ] [root@linhost ~]# cat <<EOF >> /etc/nslcd.conf tls_cacertfile /etc/pki/tls/certs/ca-bundle.crt tls_reqcert no EOF [root@linhost ~]# service nslcd restart nslcd を停止中: [ OK ] nslcd を起動中: [ OK ] [root@linhost ~]# cat <<EOF >> /etc/pam_ldap.conf tls_cacertfile /etc/pki/tls/certs/ca-bundle.crt tls_checkpeer no EOF
では、動作を確認してみます。
[root@linhost ~]# id foo uid=1000(foo) gid=1000(foo) 所属グループ=1000(foo) [root@linhost ~]# su - foo Creating home directory for foo. [foo@linhost ~]$ su - bar パスワード: secret4 Creating home directory for bar. [bar@linhost ~]$ id uid=1001(bar) gid=1001(bar) 所属グループ=1001(bar) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [bar@linhost ~]$
良いようですね。では。
0 コメント:
コメントを投稿