轻量级目录访问协议(LDAP)是一种应用层协议,用于访问、修改和验证对象,使用分布式目录信息服务。可以将其看作是一个电话簿或记录本,存储多个层级的同类信息。它用于 Active Directory 和 OpenLDAP 网络,允许用户通过单个账户访问多个层级的内部信息。例如,电子邮件认证、拉取员工联系信息和内部网站认证都可以利用 LDAP 服务器的记录库中的单个用户账户。
本节提供了在 FreeBSD 系统上配置 LDAP 服务器的快速入门指南。假设管理员已经有了一个设计方案,其中包括要存储的信息类型、这些信息的用途、哪些用户应有权访问这些信息,以及如何保护这些信息不受未经授权的访问。
32.5.1. LDAP 术语和结构
在开始配置之前,应该理解 LDAP 使用的一些术语。所有目录条目都由一组 属性 组成。每个属性集都包含一个唯一标识符,称为 区分名称(DN),通常由其他一些属性(如常见名称或 相对区分名称(RDN))构建。类似于目录有绝对路径和相对路径,可以将 DN 看作是绝对路径,将 RDN 看作是相对路径。
一个 LDAP 条目的示例如下。此示例搜索指定用户账户(uid
)、组织单位(ou
)和组织(o
)的条目:
% ldapsearch -xb "uid=trhodes,ou=users,o=example.com"
# extended LDIF
#
# LDAPv3
# base <uid=trhodes,ou=users,o=example.com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# trhodes, users, example.com
dn: uid=trhodes,ou=users,o=example.com
mail: trhodes@example.com
cn: Tom Rhodes
uid: trhodes
telephoneNumber: (123) 456-7890
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
此示例条目显示了 dn
、mail
、cn
、uid
和 telephoneNumber
属性的值。cn
属性是 RDN。
32.5.2. 配置 LDAP 服务器
# pkg install openldap-server
安装后会创建目录 /var/db/openldap-data 用于存储数据。必须创建用于存储证书的目录:
# mkdir /usr/local/etc/openldap/private
# openssl req -days 365 -nodes -new -x509 -keyout ca.key -out ../ca.crt
提示中的条目可以是通用的 *,除了 Common Name
。此条目必须与系统主机名 不同。如果这是一个自签名证书,前缀主机名为 CA
,表示证书颁发机构。
接下来的任务是创建证书签名请求和私钥。输入以下命令并按照提示操作:
# openssl req -days 365 -nodes -new -keyout server.key -out server.csr
在生成证书的过程中,确保正确设置 Common Name
属性。证书签名请求必须使用证书颁发机构签名,才能作为有效证书使用:
# openssl x509 -req -days 365 -in server.csr -out ../server.crt -CA ../ca.crt -CAkey ca.key -CAcreateserial
证书生成过程的最后一步是生成并签署客户端证书:
# openssl req -days 365 -nodes -new -keyout client.key -out client.csr
# openssl x509 -req -days 3650 -in client.csr -out ../client.crt -CA ../ca.crt -CAkey ca.key
记住在提示时使用相同的 Common Name
属性。完成后,确保通过上述命令生成了总共八(8)个新文件。
运行 OpenLDAP 服务器的守护进程是 slapd。其配置通过 slapd.ldif 进行:旧的 slapd.conf 已被 OpenLDAP 废弃。
#
# 详细的配置选项请参见 slapd-config(5)。
# 该文件不应为全世界可读。
#
dn: cn=config
objectClass: olcGlobal
cn: config
#
#
# 定义全局 ACL 禁用默认的读取权限。
#
olcArgsFile: /var/run/openldap/slapd.args
olcPidFile: /var/run/openldap/slapd.pid
olcTLSCertificateFile: /usr/local/etc/openldap/server.crt
olcTLSCertificateKeyFile: /usr/local/etc/openldap/private/server.key
olcTLSCACertificateFile: /usr/local/etc/openldap/ca.crt
#olcTLSCipherSuite: HIGH
olcTLSProtocolMin: 3.1
olcTLSVerifyClient: never
这里必须指定证书颁发机构、服务器证书和服务器私钥文件。建议让客户端选择安全加密套件,并省略 olcTLSCipherSuite
选项(因为它与 openssl 以外的 TLS 客户端不兼容)。选项 olcTLSProtocolMin
允许服务器要求最低的安全级别:这是推荐的。虽然对服务器来说,验证是强制的,但对客户端来说不是:olcTLSVerifyClient: never
。
第二部分是关于后端模块的配置,可以按以下方式进行配置:
#
# 加载动态后端模块:
#
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulepath: /usr/local/libexec/openldap
olcModuleload: back_mdb.la
#olcModuleload: back_bdb.la
#olcModuleload: back_hdb.la
#olcModuleload: back_ldap.la
#olcModuleload: back_passwd.la
#olcModuleload: back_shell.la
第三部分用于加载数据库将使用的 ldif
模式:它们是必不可少的。
dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema
include: file:///usr/local/etc/openldap/schema/core.ldif
include: file:///usr/local/etc/openldap/schema/cosine.ldif
include: file:///usr/local/etc/openldap/schema/inetorgperson.ldif
include: file:///usr/local/etc/openldap/schema/nis.ldif
接下来是前端配置部分:
# 前端设置
#
dn: olcDatabase={-1}frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: {-1}frontend
olcAccess: to * by * read
#
# 示例全局访问控制策略:
# Root DSE:允许任何人读取
# 子模式(sub)条目 DSE:允许任何人读取
# 其他 DSE:
# 允许自我写访问
# 允许经过身份验证的用户读取访问
# 允许匿名用户进行身份验证
#
#olcAccess: to dn.base="" by * read
#olcAccess: to dn.base="cn=Subschema" by * read
#olcAccess: to *
# by self write
# by users read
# by anonymous auth
#
# 如果没有访问控制策略,默认策略是:
# 允许任何人读取任何内容,但限制更新为 rootdn。 (例如,"access to * by * read")
#
# rootdn 总是可以读取和写入一切!
#
olcPasswordHash: {SSHA}
# {SSHA} 已是 olcPasswordHash 的默认值
另一个部分是配置后端部分,后续访问 OpenLDAP 服务器的配置只能作为全局超级用户进行。
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: to * by * none
olcRootPW: {SSHA}iae+lrQZILpiUdf16Z9KmDmSwT77Dj4U
默认的管理员用户名是 cn=config
。在 shell 中输入 slappasswd,选择一个密码并使用其哈希值填入 olcRootPW
。如果现在不指定此选项,在 slapd.ldif 导入之前,之后将无法修改 全局配置 部分。
最后一部分是关于数据库后端:
################################
# LMDB 数据库定义
################################
#
dn: olcDatabase=mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: mdb
olcDbMaxSize: 1073741824
olcSuffix: dc=domain,dc=example
olcRootDN: cn=mdbadmin,dc=domain,dc=example
# 避免使用明文密码,尤其是 rootdn 密码。
# 参见 slappasswd(8) 和 slapd-config(5) 以获取详细信息。
# 建议使用强身份验证。
olcRootPW: {SSHA}X2wHvIWDk6G76CQyCMS1vDCvtICWgn0+
# 数据库目录必须在运行 slapd 之前存在,并且
# 仅限 slapd 和 slap 工具访问。
# 推荐使用 700 权限。
olcDbDirectory: /var/db/openldap-data
# 要维护的索引
olcDbIndex: objectClass eq
这个数据库托管了 LDAP 目录的 实际内容。除了 mdb
类型外,还有其他类型可用。其超级用户(不要与全局超级用户混淆)在这里进行配置:olcRootDN
中是一个(可能是自定义的)用户名,olcRootPW
中是密码哈希值;可以像之前一样使用 slappasswd。
配置完成后,slapd.ldif 必须放置在一个空目录中。建议按照以下方式创建目录:
# mkdir /usr/local/etc/openldap/slapd.d/
导入配置数据库:
# /usr/local/sbin/slapadd -n0 -F /usr/local/etc/openldap/slapd.d/ -l /usr/local/etc/openldap/slapd.ldif
启动 slapd 守护进程:
# /usr/local/libexec/slapd -F /usr/local/etc/openldap/slapd.d/
可以使用 -d
选项进行调试,具体使用方法请参见 slapd(8)。要验证服务器是否正在运行并且工作正常,可以运行以下命令:
# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts
#
#
dn:
namingContexts: dc=domain,dc=example
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
服务器仍然需要信任。如果以前没有进行过此操作,请按照以下说明进行操作。安装 OpenSSL 软件包和 Ports :
从 ca.crt 存储的目录(在此示例中为 /usr/local/etc/openldap)中,运行以下命令:
现在,CA 和服务器证书将在各自的角色中正确识别。要验证这一点,可以从 server.crt 目录运行以下命令:
# openssl verify -verbose -CApath . server.crt
如果 slapd 正在运行,请重新启动它。如 /usr/local/etc/rc.d/slapd 所示,要在启动时正确运行 slapd,必须将以下行添加到 /etc/rc.conf 中:
slapd_enable="YES"
slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/
ldap://0.0.0.0/"'
slapd_sockets="/var/run/openldap/ldapi"
slapd_cn_config="YES"
slapd 在启动时不提供调试信息。可以查看 /var/log/debug.log、dmesg -a 和 /var/log/messages 来进行调试。
以下示例将组 team
和用户 john
添加到仍然为空的 domain.example
LDAP 数据库中。首先,创建文件 domain.ldif:
# cat domain.ldif
dn: dc=domain,dc=example
objectClass: dcObject
objectClass: organization
o: domain.example
dc: domain
dn: ou=groups,dc=domain,dc=example
objectClass: top
objectClass: organizationalunit
ou: groups
dn: ou=users,dc=domain,dc=example
objectClass: top
objectClass: organizationalunit
ou: users
dn: cn=team,ou=groups,dc=domain,dc=example
objectClass: top
objectClass: posixGroup
cn: team
gidNumber: 10001
dn: uid=john,ou=users,dc=domain,dc=example
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
cn: John McUser
uid: john
uidNumber: 10001
gidNumber: 10001
homeDirectory: /home/john/
loginShell: /usr/bin/bash
userPassword: secret
请参考 OpenLDAP 文档了解更多详情。使用 slappasswd 将明文密码 secret
替换为 userPassword
中的哈希值。指定的 loginShell
路径必须在允许 john
登录的所有系统中存在。最后,使用 mdb
管理员修改数据库:
# ldapadd -W -D "cn=mdbadmin,dc=domain,dc=example" -f domain.ldif
对 全局配置 部分的修改只能由全局超级用户执行。例如,假设 olcTLSCipherSuite: HIGH:MEDIUM:SSLv3
最初被指定,现在必须删除。首先,创建一个包含以下内容的文件:
# cat global_mod
dn: cn=config
changetype: modify
delete: olcTLSCipherSuite
然后,应用修改:
# ldapmodify -f global_mod -x -D "cn=config" -W
在提示时,提供在 配置后端 部分选择的密码。此时不需要提供用户名:这里的 cn=config
代表要修改的数据库部分的 DN。或者,可以使用 ldapmodify
删除数据库中的一行,使用 ldapdelete
删除整个条目。
如果出现问题,或者全局超级用户无法访问配置后端,则可以删除并重新写入整个配置:
# rm -rf /usr/local/etc/openldap/slapd.d/
然后,可以编辑并重新导入 slapd.ldif。请仅在没有其他解决方案时遵循此过程。
这仅是服务器的配置。相同的机器还可以托管 LDAP 客户端,并具有自己的单独配置。