http://minitrue.googlecode.com/svn-history/r112/trunk/txt/ch12.txt
第 12 章 使用 OpenLDAP 提供集中式网络目录服务
12.0 介绍
我相信,知道如何管理一个轻量级目录访问协议(LDAP)目录服务器,已成为网络管理员的必备技能。LDAP 目录是使网络保持简单的关键所在。它是你的全局跨平台跨应用目录,支持简化的网络验证,以及集中的公司数据存储。LDAP 是跨平台、网络自适应和基于标准的协议。现在已有大量 LDAP 实现,在本章中,我们将使用优秀的免费自由软件 OpenLDAP。
LDAP 被众多应用程序广泛支持,例如,大多数电子邮件客户端都带有 LDAP 客户端。另外,多数数据库、内容管理系统(CMS)、群件和消息服务器、验证服务器、客户管理应用和应用服务器都能与 LDAP 服务器对话。
某些人喜欢争论 LDAP 是不是数据库。严格来说,这是一种协议,而不是数据库。它访问的是一种为高速读取进行特别优化的数据库。可以将它用于相对静态的信息,比如公司目录、用户数据、客户数据、密码、资产追踪和密钥等。OpenLDAP 使用 Sleepycat Berkeley DB。
为什么不用一个普通的关系数据库,比如 PostgreSQL、Oracle 或者 MySQL 呢?如果你喜欢的话当然可以,但是你会失去 LDAP 所带来的好处,也就是:
• 高速读取
• 灵活的数据类型
• 几近通用的应用支持
• 细化数据访问控制
• 分布式存储和复制
• 无需数据库专家级管理员
• 无需定制 API
你不应该将 OpenLDAP 作为网店或者网站的后端,比如,不能用于任何需要快速频繁变更的应用程序。那里才要用到关系型数据库管理系统(RDBMS)。
Sleepycat BDB 与关系数据库的结构有所不同。不像关系数据库,以栏目和行的形式存储信息,而且有一个严格的索引和字段集合,这里的数据是以属性类型/属性值配对形式存储的。这样的结构在设计数据形式时提供了极大的灵活性。以某种特殊的用户记录为例,可以添加新的数据类型,而无须重新设计整个数据库。你可以存储任何种类的文本或二进制数据。因为这就像一个大的普通文件一样简单,添加新条目也非常方便——只要把它们附加上去即可。OpenLDAP 支持分布式的架构、复制和加密。
LDAP 目录结构
让我们回顾一下 LDAP 目录的基本概念和结构。这比拥有关于配置选项的广博知识更为重要,因为如果你对于自己需要什么,以及各个部分相互之间的联系没有清晰的概念,那么 LDAP 就是一团神秘的迷雾。但其实它并没有那么神秘,一旦你掌握了基本概念,那么就能很快进入状态。正如教练们经常说的,首先得打好基础。LDAP 目录可以画成一张标准的自顶向下树状结构图,根位于顶部,而分支逐级向下延展。图 12-1 是一个层级命名空间,它也被称为目录信息树(DIT)。
{{附图}}
图 12-1。一个 LDAP 层级样例。
这个目录样例的根是 country 条目。下一站是 state 条目,然后是 organizational unit(OU)条目,也就是公司名称。从这里分为两个不同的公司条目,因此也被称为 organizational units。左边的分支以用户 ID(UID)终结。质量保证(QA)OU 可以容纳多个用户,而不仅是样例中的一个。
现在要说到重点了:Terry Jones 有一个 Distinguished Name(DN),由 Terry 的 Relative Distinguished Name(RDN)组成,在这个例子中就是 UID,还要加上所有上级条目:uid=terryjones, ou=qa, ou=alrac's cookies, ou=or, c=us。任何属性都可以是 RDN,它必须在所属等级的众多条目中保持唯一。UID 通常是唯一的,因为它是用户登录的基本要素,但是你也可以使用其它任何属性。显然,这里需要一点小常识,例如,有很多重复的姓氏,那么使用 SN 属性就会导致问题。最常用于标识人的 RDN 是 UID 或 Common Name(CN)。
目录的基本单元是条目(entry)。条目也被成为记录(record)或目录对象(directory object)。Terry Jones 的条目包含了大量属性(attribute),诸如姓名、电话号码、email 地址,等等。你不能凭空杜撰属性,它们必须是在 OpenLDAP 中已经定义的。一种查看它们的方便途径是使用 GQ LDAP 客户端( http://sourceforge.net/projects/gqclient/)。你也可以在 /etc/ldap/schema(Fedora 上是 /etc/openldap/schema)目录文件中看到 objectClass 的定义。
你可以创建自己的 objectClass 定义和属性类型。我不建议这样做,除非你一定需要那些没有被包括进去的东西。默认的 schema 是可扩展的,而且已经有人为了将它们通用化而付出了巨大努力,没有必要重新发明轮子。另一方面(总会有另外一面,不是吗),这样可以使 OpenLDAP 变得更为灵活、更容易扩展,而且可以很方便地共享定制的 schema。
每个属性都是由属性类型和属性值组成的。属性可以有多个值,例如,Terry Jones 的条目可能会是这样:
uid=terryjones
cn=Terry Jones
gn=Terry
sn=Jones
telephoneNumber=123-456-7890
telephoneNumber=123-456-7891
上面显示了两个重复的属性。你可以任意使用多个重复属性。重复属性常见的用途是人名,比如:
cn=Terry Jones
cn=T. Jones
cn=Terry "codefiend" Jones
cn=Codefiend
这样设置的结果是,搜索任何一个属性值都能成功,所以 Terry Jones 就无所遁形了。后缀(suffix)或命名上下文(naming context)位于 LDAP 层级体系的顶端。在我们这个简单的例子中,后缀是 c=us。近来流行的一种常见办法是使用公司的域名,比如 dc=alrac,dc=net。DC 表示域组件(domain component)。
Schema、objectClass 与属性
当你在 DIT 中创建了一个条目时,它的数据包含在属性中。它们都属于 objectClass。Schema 可以认为是装有 objectClass 的大口袋。所以,当听到某些人讨论 OpenLDAP schema 的时候,你就知道他们指的是定义 OpenLDAP 目录中组织和数据类型的文件。在 OpenLDAP 中,某些 schema 是在 slapd 中硬编码的。
objectClass 是 objectClass 层级体系的一部分。它从父母那里继承了所有属性。例如,inetOrgPerson objectClass 是你经常要用到的。如果查看一下 /etc/ldap/schema/inetorgperson.schema,你就能找到这个定义:
objectclass ( 2.16.840.1.113730.3.2.2
NAME 'inetOrgPerson'
DESC 'RFC2798: Internet Organizational Person'
SUP organizationalPerson
STRUCTURAL
这一段说明该长串 objectClass 数字是一个正式的对象 ID(OID)号码。所有 LDAP OID 都是全局唯一的,你不能自行杜撰。仅在你创建一个定制 schema 并且需要某些新 OID 时,才会有关系。然后,寻找一个注册机构分配一些号码给你,比如 Internet 号码分配机构(IANA)。
SUP(上级) organizationalPerson 这一行告诉你,它的上一级 objectClass 是 organizationalPerson,也就是顶级 objectClass person 的子节点。objectClass 定义了所有子节点的必要和可选属性,你可以在任何 LDAP 浏览器中读到。
STRUCTURAL 表示该 objectClass 可以用于在你的 DIT 中创建条目,你还能看到 AUXILARY objectClass,这些都不能独立存在,而必须与 STRUCTURAL objectClass 一起使用。
objectClass 同样也是一种属性。
如果现在不太明白,也别担心。当你创建了一个简单的目录之后,就知道它是如何实现的了。
“秘密的” RootDSE
还有一点你应该知道:rootDSE。这是那些聪明的自我引用式极客名称之一:DSE 表示 DSA 特定条目,而 DSA 表示目录系统代理。这是 LDAP 层级体系中不可见的最高等级条目,也是 LDAP 服务器的内置属性。若要查看它们,可以在 LDAP 服务器上运行以下两条命令:
$ ldapsearch -x -s base -b "" +
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: +
#
#
dn:
structuralObjectClass: OpenLDAProotDSE
configContext: cn=config
namingContexts: dc=alrac,dc=net
supportedControl: 2.16.840.1.113730.3.4.18
supportedControl: 2.16.840.1.113730.3.4.2
[...]
supportedFeatures: 1.3.6.1.4.1.4203.1.5.4
supportedFeatures: 1.3.6.1.4.1.4203.1.5.5
supportedLDAPVersion: 3
supportedSASLMechanisms: DIGEST-MD5
supportedSASLMechanisms: CRAM-MD5
supportedSASLMechanisms: NTLM
entryDN:
subschemaSubentry: cn=Subschema
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
所有那些长串数字都是正式的对象识别符(OID)。要学习更多关于它们的内容,可访问: http://www.alvestrand.no/objectid/ 。该网站包括了一个可以搜索的数据库,所以你就能查看特定 OID 的含义。
这条命令显示同样的输出内容,以及整个 subschema:
$ ldapsearch -x -s base -b "cn=subschema" objectclasses
[...]
# Subschema
dn: cn=Subschema
objectClasses: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRAC
T MUST objectClass )
objectClasses: ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject' DESC 'RF
C2252: extensible object' SUP top AUXILIARY )
objectClasses: ( 2.5.6.1 NAME 'alias' DESC 'RFC2256: an alias' SUP top STRUCTU
RAL MUST aliasedObjectName )
objectClasses: ( 2.16.840.1.113730.3.2.6 NAME 'referral' DESC 'namedref: named
subordinate referral' SUP top STRUCTURAL MUST ref )
objectClasses: ( 1.3.6.1.4.1.4203.1.4.1 NAME ( 'OpenLDAProotDSE' 'LDAProotDSE'
) DESC 'OpenLDAP Root DSE object' SUP top STRUCTURAL MAY cn )
objectClasses: ( 2.5.17.0 NAME 'subentry' SUP top STRUCTURAL MUST ( cn $ subtr
eeSpecification ) )
[...]
那是跟你的 /etc/ldap/schema 文件完全相同的内容。你无需对 rootDSE 做任何事,这里只是展示一下,看看它长什么样。rootDSE 有时会与 root DN 混淆,但它们不是同一个东西。rootDSE 是你的裸 OpenLDAP 服务器,包括 schema 和所支持的协议。你可能在很多文档中看到 root DN 作为后缀名,或者数据层级体系的基础名出现。我会避免使用 root DN 术语,它太容易混淆了。哦,还有 rootdn。那是目录的超级用户,rootdn 和 rootpw 指令会在 slapd.conf 中出现。是的,这也比较容易混淆。rootdn 权力太大,很多管理员都不喜欢设立 rootdn,而是创建一些在目录内部定义的管理用户。
决定目录的深度
你试图规划未来,而且想把 DIT 设计为可以随着组织成长而自然无缝扩张的架构。这是一个宏伟的目标,那是肯定的!所以,你在考虑把它的结构变得更宽更扁,还是更窄更深。这是所有 LDAP 管理员要面临的问题,而且标准答案永远是“这要看情况而定”。我自己的偏好是采用一种扁平的目录结构,因为这样比较容易维护,而且 LDAP 是为了在一个水平上搜索而进行优化的,而不是在整个层级体系中上下求索。
图 12-2 展示了一个具有三个 OU 的 DIT:
{{附图}}
图 12-2。DIT 发芽抽枝。
这看上去很漂亮,而且很有组织,不是吗?三个不同的部门都有它们各自的 OU,这感觉很舒服,就像一个整洁的文件柜。但是想想这个问题——当 Jenn 从 Upstairs 移动到 Downstairs 时会怎样?你得将她从 Upstairs 删除,还要在 Downstairs 中创建一个新的,这需要不少步骤,无论你有多么高的效率。
现在,看看图 12-3。
{{附图}}
图 12-3。DIT 被切断了。
所有用户都集中到了 People OU。我们如何才能知道他们属于那些部门?通过给他们分配一个额外的 OU 属性,象这样:
dn: cn=Jenn Dancer,ou=people,dc=foo,dc=com
objectClass: inetOrgPerson
cn: Jenn Dancer
ou=Upstairs
[...]
Jenn 想搬到 Downstairs?小菜一碟。我所要做的就是运行 ldapmodify 或者某个图形化的 LDAP 浏览器,将 ou=Upstairs 改为 ou=Downstairs,还有其它变更(例如,电话号码和职位)。这样比把她移动到某个新的 OU 工作量减少一半,只需要下列步骤:
• 将现有条目通过 ldapsearch 输出到一个 LDIF 文件中。
• 用 ldapdelete 删除记录。
• 编辑 LDIF 文件。
• 用 ldapadd 添加到新的 OU 中。
你可能还会考虑将权力下放给初级管理员,或者是如何保护敏感数据等问题。可能意味着要把某些数据存储在不同的子树或独立的数据库中,这样会使管理复杂一点,但是可以让你控制谁能获得读写权限。
这永远不是一个容易阐述的话题,而且如果你去问另外五位 LDAP 管理员的建议,可能会得到八种不同的意见。Gerald Carter 撰写的《LDAP 系统管理》(O'Reilly),特别有助于考虑规划目录拓扑。
12.1 在 Debian 上安装 OpenLDAP
问题
你准备开始工作,并且让 OpenLDAP 启动运行。在 Debian 上的最佳安装方式是什么?
解决方案
只要运行 Aptitude 并且安装这些软件包:
# aptitude install slapd ldap-utils gq db4.3-doc db4.2-util
你会被问及,是否创建一个 LDAP admin 密码。Debian 然后就会创建 LDAP admin 用户,并且将你现有的域名作为后缀,或者命名上下文。
然后,执行一次简单的搜索,确认服务器是否正在运行,以及能否响应请求:
# ldapsearch -xb '' -s base '(objectclass=*)' namingContexts
[...]
dn:
namingContexts: dc=alrac,dc=net
[...]
运行这条命令以展示 admin 用户:
$ ldapsearch -xb 'dc=alrac,dc=net'
[...]
# admin, alrac.net
dn: cn=admin,dc=alrac,dc=net
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
[...]
很好!结果说明是成功的。现在,你可以继续进行后面的步骤了。
讨论
Debian 创建了一个裸配置,还有一个 openldap 用户,你可以在 /etc/passwd 中看到,创建了启动文件并且在开机时启动,还给所有文件设置了正确的属主和权限。它还创建了 OpenLDAP admin 用户,它并不是像 openldap 这样的系统用户,而是一个位于 OpenLDAP 目录中的用户。
你可能已经在 OpenLDAP How-to 文档中看到要到 slapd.conf 中创建一个 rootdn 和 rootpw。rootdn 是数据库的超级用户,就像我们的 admin 用户,而 rootpw 是 rootdn 的口令。对于第一次创建的目录这是必需的,而且你可能喜欢以这种方式配置你的数据库超级用户。rootdn 会自动获得不受限制的所有访问权限,而且不需要访问控制,我们的 admin 用户也一样。
某些管理员出于安全的考虑,不想在 slapd.conf 中设置 rootpw。某些管理员不想在目录中设置超级用户,比如我们的 admin 用户,也同样出于安全的理由。如果你一定要将它保留在 slapd.conf 中,那么就得再三确认该文件被妥善保护——让它只能被属主和组所有者读取,并且只在你需要变更时打开写权限。
OpenLDAP 依赖于 Sleepycat Berkeley DB 作为其后端数据库。Aptitude 应该会把你需要的版本拉进来。db4.2-util 软件包含有管理 BDB 的基本命令。
db4.3-doc 软件包含有完整的 Sleepycat BDB 手册。它的目标读者是程序员,但是也包括了很多对于服务器管理员有用的信息。(不存在 db4.2-doc 软件包,软件包版本不匹配没有关系。)
获取与 Berkeley DB 版本匹配的 db4.*-util 版本。如果你不知道要找哪个软件包名称,dpkg 可以显示你的系统中已经安装的版本:
$ dpkg -l | grep db4
ii libdb4.2 4.2.52+dfsg-2 Berkeley v4.2 Database Libraries [runtime]
ii libdb4.3 4.3.29-8 Berkeley v4.3 Database Libraries [runtime]
ii libdb4.4 4.4.20-8 Berkeley v4.4 Database Libraries [runtime]
你可能会有多个版本,因为大量应用程序都使用 Berkeley DB 作为它们的后端。通过 apt-cache 寻找正确的 slapd 版本:
$ apt-cache depends slapd | grep db4
Depends: libdb4.2
你可以看到自己的后缀,也就是目录的基础名称,在 /etc/ldap/slapd.conf 中:
# The base of your directory in database #1
suffix "dc=alrac,dc=net"
这里是 ldapsearch 各选项的含义:
-x
通过明文验证绑定到目录。
-b
开始搜索。
-s
定义搜索范围。你的选项是 base、one 或者 sub。base 表示搜索 base 对象,one 搜索某个条目的直接子节点,但不包括条目本身,sub 搜索整个子树以及该条目。默认值为 sub。
你可以从源码安装,如果真想这么做的话。请访问 OpenLDAP.org( http://www.openldap.org/)获取更多说明。
参阅
• man ldapsearch
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
12.2 在 Fedora 上安装 OpenLDAP
问题
你准备开始工作,并且让 OpenLDAP 启动运行。在 Fedora 上的最佳安装方式是什么?
解决方案
只要运行 Yum 并且安装这些软件包:
# yum install openldap openldap-servers openldap-clients db4-utils gq
讨论
Fedora 的 OpenLDAP 实现需要花一点工夫。你得从头开始配置,修正某些文件属性,还要创建一个数据库配置文件——我们会在下一节中讲述。它会创建启动文件和一个 ldap 系统用户,而 Yum 负责处理依赖关系。
你可以从源码安装,如果真想这么做的话。请访问 OpenLDAP.org( http://www.openldap.org/)获取更多说明。
参阅
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
12.3 配置并测试 OpenLDAP 服务器
问题
安装 OpenLDAP 服务器很顺利,现在你该如何启动并进行测试?
解决方案
Debian 用户不需要阅读本节,因为 Debian 安装程序已经完成了所有工作,但无论如何,回顾一下总是有帮助的。
Fedora 用户,拷贝这个例子:/etc/openldap/slapd.conf。在括号中替换上你自己的域名(任何一个都行,甚至 example.com),并且填上你自己的 rootpw:
#######################################################################
# Global Directives:
# Schema and objectClass definitions
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
pidfile /var/run/slapd/slapd.pid
argsfile /var/run/slapd/slapd.args
# Read slapd.conf(5) for possible values
loglevel -1
# Where the dynamically loaded modules are stored
modulepath /usr/lib/ldap
moduleload back_bdb
# The maximum number of entries that is returned for a search operation
sizelimit 500
# The tool-threads parameter sets the actual amount of cpus that is used
# for indexing.
tool-threads 1
#######################################################################
# Specific Backend Directives for bdb:
# Backend specific directives apply to this backend until another
# 'backend' directive occurs
backend bdb
checkpoint 512 30
#######################################################################
# Specific Directives for database #1
database bdb
suffix "dc=[alrac],dc=[net]"
rootdn "cn=admin,dc=[alrac],dc=[net]"
rootpw [password]
# Where the database file are physically stored for database #1
directory "/var/lib/ldap"
# Indexing options for database #1
index objectClass eq
# Save the time that the entry gets modified, for database #1
lastmod on
# admin can read/write all passwords
# users can change their own passwords
access to attrs=userPassword,shadowLastChange
by dn="cn=admin,dc=alrac,dc=net" write
by anonymous auth
by self write
by * none
# many applications need read access to the rootDSE
# especially to read supported SASL mechanisms
# this restricts them to the rootDSE; they cannot read past this level
access to dn.base="" by * read
# admin gets unlimited read/write access to database
# everyone else read-only
access to *
by dn="cn=admin,dc=alrac,dc=net" write
by * read
#######################################################################
然后,确认 /var/lib/ldap 中的文件都为 ldap 用户所有:
# chown -R ldap:ldap /var/lib/ldap
如果没有 /var/lib/ldap/DB_CONFIG 文件,就创建一个空的:
# touch /var/lib/ldap/DB_CONFIG
下一步,运行 slaptest 命令检查 /etc/ldap/slapd.conf:
# slaptest
config file testing succeeded
现在,启动它:
# /etc/init.d/ldap start
Checking configuration files for slapd: config file testing succeeded
[ OK ]
Started slapd: [ OK ]
最后,运行这个简单的测试,确认服务器正在运行并且可以响应请求:
# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
[...]
dn:
namingContexts: dc=alrac,dc=net
[...]
很好!结果说明是成功的。现在,你可以继续进行后面的步骤了。
讨论
Debian 用户不需要 rootpw 或 rootdn,无论如何,这些都会在下一节中讲到。
loglevel -1 表示记录一切,而且这样可能会在瞬间将数兆日志打入 syslog。参阅第 12.12 节获取更多信息。
参阅第 12.1 节讨论部分中关于 ldapsearch 选项的解释。
当你运行 slaptest 时,你可能会看到警告提示。slapd 应该还是会运行,但是应该修复任何引发警告提示的问题。Fedora 上某些常见错误是由以下原因引起:
• 不正确的文件权限或属主
• 丢失了 /var/lib/ldap/DB_CONFIG
按照本节所介绍的步骤进行,应该可以防止出现任何错误。例如,如果 /var/lib/ldap 中的文件并非 ldap 用户所有,你将会得到 “permission denied” 错误。如果 DB_CONFIG 丢失,你会得到一次警告提示,但 slapd 还是会运行。
DB_CONFIG 包含了用于调整 Berkeley DB 后端的选项。参阅第 12.11 节学习如何配置。
这只是用于测试基本功能的简单安装,在 slapd.conf 中设置一个 rootpw 口令,从安全角度来看并不是最佳的实践,而且我们并没有真正建立一个目录。但是我们正在接近目标。
参阅
• man ldapsearch
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
12.4 在 Fedora 上创建一个新数据库
问题
你的 Fedora OpenLDAP 安装并没有包括一个管理用户,也没有其它任何用户。你需要创建一个 admin 用户来管理目录,而且你还需要定义后缀。
解决方案
这里有三个步骤:
1. 用新的信息创建一个 LDIF 文件。
2. 使用 ldapadd 命令将新条目添加到 Berkeley DB。
3. 在 slapd.conf 中配置读写权限。
首先,创建 LDAP 数据交换格式(LDIF)文件,在这个例子中名为 first.ldif。替换你自己的域名、公司名、描述,还有口令。去掉所有前导和尾随的空格。用一个空行分隔条目,注释必须位于它们自己所在的行上,而且在每个冒号后面必须有一个空格:
##first.ldif
# root dn entry
dn: dc=alrac,dc=net
objectclass: dcObject
objectclass: organization
o: Alrac's Fine Cookies and Beer
dc: alrac
# directory administrator
dn: cn=admin,dc=alrac,dc=net
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
userPassword: bigsecretword
description: LDAP administrator
第二步,运行这条 ldapadd 命令。你会被问及 slapd.conf 中输入的 rootpw 口令:
# ldapadd -x -D "cn=admin,dc=alrac,dc=net" -W -f first.ldif
Enter LDAP Password:
adding new entry "dc=alrac,dc=net"
adding new entry "cn=admin,dc=alrac,dc=net"
让我们看看新条目:
$ ldapsearch -x -b 'dc=alrac,dc=net'
[...]
# alrac.net
dn: dc=alrac,dc=net
objectClass: dcObject
objectClass: organization
o: Alrac's Fine Cookies and Beer
dc: alrac
# admin, alrac.net
dn: cn=admin,dc=alrac,dc=net
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
userPassword: fji8Hu11hs
description: LDAP administrator
[...]
在 slapd.conf 中注释 rootpw 和 rootdn 条目。然后,重启 OpenLDAP,并且再次查看目录条目:
# /etc/init.d/ldap restart
$ ldapsearch -x -b 'dc=alrac,dc=net'
现在,admin 用户就拥有了完全的数据库控制权。
讨论
注意 LDIF 文件中的空格。一个空行用于划分条目界限。某一行的前导空格表示该行是前一行的后续,逗号分隔每个名/值对,而任何文字中的逗号必须转义,就像这个例子所示:
dn: uid=twhale,ou=people,ou=factory,ou=bluecollars,
o=widgets\, inc.,c=au,dc=widgets,dc=com
admin 用户可以拥有任何名字,比如 db-admin 或 ldapgoddess,或者任何你喜欢的名字。你会在很多 LDAP 文档中看到 Manager 用户,和我们的 admin 用户一样。
first.ldif 文件包含两个独立的条目。第一个条目定义了我们的后缀。那是整个目录树的根。第二个条目定义了 admin 用户,它在 slapd.conf 中被赋予了整个数据库的读写权限。所有其它用户只给了读权限。他们可以更改自己的口令,而且无法看到他人的口令。
每个条目都要有自己的唯一 DN。记住,这些是由相对识别名(RDN)和它所有的祖先结合在一起构成的。(参阅本章的介绍部分,获取更多信息。)
你的 LDIF 文件不必使用 .ldif 文件后缀。保留它则毫无疑问不会导致混淆。
为什么要更换 slapd.conf 中的 rootdn 和 rootpw?rootdn 是数据库的超级用户,就像我们的 admin 用户,而 rootpw 是 rootdn 的口令。对于初次创建目录是有用的,而且你可能喜欢通过这种方式来配置你的数据库超级用户。某些管理员出于安全的考虑,不想在 slapd.conf 中设置 rootpw。某些管理员不想在目录中设置超级用户,比如我们的 admin 用户,也同样出于安全的理由。如果你一定要将它保留在 slapd.conf 中,那么就得再三确认该文件被妥善保护——让它只能被属主和组所有者读取,并且只在你需要变更时打开写权限。
如果你选择保留 slapd.conf 中的 rootdn,那么我们在前一节中创建的 admin ACL 就没有必要了。rootdn 不需要显式的访问规则。
ObjectClass 与属性
打开一个图形化 LDAP 浏览器,如 gq,查看每个 ObjectClass 可用的属性。这是一种查看选项的简单方式。你也可以在 /etc/ldap/schema/(Fedora 上是 /etc/openldap)中查看 schema 文件。inetOrgPerson 是你将经常用到的一个。/etc/ldap/schema/inetorgperson.schema 定义了那些属性是必要的,而那些是可选的:
# inetOrgPerson
# The inetOrgPerson represents people who are associated with an
# organization in some way. It is a structural class and is derived
# from the organizationalPerson which is defined in X.521 [X521].
objectclass ( 2.16.840.1.113730.3.2.2
NAME 'inetOrgPerson'
DESC 'RFC2798: Internet Organizational Person'
SUP organizationalPerson
STRUCTURAL
MAY (
audio $ businessCategory $ carLicense $ departmentNumber $
displayName $ employeeNumber $ employeeType $ givenName $
homePhone $ homePostalAddress $ initials $ jpegPhoto $
labeledURI $ mail $ manager $ mobile $ o $ pager $
photo $ roomNumber $ secretary $ uid $ userCertificate $
x500uniqueIdentifier $ preferredLanguage $
userSMIMECertificate $ userPKCS12 )
)
如上所示,它们都是可选的。simpleSecurityObject 不那么复杂,它只有一个必要的属性:
objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
DESC 'RFC1274: simple security object'
SUP top AUXILIARY
MUST userPassword )
参阅
• man 1 ldapsearch
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
• 《LDAP 系统管理》,Gerald Carter 著 (O’Reilly)
12.5 在你的目录中添加更多用户
问题
你准备往 OpenLDAP 目录中添加更多用户。你该怎么做?
解决方案
确认 OpenLDAP 服务器正在运行。下一步,创建一个 LDIF 文件,其中包含你的新用户条目,然后使用 ldapadd 将它们输出到 OpenLDAP 目录中。
我们正准备稍微扩展一下目录结构,因为现在这只是一个老式的单层目录。我们想要对数据进行整理,不要把所有内容都放在顶层,所以我们将会添加一个 people 组织单元(OU)。我们的目录现在看上去如图 12-4。
{{附图}}
图 12-4。添加一个新的 OU 及相关用户
你可以看到我们的 admin 正孤立在外。(它在顶层孤立。)
这个 users.ldif 样例文件添加了新的 OU 和两个用户。注意你的空格!注释必须位于它们自己所在的行上,而且在每个冒号后面必须有一个空格,还要用空行分隔条目:
##/etc/ldap/ldif/users.ldif
dn: ou=people,dc=alrac,dc=net
ou: people
description: All people in organisation
objectClass: organizationalUnit
dn: uid=cschroder,ou=people,dc=alrac,dc=net
objectClass: inetOrgPerson
cn: Carla Schroder
sn: Schroder
uid: cschroder
userPassword: password
telephoneNumber: 444-222-3333
homePhone: 555-111-2222
description: indescribable
dn: uid=thanson,ou=people,dc=alrac,dc=net
objectClass: inetOrgPerson
cn: Terry Hanson
sn: Hanson
uid: thanson
userPassword: password
telephoneNumber: 222-333-4455
homePhone: 112-334-5678
description: absolutely fabulous
现在,将这些新条目添加到数据库:
# ldapadd -x -D "cn=admin,dc=alrac,dc=net" -W -f users.ldif
Enter LDAP Password:
adding new entry "ou=people,dc=alrac,dc=net"
adding new entry "uid=cschroder,ou=people,dc=alrac,dc=net"
adding new entry "uid=thanson,ou=people,dc=alrac,dc=net"
然后,运行常用的 ldapsearch 命令验证你的条目:
$ ldapsearch -x -b 'dc=alrac,dc=net'
若要添加更多用户,你就需要创建一个新的 .ldif 文件,或者覆盖旧的文件。你不能只添加新条目到现有的文件中,因为当 ldapadd 找到某个现有的条目时,它会停止并且不再往下读取文件剩余部分。
讨论
ldapadd 要求有一个正在运行的服务器,如果 slapd 不在运行,那么它就无法工作。所有以“ldap”开头的命令在要在运行的服务器上操作。而“slap”命令,如 slapcat 和 slapadd,要求 slapd 不在运行状态。参阅前一节的讨论部分,学习创建 LDIF 文件相关细节要点。
参阅
• man 1 ldapsearch
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
• 《LDAP 系统管理》,Gerald Carter 著 (O’Reilly)
12.6 修正目录条目
问题
由于用户变更,或者你操作失误,所以想要改变一个现有的目录条目。你该怎么做?
解决方案
一种途径是使用 ldapmodify。你需要创建一个新的特殊格式 LDIF 文件。这个例子添加了一个标题,变更了 email 地址,并且添加了一张照片:
##/etc/ldap/modfile.ldif
dn: uid=thanson,ou=people,dc=alrac,dc=net
changetype:modify
add:title
title:Fire Marshal
-
replace:mail
-
add: jpegphoto
jpegphoto:< file:///filename.jpg
下一步,以这种方式使用 LDIF 文件:
# ldapmodify -x -D "cn=admin,dc=alrac,dc=net" -W -f modfile.ldif
Enter LDAP Password:
modifying entry "cn=Terry Hanson,ou=people,dc=alrac,dc=net"
然后,通过 ldapsearch 验证:
$ ldapsearch -xtb 'dc=alrac,dc=net' 'cn=terry hanson'
[...]
# Terry Hanson, people, alrac.net
dn: cn=Terry Hanson,ou=people,dc=alrac,dc=net
objectClass: inetOrgPerson
cn: Terry Hanson
sn: Hanson
uid: thanson
telephoneNumber: 333.444.4545
homePhone: 222-333-5555
description: burning down the house
title: Fire Marshal
jpegPhoto:< file:///tmp/ldapsearch-jpegPhoto-Sx11P8
[...]
讨论
对于少量条目的变更,图形化 LDAP 浏览器(见第 12.10 节)通常比较快,也比较方便。使用 LDIF 用于大量变更比较快,而且适合顶尖的脚本专家。
注意 ldapsearch 新的 -t 选项。该选项告诉 ldapsearch 要存储照片、音频文件,或者其它非字符数据的临时文件。如果你不使用它,那么就会得到大量编码,象这样:
fdtvWuJG2BwGFzjms1d7eTubLmBp5EFktAAPZfvNUzNVthoyz6sMbkgtSAd6dj3mqudjOCW6QxUAItBmSbQw
638J7W+NQArNTIZ4wNQbkdXh3sATNVnpSns2yveXHeYU5+1o46yelp6pu02LGcYBKimkNyRuq/j+/QUGJBp
3mdwf3q2PTbca2gFkCkkKVRixIltTMw4m3+91vTmZYaGy5Ktbxnq0
当你添加 JPEG 照片时,它必须是可用的,否则 ldapmodify 会返回消息 ldapmodify: invalid format。虽然该消息跟“我找不到那个文件”完全不同,但这就是它实际上的意思。JPEG 文件以 base-64 MIME 编码格式导入数据库。如果你准备包含人们的 ID 照片,就要确认它们的物理尺寸和文件大小都是比较小的,否则它们会在 LDAP 客户端上看起来很奇怪。
OpenLDAP 对待变更文件的格式和语法十分苛刻。从 DN 开始标识条目,然后关键词 changetype 后面要跟随变更类型: add、modify、modrdn 或 delete。删除一个条目只需要两行:
dn: cn=Terry Hanson,ou=people,dc=alrac,dc=net
changetype:delete
jpegPhoto 和 audio 属性的语法都很讲究:
jpegphoto:< file:///filename.jpg
:< 中间不能有空格,而后面要跟一个空格。file:// 有两个斜杠,然后是文件名。
当你修改一个现有的条目时,可能用到的关键词是 add、replace 或 delete。replace 是全部或者全不,例如,如果该条目有三个 email 地址,而你的 LDIF 文件包含:
replace: mail
它就会删除三个旧地址,然后添加这个新地址。
delete 也可以是全部或全不,或者可选。如果你的条目中有三个 homePhone 属性,而你使用:
delete: homephone
那么所有三个都会被删除。要删除一个单独的属性,这么做:
delete: homephone
homePhone: 222-333-5555
参阅
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
• 《LDAP 系统管理》,Gerald Carter 著 (O’Reilly)
12.7 连接至远程 OpenLDAP 服务器
问题
你不会总是待在物理服务器旁边,或者你想要托管服务器,所以需要知道如何远程管理你的 OpenLDAP 服务器。
解决方案
所有 OpenLDAP 命令都使用同样的 -H 选项连接远程主机,如这个例子中,在本地网络使用服务器的主机名:
# ldapsearch -H ldap://xena -xtb 'dc=alrac,dc=net'
或者,你可以使用完全限定的域名:
# ldapsearch -H ldap://xena.alrac.net -xtb 'dc=alrac,dc=net'
或者,指定端口。你无需这么做,除非要使用别的端口:
# ldapsearch -H ldap://xena.alrac.net:389 -xtb 'dc=alrac,dc=net'
讨论
大量文档仍提到要使用小写的 -h,但是该选项已经不再使用了,而且未来即将被废弃。
并非只能在样例命令中使用这些选项,任何 OpenLDAP 命令都可以远程执行(例如,搜索、变更,等等)。
参阅
• man 1 ldapsearch
• man 1 ldapmodify
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
• 《LDAP 系统管理》,Gerald Carter 著 (O’Reilly)
12.8 在你的 OpenLDAP 目录中搜索
问题
你的目录正在增长,而你想知道如何细化搜索,以便只摘出所需要的信息,而不用在一大堆无关的信息里跋涉。
解决方案
ldapsearch 命令附带了一系列选项,用于搜索任何一个可以想到的属性。这条命令通过 common name(CN)搜索指定的用户:
$ ldapsearch -xtb 'dc=alrac,dc=net' 'cn=carla'
如果你不太确定要查找什么,就可以使用通配符。这个例子搜索以 schroder 结尾的 UID:
$ ldapsearch -xtb 'dc=alrac,dc=net' 'uid=*schroder'
也许你想要获得所有以某个电话前缀开头的条目:
$ ldapsearch -xtb 'ou=people,dc=alrac,dc=net' '(telephoneNumber=333*)'
你可能只是想要一份属性列表,而不含相应内容:
$ ldapsearch -xtb 'dc=alrac,dc=net' 'cn=carla' -A
你可以从 DIT 的另一个层次开始:
$ ldapsearch -xtb 'ou=people,dc=alrac,dc=net' 'cn=carla'
你可以限制搜索的规模,如这个例子中搜索照片条目,并且限制结果为 10 条:
$ ldapsearch -z 10 -xtb 'ou=people,dc=alrac,dc=net' '(jpegPhoto=*)'
这条命令建立了一份目录所用 objectClass 的列表:
$ ldapsearch -xb 'dc=alrac,dc=net' '(objectclass=*)' dcObject
或者,搜索指定 objectClass 的条目:
$ ldapsearch -xb 'dc=alrac,dc=net' '(objectclass=simpleSecurityObject)'
组合属性以缩小搜索范围,比如拥有特定电话前缀和邮件域的用户:
$ ldapsearch -xtb 'dc=alrac,dc=net' '(&(mail=*domain.com)(telephoneNumber=333*))'
或者,列出某个指定邮件域中的所有用户,除具有指定电话前缀(注意你的括号)之外:
$ ldapsearch -xtb 'dc=alrac,dc=net' '(&(mail=*domain.com)(!(telephoneNumber=333*)))'
讨论
如果你正在想,“忘掉它,我要走捷径,用那些漂亮的图形化 LDAP 客户端”。慢着,那些漂亮的图形化界面还是需要关于 OpenLDAP 命令的知识。
这里是一些用于多种搜索表达式的语法样例:
匹配该值
(attribute=value)
(objectclass=name)
近似匹配该值,这需要一个近似指数,参阅第 12.9 节获取更多信息
(attribute~=value)
匹配所有这些值
(&(exp1)(exp2)(exp3))
匹配其中任何一个值,exp1 OR exp2 OR exp3
(|(exp1)(exp2)(exp3))
排除该值
(!(exp1))
这些值都排除
(&(!(exp1))(!(exp2)))
排除任何一组值
(|(!(exp1))(!(exp2)))
还有一些其它可用的搜索类型,尽管如此,我还是没有发现它们有什么用,因为这些搜索类型依赖于属性的排序规则,而它们多数都没有此类规则:
匹配大于的结果
(attribute>=value)
匹配小于的结果
(attribute<=value)
参阅
• man 1 ldapsearch
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
• 《LDAP 系统管理》,Gerald Carter 著 (O’Reilly)
12.9 为你的数据库建立索引
问题
你注意到 slapd.conf 中有一些索引选项——那些都是干什么用的?它们可以让你的目录查询更快么?
解决方案
它们确实可以。索引经常搜索的属性将会提高性能。这里是一些不同用途的索引样例:
#always have this one
index objectClass eq
#for common name searches
index cn,sn,uid pres,eq,sub
#email address searches
index mail pres,eq
这些配置都在 slapd.conf 中。
讨论
如果你在 slapd 运行时改变了索引设置,那么一个内部的任务就会自动运行,并生成新的索引。你无需显式重新生成索引。尽管如此,如果 slapd 在索引任务完成之前停止,那么就得手工通过 slapindex 命令生成新的索引:
# /etc/init.d/slapd stop (Debian)
# /etc/init.d/ldap stop (Fedora)
# slapindex
当它完成时,重新启动 OpenLDAP。如果你有一个比较大的目录,这个过程会消耗若干分钟。
建立索引会使 id2entry 文件大小增长。数据库越大,索引越多,该文件就会变得越大。来自 OpenLDAP-devel 邮件列表的这份邮件( http://www.openldap.org/lists/openldap-devel/200510/msg00131.html)说:
对于我的测试数据库而言,360 MB 的输入 LDIF 和 285,000 个条目,以及 15 个索引属性,使用 512 MB BDB 缓存.... 最终的 id2entry 数据库大约有 800 MB,加上所有的索引,总大小约为 2.1 GB。
索引语法为:
index [attributes] [index type]
多个属性和索引类型是用逗号分隔的。这些是最常用的索引类型:
pres
匹配属性类型,而不是属性值。例如,搜索属性 (objectclass=inetOrgPerson) 或 (attribute=mail)。
eq
匹配确切的属性值,如 (cn=fred) 只返回确切匹配“fred”的结果。
sub
通配符搜索索引,如 (cn=lisa*)。有多种不同的 sub。例如,subinitial 是为 (cn=lisa*) 之类的搜索进行优化的,subfinal 是为 (cn=*smith) 之类的搜索进行优化的,而 subany 是为 (cn=*isa*) 之类的搜索进行优化的。
创建不必要的索引会影响性能。未索引的搜索总是会成功,你的目标是索引最常用的搜索,而不要担心不常用的搜索类型。聪明的索引可以显著提升性能。观察你的日志文件,看看你的用户或应用程序都在查找什么,那是你决定什么需要索引的最佳参考指南。参阅第 12.12 节,获得更多信息。
参阅
• man 8 slapindex
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
• 《LDAP 系统管理》,Gerald Carter 著 (O’Reilly)
12.10 使用图形界面管理你的目录
问题
你想要一些漂亮的图形化工具用于管理 LDAP 目录。
解决方案
有非常多的图形化 LDAP 目录查看器和管理器,它们的用途和特点多种多样。你还是需要知道 OpenLDAP 命令,但是一个好的图形化界面可以让你更有效率。这里是一些优秀的开源应用程序:
GQ ( http://gq-project.org/)
这是一个非常简单的独立 LDAP 客户端。它是一个浏览器,也是一个编辑工具。你可以很方便地浏览 schema 细节,还能看到你的目录结构,如图 12-5 所示。你也可以通过验证创建或编辑条目。
Web 浏览器
Konqueror 和 Internet Explorer 都包括了简单的 LDAP 查看器。你可以看到你的目录,但是不能编辑它。输入一个含有前缀的 URL,如 ldap://localhost:389/dc=alrac,dc=net ,然后就能看到如图 12-6 所示结果。
LAT,LDAP 管理工具( http://dev.mmgsecurity.com/projects/lat/)
一个漂亮而且功能丰富的查看器和编辑工具(见图 12-7)。它包括了用于 Samba 和活动目录集成的工具,一个很好的搜索工具,LDIF 导入和导出,以及其它基本的管理特性。
基于 Web 的 LDAP 管理器
phpLDAPadmin( http://phpldapadmin.sourceforge.net/)和 Gosa( https://www.gosa-project.org/)是两种流行的基于 web 的 LDAP 管理器。它们都非常复杂,就像多数 PHP 应用程序一样,因为它们依赖于 HTTP 服务器、PHP 和多种模块及相应的库。所以它们都需要花点工夫学习,但它们的好处是,都有颇具吸引力的界面,通用的客户端,还有任何 PHP 程序员都能扩展定制它们。
{{附图}}
图 12-5。GQ 查看 LDAP 目录视图
{{附图}}
图 12-6。Konqueror 中看到我们的 LDAP 目录
讨论
就像所有优秀的 Linux 管理员一样,你不会在 LDAP 服务器上运行 X Windows,以及所有相关应用程序,你不需要它们,因为它们都支持安全的远程访问。
{{附图}}
图 12-7。LAT 的目录视图
参阅
• OpenLDAP.org: http://www.openldap.org/
• 《LDAP 目录详解:介绍与分析》,Brian Arkills 著 (Addison-Wesley)
• 《LDAP 系统管理》,Gerald Carter 著 (O’Reilly)
12.11 配置 Berkeley DB
问题
你知道自己需要使用 /var/lib/ldap/DB_CONFIG 来配置 LDAP 目录的数据库后端(Berkeley DB),从而使它可以精力充沛地工作,而不会陷入泥沼。你如何知道要使用哪些选项和值?
解决方案
我们将从某些对于入门者合适的值开始,然后学习如何通过计算来细化它们。
记得要检查你的 slapd.conf,如果存在重复的 BDB 条目就要清除掉。它们可以放在不同的文件中,但最好是都保留在 DB_CONFIG 中。你不想要那些重复或者冲突的条目。
首先,确认在 slapd.conf 中有一个 cachesize 条目:
cachesize 5000
然后,在 /var/lib/ldap/DB_CONFIG 中输入这些选项和值:
##/var/lib/ldap/DB_CONFIG
set_cachesize 0 1048576 0
set_lk_max_objects 1500
set_lk_max_locks 1500
set_lk_max_lockers 1500
#
#logging settings
set_lg_regionmax 1048576
set_lg_bsize 32768
set_lg_max 131072
set_lg_dir /var/log/openldap
set_cachesize 值是以字节为单位的,而且必须是 2 的乘方,所以例子中的数值为一兆。你如何知道该用多少?在 Debian 上使用 db4.2_stat 命令,而在 Fedora 上使用 db_stat 命令,从两个主数据库文件 id2entry.bdb 和 dn2id.bdb 中生成统计信息:
# db4.2_stat -d /var/lib/ldap/id2entry.bdb
53162 Btree magic number.
9 Btree version number.
Flags: little-endian
2 Minimum keys per-page.
16384 Underlying database page size.
1 Number of levels in the tree.
6 Number of unique keys in the tree.
6 Number of data items in the tree.
0 Number of tree internal pages.
0 Number of bytes free in tree internal pages (0% ff).
1 Number of tree leaf pages.
12374 Number of bytes free in tree leaf pages (24% ff).
0 Number of tree duplicate pages.
0 Number of bytes free in tree duplicate pages (0% ff).
0 Number of tree overflow pages.
0 Number of bytes free in tree overflow pages (0% ff).
0 Number of pages on the free list.
# db4.2_stat -d /var/lib/ldap/dn2id.bdb
53162 Btree magic number.
9 Btree version number.
Flags: duplicates, little-endian
2 Minimum keys per-page.
4096 Underlying database page size.
1 Number of levels in the tree.
13 Number of unique keys in the tree.
19 Number of data items in the tree.
0 Number of tree internal pages.
0 Number of bytes free in tree internal pages (0% ff).
1 Number of tree leaf pages.
3378 Number of bytes free in tree leaf pages (18% ff).
0 Number of tree duplicate pages.
0 Number of bytes free in tree duplicate pages (0% ff).
0 Number of tree overflow pages.
0 Number of bytes free in tree overflow pages (0% ff).
0 Number of pages on the free list.
你可以看到每个 id2entry.bdb 页面都需要 16 KB,而 dn2id.bdb 需要 4 KB 每页,还有每个文件使用内部页面的数量。所以,你可以使用这个公式计算最小的内存需求:
((50+1) * 4096) + ((12+1) * 16384)) = 421,888 bytes
这里不需要计算其它库的开销或者索引。作为快捷方式,将这个数字加倍就能获得相当好的性能。所以,对于这个例子来说,我们可以将它确定为 1 MB 内存。
你如何知道哪些值要分配给 set_lk_max_objects 1500、set_lk_max_locks 1500 和 set_lk_max_lockers 1500?使用 db4.2_stat -c(在 Fedora 上是 db_stat)命令:
# cd /var/lib/ldap
# db4.2_stat -c
100 Last allocated locker ID.
2147M Current maximum unused locker ID.
9 Number of lock modes.
1500 Maximum number of locks possible.
1500 Maximum number of lockers possible.
1500 Maximum number of lock objects possible.
3 Number of current locks.
11 Maximum number of locks at any one time.
12 Number of current lockers.
19 Maximum number of lockers at any one time.
3 Number of current lock objects.
8 Maximum number of lock objects at any one time.
1170 Total number of locks requested.
1167 Total number of locks released.
0 Total number of lock requests failing because DB_LOCK_NOWAIT was set.
0 Total number of locks not immediately available due to conflicts.
0 Number of deadlocks.
0 Lock timeout value.
0 Number of locks that have timed out.
0 Transaction timeout value.
0 Number of transactions that have timed out.
552KB The size of the lock region..
0 The number of region locks granted after waiting.
2579 The number of region locks granted without waiting.
对于一个较小的目录,1500 是个合理的起点,通过你的 db4.2_stat -c 执行结果决定是否需要增加。当使用率达到设定值 85% 时,就要增加它们。还要查看你的 Number of current values 输出结果、超时值和失败信息。
对于 OpenLDAP 2.3 及以上版本,你在变更 DB_CONFIG 之后所要做的就是重启 slapd:
# /etc/init.d/slapd restart (Debian)
# /etc/init.d/ldap restart (Fedora)
尽管如此,这样不会总是生效,所以如果 slaptest 返回错误,而且版本为 2.2 及更早的话,Debian 用户需要使用数据库恢复命令:
# /etc/init.d/slapd stop
# db4.2_recover -h /var/lib/ldap
# /etc/init.d/slapd start
Fedora 用户使用略有不同的命令:
# /etc/init.d/ldap stop
# db_recover -h /var/lib/ldap
# /etc/init.d/ldap start
然后,运行这条命令验证你的新缓存大小。这些都是基于 DB_CONFIG 设定值为 16777216 的例子。同样,Debian 命令在前,Fedora 在后:
# db4.2_stat -h /var/lib/ldap -m | head -n 2
20MB 1KB 604B Total cache size.
1 Number of caches.
# db_stat -h /var/lib/ldap -m | head -n 2
现在,当 slapd 运行时要留意性能。转到数据库存储的目录:
# cd /var/lib/ldap
# db4.2_stat -m (Debian)
# db_stat -m (Fedora)
这样可以显示完整的缓存统计信息。
讨论
cachesize 定义了 LDAP 后端保留在内存中的条目数量。为了获得最佳性能,这个数字应等于目录中的条目数,但是可以稍微少一点。这并不是 BDB 缓存,而是 OpenLDAP 自己的内部缓存。默认值为 1000。
注意你的磁盘 I/O —— iostat 是一个很好的查看工具——还要留意 Requested pages found in the cache 值,该值可以通过在数据库目录中运行 db_stat -m 获得。你应该让它尽可能地接近 100%,而从缓存之外读取的页面应该为 0。如果这个比率降到 95% 以下,就要调高 set_cachesize 值。你想让请求尽可能多地从内存缓存响应,而不想产生太多磁盘抖动。
set_cachesize 有三个字段:、 和 。如果你想要创建一个 2 GB 的缓存,它看上去像 set_cachesize 2 0 0。你可以通过组合 GB 和字节数值进行设置。最大值为 4 GB。不要把你的缓存设为比整个系统内存更大。任何小于 500 MB 的缓存尺寸都会自动增加 25%,以满足缓冲区开销。
ncache 告诉 BDB,它是否应该使用一个连续的内存区域,还是多个内存区域。0 或者 1 表示一段,一个较大的数值表示创建这么多数量的内存段。现在的 Linux 内核在 32 位 x86 系统中支持每个用户进程 1-3 GB 内存,而且别忘了内核本身也需要相当大的一块内存。这个例子将一个 2 GB 缓存设为横跨两个内存段:
set_cachesize 2 0 2
在 64 位系统中,理论上你的整个内存空间,除了内核保留的部分之外,都可以由一个单独的进程使用。
创建一个太大的 set_cachesize 值可能会影响整个系统的性能,但是它不会影响 OpenLDAP,所以你可以设置一个很大的值,只要你有足够的内存即可。如果你需要节省使用内存,那么不妨查看参阅部分,获取关于细化计算的详细资料。
set_lk_max_locks、set_lk_max_lockers 和 set_lk_max_objects 相应地设置了 locks、lockers 和 locked objects 的最大值。如果这些值太小,请求锁就会失败。如果这些值过大,那么锁定子系统就会比实际需求使用更多的资源。大一些的数值比较安全。在数据库目录中运行 db4.2_stat -c(Fedora 上是 db_stat -c),对其密切关注。
锁定子系统会保持读写有序。任何写入 BDB 的东西都会得到该写入对象的互斥锁。而读是共享的。
配置日志记录也会影响性能。这里是相关例子的含义:
set_lg_regionmax
用于数据库文件缓存的最大内存缓存字节数。应该随着数据库文件数量的提升而增加这个值。每一个为索引而配置的属性,都使用一个文件来保存索引,此外 id2entry 和 dn2id 会一直存在。
set_lg_bsize
日志数据的内存缓存大小字节数。当缓存填满时,它就会被写入磁盘。
set_lg_max
日志文件的最大字节数。当它达到上限时,文件就会轮转。这里应该至少设为 set_lg_bsize 的四倍。
set_lg_dir
日志文件目录。为了获得最佳性能,应该在一块单独的磁盘或者远程网络共享上存储日志文件。
slapd -V
提供 OpenLDAP 服务器版本号。
参阅
• OpenLDAP 性能优化:
http://www.openldap.org/faq/data/cache/190.html
• Berkeley DB 入门:
http://www.oracle.com/technology/documentation/berkeley-db/db/gsg/C/index.html
• 《Berkeley DB XML 事务处理入门》第 4 章( http://www.oracle.com/technology/documentation/berkeley-db/xml/gsg_xml_txn/java/blocking_deadlocks.html),见“Locks, Blocks, and Deadlocks”部分。
12.12 配置 OpenLDAP 日志记录
问题
默认安装的 OpenLDAP 会将日志导出到 syslog,而你想让它记录自己单独的日志文件。你该怎么做?
解决方案
首先,我们创建一个单独的目录,以及一个空的日志文件:
# mkdir /var/log/openldap
# touch /var/log/openldap/ldap.log
然后,添加这几行到 /etc/syslog.conf:
#Logging for openldap
local4.* /var/log/openldap/ldap.log
还要在 slapd.conf 中设置你想要的日志等级,位于 Global 部分:
loglevel 256
现在,重启 OpenLDAP 和 syslog 守护进程:
# /etc/init.d/slapd restart (Debian)
# /etc/init.d/ldap restart (Fedora)
# /etc/init.d/sysklogd restart (Debian)
# /etc/init.d/syslog restart (Fedora)
进行搜索以产生一些活动,然后查看你的日志文件。它里面应该都是这样的条目:
May 22 11:53:32 xena slapd[7686]: conn=5 fd=11 ACCEPT from IP=127.0.0.1:33643 (IP=0.
0.0.0:389)
May 22 11:53:32 xena slapd[7686]: conn=5 op=0 BIND dn="" method=128
May 22 11:53:32 xena slapd[7686]: conn=5 op=0 RESULT tag=97 err=0 text=
May 22 11:53:32 xena slapd[7686]: conn=5 op=1 SRCH base="dc=alrac,dc=net" scope=2
deref=0 filter="(objectClass=*)"
12.13 备份和恢复你的目录
12.14 细化访问控制
12.15 变更密码