runsisi's

technical notes

OpenLDAP 安装

2019-06-04 runsisilinux

OpenLDAP 是 LDAP 的开源实现,服务端工具集的名字以 slap (stand-alone LDAP) 为前缀,客户端工具集的名字以 ldap 为前缀。

从 2.4 版本开始,slapd 的配置使用 LDIF 格式进行定义(man slapd-config),以 DIT(Directory Information Tree) 的组织形式存储在指定的配置文件夹中,原有的配置文件格式(man slapd.conf)在未来的版本中将可能被废弃。

http://www.openldap.org/doc/admin24/guide.html#Configuring slapd

1. 安装

1.1 CentOS 7

~$ rpm -qi openldap-servers
Name        : openldap-servers
Version     : 2.4.44
Release     : 21.el7_6
...
~$ yum whatprovides */ldapsearch
...
openldap-clients-2.4.44-20.el7.x86_64 : LDAP client utilities
Repo        : os
Matched from:
Filename    : /usr/bin/ldapsearch
~$ sudo yum install openldap-clients
~$ rpm -ql openldap-servers
/etc/openldap/check_password.conf
/etc/openldap/schema
/etc/openldap/schema/collective.ldif
...
/etc/openldap/slapd.conf
/etc/openldap/slapd.d
/etc/sysconfig/slapd
...
/usr/sbin/slapacl
/usr/sbin/slapadd
/usr/sbin/slapauth
/usr/sbin/slapcat
/usr/sbin/slapd
/usr/sbin/slapdn
/usr/sbin/slapindex
/usr/sbin/slappasswd
/usr/sbin/slapschema
/usr/sbin/slaptest
...
/usr/share/openldap-servers/DB_CONFIG.example
/usr/share/openldap-servers/slapd.ldif
...
~$ rpm -ql openldap-clients
/usr/bin/ldapadd
/usr/bin/ldapcompare
/usr/bin/ldapdelete
/usr/bin/ldapexop
/usr/bin/ldapmodify
/usr/bin/ldapmodrdn
/usr/bin/ldappasswd
/usr/bin/ldapsearch
/usr/bin/ldapurl
/usr/bin/ldapwhoami
...

看看 slapd 是如何生成初始配置的:

~$ rpm -q --scripts openldap-servers
...
postinstall scriptlet (using /bin/sh):
...
# generate sample TLS certificate for server (will not replace)
/usr/libexec/openldap/generate-server-cert.sh -o &>/dev/null || :

# generate/upgrade configuration
if [ ! -f /etc/openldap/slapd.d/cn=config.ldif ]; then
  if [ -f /etc/openldap/slapd.conf ]; then
    /usr/libexec/openldap/convert-config.sh &>/dev/null
    mv /etc/openldap/slapd.conf /etc/openldap/slapd.conf.bak
  else
    /usr/libexec/openldap/convert-config.sh -f /usr/share/openldap-servers/slapd.ldif &>/dev/null
  fi
fi
...

1.2 Ubuntu 18.04

~$ dpkg -s slapd
Package: slapd
Status: install ok installed
Priority: optional
Section: net
Installed-Size: 15450
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Source: openldap
Version: 2.4.45+dfsg-1ubuntu1.2
...
~$ dpkg -L slapd
/.
/etc
/etc/apparmor.d
/etc/apparmor.d/usr.sbin.slapd
/etc/default
/etc/default/slapd
/etc/init.d
/etc/init.d/slapd
/etc/ldap
/etc/ldap/sasl2
/etc/ldap/schema
/etc/ldap/schema/README
/etc/ldap/schema/collective.ldif
...
/etc/ufw
/etc/ufw/applications.d
/etc/ufw/applications.d/slapd
...
/usr/sbin/slapacl
/usr/sbin/slapadd
/usr/sbin/slapauth
/usr/sbin/slapcat
/usr/sbin/slapd
/usr/sbin/slapdn
/usr/sbin/slapindex
/usr/sbin/slappasswd
/usr/sbin/slapschema
/usr/sbin/slaptest
...
/usr/share/slapd/DB_CONFIG
/usr/share/slapd/ldiftopasswd
/usr/share/slapd/slapd.conf
/usr/share/slapd/slapd.init.ldif
...
~$ dpkg -L ldap-utils
...
/usr/bin/ldapcompare
/usr/bin/ldapdelete
/usr/bin/ldapexop
/usr/bin/ldapmodify
/usr/bin/ldapmodrdn
/usr/bin/ldappasswd
/usr/bin/ldapsearch
/usr/bin/ldapurl
/usr/bin/ldapwhoami
...

看看 slapd 是如何生成初始配置的:

# debian/slapd.postinst
postinst_initial_configuration() {					# {{{
# Configure slapd for the first time (when first installed)
# Usage: postinst_initial_configuration

	if manual_configuration_wanted; then
		echo "  Omitting slapd configuration as requested." >&2
	else
		crypt_admin_pass
		create_new_configuration
	fi
}

# Configuration.
if is_initial_configuration "$@"; then
	postinst_initial_configuration
else
	postinst_upgrade_configuration
fi
# debian/slapd.scripts-common
create_new_configuration() {						# {{{
# Create a new configuration and directory

	local basedn dc backend

	# For the domain really.argh.org we create the basedn 
	# dc=really,dc=argh,dc=org with the dc entry dc: really
	db_get slapd/domain
	basedn="dc=`echo $RET | sed 's/^\.//; s/\.$//; s/\./,dc=/g'`"
	dc="`echo $RET | sed 's/^\.//; s/\..*$//'`"

	db_get slapd/backend
	backend="`echo $RET|tr A-Z a-z`"

	backup_config_once
	if [ -e "/var/lib/ldap" ] && ! is_empty_dir /var/lib/ldap; then
		echo >&2 "  Moving old database directory to /var/backups:"
		move_old_database_away /var/lib/ldap
	fi
	create_ldap_directories
	create_new_slapd_conf "$basedn" "$backend"
	create_new_directory "$basedn" "$dc"

	# Put the right permissions on this directory.
	update_permissions /var/lib/ldap

	# Now that we created the new directory we don't need the passwords in the
	# debconf database anymore. So wipe them.
	wipe_admin_pass
}

在 debian 系发行版下,初始化 slapd 配置可以使用如下的交互式方式:

~$ sudo dpkg-reconfigure slapd

1.3 docker

~$ docker pull osixia/openldap
~$ docker run -idt --net host --rm osixia/openldap

注意:使用 host 容器网络需要确保主机自身没有 slapd 服务(即 OpenLDAP 服务)已启用,否则会因为端口冲突导致容器进程启动失败。

2. 配置

通过 slapcat 命令可以以 LDIF 格式查看当前 OpenLDAP 数据库的内容。

~# slapcat -b cn=config

或者:

~# slapcat -n 0

其中数据库名(suffix) cn=config 或者编号 0 是 OpenLDAP 自身的配置数据库,而用户数据库名或编号可以通过查询配置数据库得到。

2.1 CentOS 7

2.1.1 删除配置及用户数据库

~# systemctl stop slapd
~# rm -rf /etc/openldap/slapd.d/*
~# rm -f /var/lib/ldap/*

2.1.2 定义配置及用户数据库

~$ cp /usr/share/openldap-servers/slapd.ldif .
~$ vi slapd.ldif
--- /usr/share/openldap-servers/slapd.ldif      2019-01-30 01:43:29.000000000 +0800
+++ slapd.ldif  2019-06-06 10:00:46.031012384 +0800
@@ -11,9 +11,9 @@
 #
 # TLS settings
 #
-olcTLSCACertificatePath: /etc/openldap/certs
-olcTLSCertificateFile: "OpenLDAP Server"
-olcTLSCertificateKeyFile: /etc/openldap/certs/password
+#olcTLSCACertificatePath: /etc/openldap/certs
+#olcTLSCertificateFile: "OpenLDAP Server"
+#olcTLSCertificateKeyFile: /etc/openldap/certs/password
 #
 # Do not enable referrals until AFTER you have a working directory
 # service AND an understanding of referrals.
@@ -131,18 +131,19 @@
 objectClass: olcDatabaseConfig
 olcDatabase: monitor
 olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,c
- n=auth" read by dn.base="cn=Manager,dc=my-domain,dc=com" read by * none
+ n=auth" read by dn.base="cn=admin,dc=runsisi,dc=com" read by * none
 
 #
 # Backend database definitions
 #
 
-dn: olcDatabase=hdb,cn=config
+dn: olcDatabase=mdb,cn=config
 objectClass: olcDatabaseConfig
-objectClass: olcHdbConfig
-olcDatabase: hdb
-olcSuffix: dc=my-domain,dc=com
-olcRootDN: cn=Manager,dc=my-domain,dc=com
+objectClass: olcMdbConfig
+olcDatabase: mdb
+olcSuffix: dc=runsisi,dc=com
+olcRootDN: cn=admin,dc=runsisi,dc=com
+olcRootPW: {SSHA}UNC/GjBr74HdBGx92smagS0sjP0HhT2u
 olcDbDirectory:        /var/lib/ldap
 olcDbIndex: objectClass eq,pres
 olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub

其中 olcSuffix 是用户数据库名,olcRootPW 是 OpenLDAP 管理员密码,使用 slappasswd 生成。

这里禁用了 tls,因为 rpm 包的 postinst 脚本无法正确的生成证书,如果需要启用 tls 可以阅读参考资料中的相关链接。

2.1.3 生成配置数据

~# slapadd -F /etc/openldap/slapd.d/ -n 0 -l slapd.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

或者:

~# slapadd -F /etc/openldap/slapd.d/ -b cn=config -l slapd.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

2.1.4 查看配置数据

~# slapcat -n 0
...
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=extern
 al,cn=auth" manage by * none
structuralObjectClass: olcDatabaseConfig
entryUUID: 6e901e92-1c4b-1039-9278-c58c446c6567
creatorsName: cn=config
createTimestamp: 20190606020625Z
entryCSN: 20190606020625.057105Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20190606020625Z

dn: olcDatabase={1}monitor,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {1}monitor
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=extern
 al,cn=auth" read by dn.base="cn=admin,dc=runsisi,dc=com" read by * none
structuralObjectClass: olcDatabaseConfig
entryUUID: 6e903fda-1c4b-1039-9279-c58c446c6567
creatorsName: cn=config
createTimestamp: 20190606020625Z
entryCSN: 20190606020625.057957Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20190606020625Z

dn: olcDatabase={2}mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: {2}mdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=runsisi,dc=com
olcRootDN: cn=admin,dc=runsisi,dc=com
olcRootPW:: e1NTSEF9VU5DL0dqQnI3NEhkQkd4OTJzbWFnUzBzalAwSGhUMnU=
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
structuralObjectClass: olcMdbConfig
entryUUID: 6e904bc4-1c4b-1039-927a-c58c446c6567
creatorsName: cn=config
createTimestamp: 20190606020625Z
entryCSN: 20190606020625.058262Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20190606020625Z

2.1.5 启用服务

启用服务时用户数据库会自动创建。

~# chown -R ldap.ldap /etc/openldap/slapd.d/
~# chown ldap.ldap /var/lib/ldap/
~# chmod 700 /var/lib/ldap/
~# systemctl start slapd

2.1.6 创建用户 DIT

DIT 名称空间(根目录,suffix, namingContexts)定义的约定可以查看如下链接:

https://ldap.com/dit-and-the-ldap-root-dse/

~$ vi root.ldif
dn: dc=runsisi,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: runsisi
o: my own company

注意这里的 dn 需要与用户数据库中定义的 olcSuffix 一致(即用户数据库与用户 DIT 两者的名称空间命名要一致),否则会报如下的错:

~# slapadd -F /etc/openldap/slapd.d/ -n 2 -l root.ldif  
slapadd: line 1: database #2 (dc=runsisi,dc=com) not configured to hold "dc=hustlrb,dc=com"; no database configured for that naming context
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...
~# slapadd -F /etc/openldap/slapd.d/ -b dc=runsisi,dc=com -l root.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

或者:

~# slapadd -F /etc/openldap/slapd.d/ -n 2 -l root.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

注意:-n 指定的数据库编号通过前面的 slapcat 得到。

2.2 Ubuntu 18.04

2.2.1 删除配置及用户数据库

~# systemctl stop slapd
~# rm -rf /etc/ldap/slapd.d/*
~# rm -f /var/lib/ldap/*

2.2.2 定义配置及用户数据库

~$ cp /usr/share/slapd/slapd.init.ldif .
~$ vi slapd.init.ldif
--- /usr/share/slapd/slapd.init.ldif    2018-10-23 21:01:47.000000000 +0800
+++ slapd.init.ldif     2019-06-05 15:38:56.773924017 +0800
@@ -49,32 +49,32 @@
 cn: module{0}
 # Where the dynamically loaded modules are stored
 olcModulePath: /usr/lib/ldap
-olcModuleLoad: back_@BACKEND@
+olcModuleLoad: back_mdb

 # Set defaults for the backend
-dn: olcBackend=@BACKEND@,cn=config
+dn: olcBackend=mdb,cn=config
 objectClass: olcBackendConfig
-olcBackend: @BACKEND@
+olcBackend: mdb

 # The database definition.
-dn: olcDatabase=@BACKEND@,cn=config
+dn: olcDatabase=mdb,cn=config
 objectClass: olcDatabaseConfig
-objectClass: @BACKENDOBJECTCLASS@
-olcDatabase: @BACKEND@
+objectClass: olcMdbConfig
+olcDatabase: mdb
 # Checkpoint the database periodically in case of system
 # failure and to speed slapd shutdown.
 olcDbCheckpoint: 512 30
-@BACKENDOPTIONS@
+olcDbMaxSize: 1073741824
 # Save the time that the entry gets modified, for database #1
 olcLastMod: TRUE
 # The base of your directory in database #1
-olcSuffix: @SUFFIX@
+olcSuffix: dc=runsisi,dc=com
 # Where the database file are physically stored for database #1
 olcDbDirectory: /var/lib/ldap
 # olcRootDN directive for specifying a superuser on the database. This
 # is needed for syncrepl.
-olcRootDN: cn=admin,@SUFFIX@
-olcRootPW: @PASSWORD@
+olcRootDN: cn=admin,dc=runsisi,dc=com
+olcRootPW: {SSHA}UNC/GjBr74HdBGx92smagS0sjP0HhT2u
 # Indexing options for database #1
 olcDbIndex: objectClass eq
 olcDbIndex: cn,uid eq

其中 olcSuffix 是用户数据库名,olcRootPW 是 OpenLDAP 管理员密码,使用 slappasswd 生成。

olcRootPW 的修改也可以后期通过 ldapmodify 进行修改:

~$ vi xxx.ldif
dn: olcDatabase={2}mdb,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}UNC/GjBr74HdBGx92smagS0sjP0HhT2u

2.2.3 生成配置数据

~# slapadd -F /etc/ldap/slapd.d/ -b cn=config -l slapd.init.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

或者:

~# slapadd -F /etc/ldap/slapd.d/ -n 0 -l slapd.init.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

2.2.4 查看配置数据

~# slapcat -n 0
...
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=extern
 al,cn=auth manage by * break
structuralObjectClass: olcDatabaseConfig
entryUUID: 9649c6be-1c45-1039-9dd0-35ab91e2fabd
creatorsName: cn=config
createTimestamp: 20190606012434Z
entryCSN: 20190606012434.724590Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20190606012434Z

dn: olcDatabase={1}mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: {1}mdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=runsisi,dc=com
olcAccess: {0}to attrs=userPassword by self write by anonymous auth by * non
 e
olcAccess: {1}to attrs=shadowLastChange by self write by * read
olcAccess: {2}to * by * read
olcLastMod: TRUE
olcRootDN: cn=admin,dc=runsisi,dc=com
olcRootPW:: e1NTSEF9VU5DL0dqQnI3NEhkQkd4OTJzbWFnUzBzalAwSGhUMnU=
olcDbCheckpoint: 512 30
olcDbIndex: objectClass eq
olcDbIndex: cn,uid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: member,memberUid eq
olcDbMaxSize: 1073741824
structuralObjectClass: olcMdbConfig
entryUUID: 964a75e6-1c45-1039-9dd8-35ab91e2fabd
creatorsName: cn=config
createTimestamp: 20190606012434Z
entryCSN: 20190606012434.729075Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20190606012434Z

2.2.5 启用服务

启用服务时用户数据库会自动创建。

~# chown -R openldap.openldap /etc/ldap/slapd.d/
~# chown openldap.openldap /var/lib/ldap/
~# chmod 700 /var/lib/ldap/
~# systemctl start slapd

2.2.6 创建用户 DIT

~$ vi root.ldif
dn: dc=runsisi,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: runsisi
o: my own company

注意这里的 dn 需要与用户数据库中定义的 olcSuffix 一致(即用户数据库与用户 DIT 两者的名称空间命名要一致),否则会报如下的错:

~# slapadd -F /etc/ldap/slapd.d/ -n 1 -l root.ldif 
slapadd: line 1: database #1 (dc=runsisi,dc=com) not configured to hold "dc=hustlrb,dc=com"; no database configured for that naming context
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...
~# slapadd -F /etc/ldap/slapd.d/ -b dc=runsisi,dc=com -l root.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

或者:

~# slapadd -F /etc/ldap/slapd.d/ -n 1 -l root.ldif
_#################### 100.00% eta   none elapsed            none fast!         
Closing DB...

注意:-n 指定的数据库编号通过前面的 slapcat 得到。

2.3 docker

docker-openldap 镜像所创建的容器可以通过环境变量进行配置,具体的可以参考其 github 项目主页的 readme 文档。

4. 参考资料

Step by Step OpenLDAP Server Configuration on CentOS 7 / RHEL 7

https://www.itzgeek.com/how-tos/linux/centos-how-tos/step-step-openldap-server-configuration-centos-7-rhel-7.html

Configure OpenLDAP with SSL on CentOS 7 / RHEL 7

https://www.itzgeek.com/how-tos/linux/centos-how-tos/configure-openldap-with-ssl-on-centos-7-rhel-7.html

CentOS openLDAP cert trust issues

https://serverfault.com/questions/437546/centos-openldap-cert-trust-issues

A docker image to run OpenLDAP

https://github.com/osixia/docker-openldap