一、OpenLDAP简介

LDAP是一款轻量级目录访问协议(Lightweight Directory Access Protocol,简称LDAP),属于开源集中账号管理架构的实现,且支持众多系统版本,被广大互联网公司所采用。

LDAP提供并实现目录服务的信息服务,目录服务是一种特殊的数据库系统,对于数据的读取、浏览、搜索有很好的效果。目录服务一般用来包含基于属性的描述性信息并支持精细复杂的过滤功能,但OpenLDAP目录服务不支持通用数据库的大量更新操作所需要的复杂的事务管理或回滚策略等。

LDAP具有两个标准,分别是X.500和LDAP。OpenLDAP是基于X.500标准的,而且去除了X.500复杂的功能并且可以根据自我需求定制额外扩展功能,但与X.500也有不同之处,例如OpenLDAP支持TCP/IP协议等,目前TCP/IP是Internet上访问互联网的协议。

OpenLDAP默认以Berkeley DB作为后端数据库(高版本变更为MDB,从2.4.44开始支持),BerkeleyDB数据库主要以散列的数据类型进行数据存储,如以键值对的方式进行存储。

BerkeleyDB是一类特殊的面向查询进行优化、面向读取进行优化的数据库,主要用于搜索、浏览、更新查询操作,一般对于一次写入数据、多次查询和搜索有很好的效果。BerkeleyDB不支持事务型数据库(MySQL、MariDB、Oracle等)所支持的高并发的吞吐量以及复杂的事务操作。

二、yum安装OpenLDAP

在两台机器均安装 openldap

2.1 初始化环境

主机名IP系统配置
openldap10.0.0.2CentOS - 7.9.20091U 2G

相关软件包:

安装包名称说明
openldapopenldap服务端和客户端必须用的库文件。
openldap-servers用于启动服务和设置. 包含单独的ldap后台守护程序。
openldap-clients用于启动服务和设置. 包含单独的ldap后台守护程序。
openldap-develdevel包,可选择进行安装。
openldap-servers-sql支持sql模块,可进行选择性安装。
migrationtools通过migrationtools实现OpenLDAP用户及用户组的添加,导入系统账户,可进行选择性安装。
compat-openldapopenldap兼容性库 其中compat-openldap这个包与主从有很大的关系

关闭selinux

sed -i '/ELINUX/s/enforcing/disabled/' /etc/selinux/config
setenforce 0

关闭防火墙

systemctl disable  --now firewalld.service

2.2 yum安装OpenLDAP

查看可安装版本

yum list openldap  --show-duplicates

安装openldap指定版本及相关依赖****

openldap_version=2.4.44-25.el7_9  
yum install -y \
openldap-${openldap_version} \
openldap-clients-${openldap_version} \
openldap-servers-${openldap_version} \
openldap-devel-${openldap_version} \
compat-openldap 

准备数据库配置文件

cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG

修改数据目录权限给ldap用户,此用户在安装时已自动创建

chown -R ldap:ldap /var/lib/ldap/DB_CONFIG

查看openldap版本

slapd -VV

启动ldap server服务,先启动服务,后面进行配置更改

systemctl enable slapd --now

查看服务状态

systemctl status slapd

三、配置OpenLDAP

从openldap2.4.23版本开始,所有配置都保存在/etc/openldap/slapd.d目录下的cn=config文件夹内,不再使用slapd.conf作为配置文件。配置文件的后缀为ldif,且每个配置文件都是通过命令自动生成的,任意打开一个配置文件,在开头都会有一行注释,说明此为自动生成的文件,请勿编译,使用ldapmodify命令进行修改。

安装openldap后,会有三个命令用于修改配置文件,分别为ldapadd,ldapmodify,ldapdelete,顾名思义就是添加,修改和删除。而需要修改或增加配置时,则需要先写一个ldif后缀的配置文件,然后通过命令将写的配置更新到slapd.d目录下的配置文件中去,完整的配置过程如下:

3.1 导入基本schema

注意:导入顺序有要求,如果顺序不对会报错

我们需要向ldap中导入一些基本的schema。这些schema文件位于/etc/openldap/schema/目录中,schema控制着条目拥有哪些对象类和属性,可以自行选择需要的进行导入,依次执行下面的命令,导入基础的一些配置,我这里将所有的都导入一下,其中core.ldif是默认已经加载了的,不用导入。

ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/collective.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/corba.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/duaconf.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/dyngroup.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/java.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/misc.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/openldap.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/pmi.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/ppolicy.ldif

3.2 修改配置

创建数据存放目录

mkdir /data/ldap
chown ldap.ldap /data/ldap/

准备加密后的密码(加了盐)

[root@centos7 ~]# slappasswd -s "passwd"
{SSHA}5QOpyWl4FbzXo6RoFNCadFbcT1DsnCLJ

新增changedomain.ldif。根据需要修改olcSuffix、olcRootDN、olcRootPW、olcAccess等选项

cat > changedomain.ldif << EOF
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=admin,dc=ldap,dc=com" read by * none

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=ldap,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=admin,dc=ldap,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}5QOpyWl4FbzXo6RoFNCadFbcT1DsnCLJ

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcDbDirectory
olcDbDirectory: /data/ldap  

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=ldap,dc=com" write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=admin,dc=ldap,dc=com" write by * read
EOF

执行命令,有5个modifying 表示修改全部修改成功

[root@openldap ~]# ldapmodify -Y EXTERNAL -H ldapi:/// -f changedomain.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={1}monitor,cn=config"

modifying entry "olcDatabase={2}hdb,cn=config"

modifying entry "olcDatabase={2}hdb,cn=config"

modifying entry "olcDatabase={2}hdb,cn=config"

modifying entry "olcDatabase={2}hdb,cn=config"

modifying entry "olcDatabase={2}hdb,cn=config"

3.3 添加根节点

未添加根节点时客户端连接ldap服务会报错:

image-20231003123730642

image-20231003123917162

新建 add-rootdn.ldif 文件

cat > add-rootdn.ldif << EOF
dn: dc=ldap,dc=com
objectClass: top
objectClass: domain
o: ldap
EOF

执行命令添加根节点

[root@openldap ~]# ldapadd -x -D cn=admin,dc=ldap,dc=com -W -f add-rootdn.ldif
Enter LDAP Password: 
adding new entry "dc=ldap,dc=com"

再次使用客户端连接不再报错

image-20231003124312261

3.4 启用 memberof 功能

3.4.1 启用功能

新增add-memberof.ldif,#开启memberof 可以查询用户所属组,和第三方应用结合进行组过滤

cat > add-memberof.ldif << EOF
dn: cn=module{0},cn=config
cn: module{0}
objectClass: olcModuleList
objectclass: top
olcModuleload: memberof.la
olcModulePath: /usr/lib64/openldap

dn: olcOverlay={0}memberof,olcDatabase={2}hdb,cn=config
objectClass: olcConfig
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: top
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfUniqueNames
olcMemberOfMemberAD: uniqueMember
olcMemberOfMemberOfAD: memberOf
EOF

新增refint1.ldif文件

cat > refint1.ldif << EOF
dn: cn=module{0},cn=config
add: olcmoduleload
olcmoduleload: refint
EOF

新增refint2.ldif文件

cat > refint2.ldif << EOF
dn: olcOverlay=refint,olcDatabase={2}hdb,cn=config
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcRefintConfig
objectClass: top
olcOverlay: refint
olcRefintAttribute: memberof uniqueMember  manager owner
EOF

依次执行下面命令,加载配置,顺序不能错

ldapadd -Q -Y EXTERNAL -H ldapi:/// -f add-memberof.ldif
ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f refint1.ldif
ldapadd -Q -Y EXTERNAL -H ldapi:/// -f refint2.ldif

### 执行结果
[root@openldap ~]# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f add-memberof.ldif
adding new entry "cn=module{0},cn=config"

adding new entry "olcOverlay={0}memberof,olcDatabase={2}hdb,cn=config"

[root@openldap ~]# ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f refint1.ldif
modifying entry "cn=module{0},cn=config"

[root@openldap ~]# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f refint2.ldif
adding new entry "olcOverlay=refint,olcDatabase={2}hdb,cn=config"

3.4.2 验证结果

使用客户端连接ldap 服务,创建test用户 两种类型的组(Group和groupOfUniqueNames)

image-20231003124425716

Group 以 memberUid 来表示所属关系

image-20231003130942007

groupOfUniqueNames 以 uniqueMember来表示所属关系

image-20231003131144634

然后使用如下查询语句可以查询到test 用户所属的组(很明显只有groupOfUniqueNames类型的组支持),表示 memberOf 功能添加成功!

[root@openldap ~]# ldapsearch -x -LLL -H ldap:/// -D cn=admin,dc=ldap,dc=com -W -b uid=test,dc=ldap,dc=com memberOf
Enter LDAP Password: 
dn: uid=test,dc=ldap,dc=com
memberOf: cn=groupOfUniqueNames\20,dc=ldap,dc=com

3.5 启用日志轮转

默认情况,ldap并没有启用日志记录功能,这里根据需要开启日志功能

新增文件loglevel.ldif

#vim loglevel.ldif
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats

执行命令启用日志

ldapmodify -Y EXTERNAL -H ldapi:/// -f loglevel.ldif 

配置日志

sed -i "/^local7/ a local4.* /var/log/slapd/slapd.log " /etc/rsyslog.conf
systemctl restart rsyslog

查看日志是否生成

tail /var/log/slapd.log #若未看到日志,则重启slapd服务再次观察

启用日志轮转功能

cat > /etc/logrotate.d/slapd <<EOF
/var/log/slapd/slapd.log{
	daily
	rotate 5 
	copytruncate 
	dateext
	missingok
}
EOF
systemctl restart rsyslog

验证日志轮转结果

[root@openldap ldip]# logrotate -f /etc/logrotate.d/slapd 
[root@openldap ldip]# ll /var/log/slapd/
total 4
-rw------- 1 root root   0 Jan 17 16:00 slapd.log
-rw------- 1 root root 486 Jan 17 16:00 slapd.log-20230117

3.6 关闭匿名登录

ldap默认是可以通过匿名登录的(拥有查询权限),从安全角度考虑,需要禁用此功能

匿名查询

[root@openldap ~]# ldapsearch -x -LLL -b  uid=test,dc=ldap,dc=com memberOf
dn: uid=test,dc=ldap,dc=com
memberOf: cn=groupOfUniqueNames\20,dc=ldap,dc=com

新建文件disable_anon.ldif

cat > disable_anon.ldif << EOF
dn: cn=config
changetype: modify
add: olcDisallows
olcDisallows: bind_anon

dn: cn=config
changetype: modify
add: olcRequires
olcRequires: authc

dn: olcDatabase={-1}frontend,cn=config
changetype: modify
add: olcRequires
olcRequires: authc
EOF

执行命令修改配置

[root@openldap ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f disable_anon.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"

modifying entry "cn=config"

modifying entry "olcDatabase={-1}frontend,cn=config"

成功关闭匿名查询

[root@openldap ~]# ldapsearch -x -LLL -b  uid=test,dc=ldap,dc=com memberOf
ldap_bind: Inappropriate authentication (48)
	additional info: anonymous bind disallowed

image-20231003133736066

四、数据备份与恢复

openldap的数据备份,可以通过slapcatldapsearch两种方式来进行。 openldap的数据恢复,则使用slapadd命令。

4.1 使用 slapcat 备份

slapcat命令只能在openldap服务器上执行

[root@openldap ~]# slapcat -n 2 -l ~/ldap_bak.ldif  
651baa6a hdb_db_open: warning - no DB_CONFIG file found in directory /data/ldap: (2).
Expect poor performance for suffix "dc=ldap,dc=com".

 # 数据保存在文件中
[root@openldap ~]# head ldap_bak.ldif 
dn: dc=ldap,dc=com
objectClass: top
objectClass: domain
o: ldap
structuralObjectClass: domain
dc: ldap
entryUUID: ee1ed588-f5f2-103d-9e31-430d06141758
creatorsName: cn=admin,dc=ldap,dc=com
createTimestamp: 20231003044158Z
entryCSN: 20231003044158.023887Z#000000#000#000000

4.2 使用 ldapsearch 备份

ldapsearch命令可以在openldap服务器或者openldap客户端上执行

ldapsearch -x -D "cn=admin,dc=ldap,dc=com" -w "passwd" -b "dc=ldap,dc=com" -LLL -H ldap://10.0.0.2 > ~/ldap_bak.ldif

以上是使用用户密码验证方式备份,如果openldap允许匿名访问的话,执行命令如下:

ldapsearch -x -b "dc=ldap,dc=com" -H ldap://10.0.0.2 -LLL > ~/ldap_bak.ldif

4.3 备份指定 basedn 数据

例如,只备份用户数据,可以指定用户所在basedn,例如:cn=users,dc=ldap,dc=com

ldapsearch -x -D "cn=admin,dc=ldap,dc=com" -w "passwd" -b "cn=users,dc=ldap,dc=com" -LLL -H ldap://10.0.0.2 > ~/uesrs_bak.ldif

4.4 全量数据恢复

关闭openldap服务,并删除数据

 systemctl stop slapd
 rm -rf /var/lib/ldap/*

导入openldap备份数据

slapadd -l ~/ldap_bak.ldif

复制DB配置文件

cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
chown ldap:ldap -R /var/lib/ldap/

启动OpenLDAP服务

systemctl start slapd

4.5 恢复指定 basedn 数据

恢复指定basedn数据时,需要只有basedn的备份数据,或从全量数据中摘出来需要恢复的basedn数据的单独ldif文件 例如,恢复用户所在的basedn数据

ldapadd -H ldap://10.0.0.2 -x -D "cn=admin,dc=ldap,dc=com" -w "password" -f ~/uesrs_bak.ldif

需要注意的是,要提前确保需要恢复的basedn和basedn下的数据不能重复,否则遇到重复的数据会失败并退出,可以提前将重复的数据删除再进行恢复或者恢复到一个新的basedn(需要改备份文件的basedn相关内容)

4.6 备份脚本

#!/bin/bash

LDAPBK=ldap-$( date +%Y%m%d-%H ).ldif

BACKUPDIR=/root/ldap_backups

BACKUP_EXEC=`which slapcat`

PACKAGE=`which gzip`

FIND=`which find`


checkdir(){
	if [ ! -d "$BACKUPDIR" ]; then
	  mkdir -p ${BACKUPDIR}
	fi
}

backuping(){
	echo "Backup Ldap Start...."
	${BACKUP_EXEC} -n 2 -l ${BACKUPDIR}/${LDAPBK}

	${PACKAGE} -9 $BACKUPDIR/$LDAPBK
}
delete_expired_files() {
	${FIND} $BACKUPDIR/ -ctime +30 -name "*.gz" -exec rm {} \;
}
checkdir
backuping
delete_expired_files

定时备份

crontab -e
0 2 * * * /path/ldap_backup.sh

参考链接

slapd-config(5) (openldap.org)

https://chenzhonzhou.github.io/2020/11/03/openldap-yum-an-zhuang/

OpenLDAP 数据备份与恢复 | 凡间的精灵

https://wandouduoduo.github.io/articles/3337f7d4.html