30.5.轻型目录访问协议(LDAP)

轻型目录访问协议 (LDAP) 是一种应用层协议,用于使用分布式目录信息服务访问、修改和验证对象。可以把它想象成一本电话或唱片簿,它存储了几个层次的分层、同质信息。它用于 Active Directory 和 OpenLDAP 网络,允许用户使用单个帐户访问多个级别的内部信息。例如,电子邮件身份验证、提取员工联系信息和内部网站身份验证都可能使用 LDAP 服务器记录库中的单个用户帐户。

本节提供在 FreeBSD 系统上配置 LDAP 服务器的快速入门指南。它假定管理员已经有一个设计计划,其中包括要存储的信息类型、该信息将用于什么目的、哪些用户应有权访问该信息,以及如何防止未经授权的访问。

30.5.1. LDAP 术语和结构

LDAP 使用几个术语,在开始配置之前应了解这些术语。所有目录条目都由一组 属性 组成。这些属性集中的每一个都包含一个称为 可分辨名称 (DN) 的唯一标识符,该标识符通常由其他几个属性(如公用或 相对可分辨名称 (RDN))构建。与目录具有绝对路径和相对路径的方式类似,将 DN 视为绝对路径,将 RDN 视为相对路径。

示例 LDAP 条目如下所示。本示例搜索指定用户帐户 (uid)、组织单位 (ou) 和组织 (o) 的条目:

  1. % ldapsearch -xb "uid=trhodes,ou=users,o=example.com"
  2. # extended LDIF
  3. #
  4. # LDAPv3
  5. # base <uid=trhodes,ou=users,o=example.com> with scope subtree
  6. # filter: (objectclass=*)
  7. # requesting: ALL
  8. #
  9. # trhodes, users, example.com
  10. dn: uid=trhodes,ou=users,o=example.com
  11. mail: trhodes@example.com
  12. cn: Tom Rhodes
  13. uid: trhodes
  14. telephoneNumber: (123) 456-7890
  15. # search result
  16. search: 2
  17. result: 0 Success
  18. # numResponses: 2
  19. # numEntries: 1

此示例条目显示 dnmailcnuidtelephoneNumber 属性的值。cn 属性是 RDN。

有关 LDAP 及其术语的更多信息,请参阅 http://www.openldap.org/doc/admin24/intro.html。

30.5.2. 配置 LDAP 服务器

FreeBSD 不提供内置的 LDAP 服务器。通过安装 net/openldap 服务器软件包或 port 开始配置:

  1. # pkg install openldap-server

package 中启用了大量默认选项。通过运行 pkg info openldap-server 来查看它们。如果它们还不够(例如,如果需要 SQL 支持),请考虑使用适当的 framework 重新编译 port。

安装将创建目录 /var/db/openldap-data 来保存数据。必须创建用于存储证书的目录:

  1. # mkdir /usr/local/etc/openldap/private

下一阶段是配置证书颁发机构。以下命令必须从 /usr/local/etc/openldap/private 执行。这一点很重要,因为文件权限需要受到限制,并且用户不应有权访问这些文件。有关证书及其参数的更多详细信息,请参阅 OpenSSL。要创建证书颁发机构,请从以下命令开始,然后按照提示操作:

  1. # openssl req -days 365 -nodes -new -x509 -keyout ca.key -out ../ca.crt

提示的条目可能是通用的,但 Common Name 条目必须与系统主机名 不同 。如果这是自签名证书,请在主机名前面加上“证书颁发机构”前缀 CA

下一个任务是创建证书签名请求和私钥。输入以下命令并按照提示操作:

  1. # openssl req -days 365 -nodes -new -keyout server.key -out server.csr

在证书生成过程中,请确保正确设置 Common Name 属性。证书签名请求必须使用证书颁发机构进行签名,才能用作有效证书:

  1. # openssl x509 -req -days 365 -in server.csr -out ../server.crt -CA ../ca.crt -CAkey ca.key -CAcreateserial

证书生成过程的最后一部分是生成客户端证书并对其进行签名:

  1. # openssl req -days 365 -nodes -new -keyout client.key -out client.csr
  2. # openssl x509 -req -days 3650 -in client.csr -out ../client.crt -CA ../ca.crt -CAkey ca.key

请记住在出现提示时使用相同的 Common Name 属性。完成后,确保通过一连串命令总共生成了 8 个新文件。

运行 OpenLDAP 服务器的守护程序已 过期。它的配置是通过 slapd.ldif 执行的:旧的 slapd.conf 已被 OpenLDAP 弃用。

slapd.ldif配置示例可用,也可以在 /usr/local/etc/openldap/slapd.ldif.sample 中找到。选项记录在 slapd-config(5) 中。与所有其他 LDAP 属性集一样,slapd.ldif 的每个部分都通过 DN 进行唯一标识。请确保在语句和该部分的所需末尾之间不留任何空行。在以下示例中,TLS 将用于实现安全通道。第一部分是全局配置:

  1. #
  2. # See slapd-config(5) for details on configuration options.
  3. # This file should NOT be world readable.
  4. #
  5. dn: cn=config
  6. objectClass: olcGlobal
  7. cn: config
  8. #
  9. #
  10. # Define global ACLs to disable default read access.
  11. #
  12. olcArgsFile: /var/run/openldap/slapd.args
  13. olcPidFile: /var/run/openldap/slapd.pid
  14. olcTLSCertificateFile: /usr/local/etc/openldap/server.crt
  15. olcTLSCertificateKeyFile: /usr/local/etc/openldap/private/server.key
  16. olcTLSCACertificateFile: /usr/local/etc/openldap/ca.crt
  17. #olcTLSCipherSuite: HIGH
  18. olcTLSProtocolMin: 3.1
  19. olcTLSVerifyClient: never

必须在这里指定证书机构、服务器证书和服务器私钥文件。建议让客户选择安全密码,省略选项 olcTLSCipherSuite (与 openssl 以外的 TLS 客户不兼容)。选项olcTLSProtocolMin让服务器要求一个最低的安全级别:建议使用。虽然验证对服务器来说是强制性的,但对客户端来说却不是必需的:olcTLSVerifyClient:never

第二部分是关于后端模块的,可以按如下方式配置:

  1. #
  2. # Load dynamic backend modules:
  3. #
  4. dn: cn=module,cn=config
  5. objectClass: olcModuleList
  6. cn: module
  7. olcModulepath: /usr/local/libexec/openldap
  8. olcModuleload: back_mdb.la
  9. #olcModuleload: back_bdb.la
  10. #olcModuleload: back_hdb.la
  11. #olcModuleload: back_ldap.la
  12. #olcModuleload: back_passwd.la
  13. #olcModuleload: back_shell.la

第三部分专门用于加载数据库使用的所需 ldif 架构:它们是必不可少的。

  1. dn: cn=schema,cn=config
  2. objectClass: olcSchemaConfig
  3. cn: schema
  4. include: file:///usr/local/etc/openldap/schema/core.ldif
  5. include: file:///usr/local/etc/openldap/schema/cosine.ldif
  6. include: file:///usr/local/etc/openldap/schema/inetorgperson.ldif
  7. include: file:///usr/local/etc/openldap/schema/nis.ldif

接下来,前端配置部分:

  1. # Frontend settings
  2. #
  3. dn: olcDatabase={-1}frontend,cn=config
  4. objectClass: olcDatabaseConfig
  5. objectClass: olcFrontendConfig
  6. olcDatabase: {-1}frontend
  7. olcAccess: to * by * read
  8. #
  9. # Sample global access control policy:
  10. # Root DSE: allow anyone to read it
  11. # Subschema (sub)entry DSE: allow anyone to read it
  12. # Other DSEs:
  13. # Allow self write access
  14. # Allow authenticated users read access
  15. # Allow anonymous users to authenticate
  16. #
  17. #olcAccess: to dn.base="" by * read
  18. #olcAccess: to dn.base="cn=Subschema" by * read
  19. #olcAccess: to *
  20. # by self write
  21. # by users read
  22. # by anonymous auth
  23. #
  24. # if no access controls are present, the default policy
  25. # allows anyone and everyone to read anything but restricts
  26. # updates to rootdn. (e.g., "access to * by * read")
  27. #
  28. # rootdn can always read and write EVERYTHING!
  29. #
  30. olcPasswordHash: {SSHA}
  31. # {SSHA} is already the default for olcPasswordHash

另一部分专门介绍配置后端,以后访问 OpenLDAP 服务器配置的唯一方法是作为全局超级用户。

  1. dn: olcDatabase={0}config,cn=config
  2. objectClass: olcDatabaseConfig
  3. olcDatabase: {0}config
  4. olcAccess: to * by * none
  5. olcRootPW: {SSHA}iae+lrQZILpiUdf16Z9KmDmSwT77Dj4U

缺省管理员用户名为 cn=config。在 shell 中键入 slappasswd,选择一个密码并在 olcRootPW 中使用其哈希值。如果现在未指定此选项,则在导入 slapd.ldif 之前,以后任何人都无法修改全局配置部分。

最后一部分是关于数据库后端的:

  1. #######################################################################
  2. # LMDB database definitions
  3. #######################################################################
  4. #
  5. dn: olcDatabase=mdb,cn=config
  6. objectClass: olcDatabaseConfig
  7. objectClass: olcMdbConfig
  8. olcDatabase: mdb
  9. olcDbMaxSize: 1073741824
  10. olcSuffix: dc=domain,dc=example
  11. olcRootDN: cn=mdbadmin,dc=domain,dc=example
  12. # Cleartext passwords, especially for the rootdn, should
  13. # be avoided. See slappasswd(8) and slapd-config(5) for details.
  14. # Use of strong authentication encouraged.
  15. olcRootPW: {SSHA}X2wHvIWDk6G76CQyCMS1vDCvtICWgn0+
  16. # The database directory MUST exist prior to running slapd AND
  17. # should only be accessible by the slapd and slap tools.
  18. # Mode 700 recommended.
  19. olcDbDirectory: /var/db/openldap-data
  20. # Indices to maintain
  21. olcDbIndex: objectClass eq

这个数据库承载 LDAP 目录的实际内容。除了 mdb 之外,其他类型的数据库都可以使用。它的超级用户,不要和全局用户混淆,在这里配置: olcRootDN 中一个(可能是自定义的)用户名和 olcRootPW 中的密码散列;slappasswd 可以像以前一样使用。

存储库包含 slapd.ldif 的四个示例。要将现有的 slapd.conf 转换为 slapd.ldif,请参阅此页面(请注意,这可能会引入一些无用的选项)。

配置完成后,必须将 slapd.ldif 放在空目录中。建议将其创建为:

  1. # mkdir /usr/local/etc/openldap/slapd.d/

导入配置数据库:

  1. # /usr/local/sbin/slapadd -n0 -F /usr/local/etc/openldap/slapd.d/ -l /usr/local/etc/openldap/slapd.ldif

启动 slapd 守护程序:

  1. # /usr/local/libexec/slapd -F /usr/local/etc/openldap/slapd.d/

-d 选项可用于调试,如 slapd(8) 中所述。要验证服务器是否正在运行且工作正常,请执行以下操作:

  1. # ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
  2. # extended LDIF
  3. #
  4. # LDAPv3
  5. # base <> with scope baseObject
  6. # filter: (objectclass=*)
  7. # requesting: namingContexts
  8. #
  9. #
  10. dn:
  11. namingContexts: dc=domain,dc=example
  12. # search result
  13. search: 2
  14. result: 0 Success
  15. # numResponses: 2
  16. # numEntries: 1

服务器仍必须受信任。如果以前从未这样做过,请按照以下说明进行操作。安装 OpenSSL 软件包或 port:

  1. # pkg install openssl

从存储 ca.crt 的目录(在此示例中为 /usr/local/etc/openldap),运行:

  1. # c_rehash .

CA 和服务器证书现在都可以在各自的角色中正确识别。若要验证这一点,请从 server.crt 目录运行以下命令:

  1. # openssl verify -verbose -CApath . server.crt

如果 slapd 正在运行,请重新启动它。如 /usr/local/etc/rc.d/slapd 中所述,要在引导时正确运行 slapd,必须在 /etc/rc.conf 中添加以下行:

  1. slapd_enable="YES"
  2. slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/
  3. ldap://0.0.0.0/"'
  4. slapd_sockets="/var/run/openldap/ldapi"
  5. slapd_cn_config="YES"

slapd 不提供启动时的调试。为此,请检查 /var/log/debug.logdmesg -a/var/log/messages

下面的例子将组 team 和用户 john 添加到 domain.example LDAP 数据库中,该数据库仍然是空的。首先,创建文件 domain.ldif

  1. # cat domain.ldif
  2. dn: dc=domain,dc=example
  3. objectClass: dcObject
  4. objectClass: organization
  5. o: domain.example
  6. dc: domain
  7. dn: ou=groups,dc=domain,dc=example
  8. objectClass: top
  9. objectClass: organizationalunit
  10. ou: groups
  11. dn: ou=users,dc=domain,dc=example
  12. objectClass: top
  13. objectClass: organizationalunit
  14. ou: users
  15. dn: cn=team,ou=groups,dc=domain,dc=example
  16. objectClass: top
  17. objectClass: posixGroup
  18. cn: team
  19. gidNumber: 10001
  20. dn: uid=john,ou=users,dc=domain,dc=example
  21. objectClass: top
  22. objectClass: account
  23. objectClass: posixAccount
  24. objectClass: shadowAccount
  25. cn: John McUser
  26. uid: john
  27. uidNumber: 10001
  28. gidNumber: 10001
  29. homeDirectory: /home/john/
  30. loginShell: /usr/bin/bash
  31. userPassword: secret

更多细节请参见 OpenLDAP 文档。使用 slappasswd 将纯文本密码secret 替换为 userPassword 中的哈希值。作为 loginShell 指定的路径必须存在于所有允许 john 登录的系统中。最后,使用 mdb 管理员来修改数据库。

  1. # ldapadd -W -D "cn=mdbadmin,dc=domain,dc=example" -f domain.ldif

全局配置部分的修改只能由全局超级用户执行。例如,假定最初指定olcTLSCipherSuite: HIGH:MEDIUM:SSLv3 选项,现在必须将其删除。首先,创建一个包含以下内容的文件:

  1. # cat global_mod
  2. dn: cn=config
  3. changetype: modify
  4. delete: olcTLSCipherSuite

然后,应用修改:

  1. # ldapmodify -f global_mod -x -D "cn=config" -W

当被要求时,提供在配置后台部分选择的密码。用户名不是必需的:在这里,cn=config 代表要修改的数据库部分的DN。另外,使用 ldapmodify 来删除数据库中的某一行,ldapdelete 来删除整个条目。

如果出现问题,或者全局超级用户无法访问配置后端,则可以删除并重新写入整个配置:

  1. # rm -rf /usr/local/etc/openldap/slapd.d/

然后可以编辑并再次导入 slapd.ldif。请仅在没有其他可用解决方案时才执行此过程。

这只是服务器的配置。同一台计算机还可以托管 LDAP 客户端,并具有自己单独的配置。