一、背景

OpenLDAP是开源的目录服务实现,AD是微软的目录服务现实。在我们的业务环境中可能会出现有的应用场景(应用、客户端)跟OpenLDAP结合比较容易;有的应用场景又必须要使用AD。几乎不可能弃用其中的任意一种。但同时维护两套系统意味着维护工作大量增加(不仅仅只是增加一倍,要考虑信息分别维护、同步等)、出错几率大大增加。

其中的一种较成熟、使用比较多的解决方案是:OpenLDAP使用AD的认证,即只在AD上维护一套用户密码,OpenLDAP将认证转发到微软AD上进行。

二、相关组件

  1. LDAP Client:这个是实际调用ldap服务的系统,也可以是类似ldapsearch之类的client程序
  2. OpenLDAP服务器:开源服务端,实际进程为slapd (OpenLDAP 2.4.44)
  3. saslauthd :简单认证服务层的守护进程,该进程要安装在openldap服务器上 (cyrus-sasl-2.1.26)
  4. AD:微软AD

流程图

三、部署

1、安装OpenLdap

(1)安装OpenLDAP服务

注:本文仅以OpenLDAP 2.4.44版本为例进行安装和配置说明,其他版本如有差异请以实际为准。

[root@localhost ~]# yum install -y openldap openldap-clients openldap-servers-sql compat-openldap openldap-devel openldap-servers
[root@localhost ~]# systemctl restart slapd.service
[root@localhost ~]# systemctl enable slapd.service

(2)配置OpenLDAP管理密码

并修改openldap配置

[root@localhost ~]# slappasswd
New password: 
Re-enter new password: 
{SSHA}XTelJmyJk2XEG/hA+E5UpHvO4Z89b7n7

把上面生成的{SSHA}开头的字符串记下来,后面修改配置文件要用


# 新建一个ldif文件用于修改openldap配置
[root@localhost ~]#  vim change_ldap_cfg.ldif
# 将以下内容写入
# 实际配置的时候建议把“#”后面的注释内容删掉,只保留配置内容
dn: olcDatabase={2}hdb,cn=config
changetype: modify  # 表示我们需要为这个文件执行变更操作
replace: olcRootDN  # 修改olcRootDN这个字段的内容
olcRootDN: cn=Manager,dc=test,dc=winad,dc=com  # 把olcRootDN这个字段的内容修改成这样
-  # 具体含义不知道,但是大概表示上面这个dn的配置还没修改完,下面还是修改这个dn的配置
replace: olcSuffix  # 修改olcSuffix这个字段的内容
olcSuffix: dc=test,dc=winad,dc=com  # 把olcSuffix这个字段的内容修改成这样
-
add: olcRootPW   # 增加一个olcRootPW字段
olcRootPW: {SSHA}XTelJmyJk2XEG/hA+E5UpHvO4Z89b7n7   # 第2步生成的密码,增加的olcRootPW这个字段的内容是这样

dn: olcDatabase={1}monitor,cn=config  # 表示修改/etc/openldap/slapd.d/cn=config/olcDatabase={1}monitor.ldif这个文件里的内容
changetype: modify  # 表示我们需要为这个文件执行变更操作
replace: olcAccess  # 修改olcAccess这个字段的内容
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=extern
 al,cn=auth" read by dn.base="cn=Manager,dc=test,dc=winad,dc=com" read by * none  # 把olcAccess这个字段的内容修改成这样

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=Manager,dc=huawang,dc=com
-
replace: olcSuffix
olcSuffix: dc=huawang,dc=com
-
add: olcRootPW
olcRootPW: {SSHA}XTelJmyJk2XEG/hA+E5UpHvO4Z89b7n7

dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=extern
 al,cn=auth" read by dn.base="cn=Manager,dc=huawang,dc=com" read by * none

上面的配置文件保存好之后,执行ldapmodify命令进行修改

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

modifying entry "olcDatabase={1}monitor,cn=config"

执行完了以后看下下面这两个文件,看看需要修改的字段改过来没有

/etc/openldap/slapd.d/cn=config/olcDatabase={1}monitor.ldif
/etc/openldap/slapd.d/cn=config/olcDatabase={2}hdb.ldif

(3)创建管理员账号

新建一个ldif文件用于导入管理员账号

[root@localhost ~]# vim base.ldif
# 添加以下内容
dn: dc=huawang,dc=com
o: huawang com
dc: huawang
objectClass: top
objectClass: dcObject
objectclass: organization

dn: cn=Manager,dc=huawang,dc=com
cn: Manager
objectClass: organizationalRole
description: Directory Manager

上面的配置文件保存好之后,执行ldapadd命令导入

导入账号

[root@localhost ~]# ldapadd -x -D "cn=Manager,dc=huawang,dc=com" -W -f base.ldif 
Enter LDAP Password:  # 这里输的密码就是上面第二步的时候配置的那个密码
adding new entry "dc=huawang,dc=com"

adding new entry "cn=Manager,dc=huawang,dc=com"

(4)配置DB数据库

[root@localhost ~]# cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
[root@localhost ~]# chown ldap:ldap -R /var/lib/ldap
[root@localhost ~]# chmod 700 -R /var/lib/ldap

(5)验证OpenLDAP配置文件

是否正确

[root@localhost ~]# slaptest -u
config file testing succeeded   #验证成功,如果是返回其他内容则失败。

(6)给相关目录授权

否则启动服务时可能会报错,权限不足

[root@localhost ~]# chown ldap:ldap -R /var/run/openldap
[root@localhost ~]# chown ldap:ldap -R /etc/openldap/

(7)导入schema

[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/collective.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/corba.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/core.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/duaconf.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/dyngroup.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/java.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/misc.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/openldap.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/pmi.ldif
[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/ppolicy.ldif

(8)添加memberOf模块

因为我们是要和WindowsAD联动,所以需要将权限组这个模块提前准备好。如果提前没有准备好,后面再加的话,还得把建好的组全删掉再重建。这个模块的作用是当你建一个组的时候,把一些用户添加到这个组里去,它会自动给这些用户添加一个memberOf属性,有很多应用需要检查这个属性。

添加的时候比较麻烦,需要建3个ldif文件,然后1个执行ldapmodify,2个执行ldapadd,注意顺序,不能出错

新建一个memberof_config.ldif文件

[root@localhost ~]# vim memberof_config.ldif
# 在文件中写入以下内容
dn: cn=module,cn=config
cn: module
objectClass: olcModuleList
olcModuleLoad: memberof
olcModulePath: /usr/lib64/openldap # 这里请注意,请确认/usr/lib64/目录下是否有openldap目录

dn: olcOverlay={0}memberof,olcDatabase={2}hdb,cn=config  # 这个意思是说在/etc/openldap/slapd.d/cn=config/目录下创建一个olcDatabase={2}hdb目录,然后在里面再创建一个olcOverlay={0}memberof.ldif文件
objectClass: olcConfig
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: top
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfNames
olcMemberOfMemberAD: member
olcMemberOfMemberOfAD: memberOf

文件保存好之后,执行ldapadd命令

[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f memberof_config.ldif

执行完之后,检查你的/etc/openldap/slapd.d/cn=config/olcDatabase={2}hdb/目录下,看是不是多了一个olcOverlay={0}memberof.ldif模块

[root@ad-passwd (13:57:34)~]# ll /etc/openldap/slapd.d/cn=config/olcDatabase={2}hdb/
总用量 4
-rw------- 1 ldap ldap 700 11月  6 13:55 olcOverlay={0}memberof.ldif

然后检查你的/etc/openldap/slapd.d/cn=config/目录下,看是不是多了一个cn=module{0}.ldif模块,这个模块的数字编号直接影响下一步操作。

[root@ad-passwd (13:58:18)~]# ll /etc/openldap/slapd.d/cn=config/
总用量 28
-rw-------. 1 ldap ldap  534 11月  7 14:28 cn=module{0}.ldif
drwxr-x---. 2 ldap ldap 4096 11月  7 14:26 cn=schema
-rw-------. 1 ldap ldap  378 11月  6 18:08 cn=schema.ldif
-rw-------. 1 ldap ldap  513 11月  6 18:08 olcDatabase={0}config.ldif
-rw-------. 1 ldap ldap  443 11月  6 18:08 olcDatabase={-1}frontend.ldif
-rw-------. 1 ldap ldap  606 11月  7 14:05 olcDatabase={1}monitor.ldif
drwxr-x---. 2 ldap ldap   41 11月  7 14:28 olcDatabase={2}hdb
-rw-------. 1 ldap ldap  716 11月  7 14:05 olcDatabase={2}hdb.ldif

新建一个refint1.ldif文件

[root@localhost ~]# vim refint1.ldif
# 在文件中写入以下内容
dn: cn=module{0},cn=config # 这里的意思就是我们上面说的那个/etc/openldap/slapd.d/cn=config/目录下的cn=module{0}.ldif,我们这一次要修改这个文件
add: olcmoduleload
olcmoduleload: refint

如果你那边不是module{0}的话,那就看是几,是几就写几就行了,对于这个文件,我们要执行ldapmodify操作:

[root@localhost ~]# ldapmodify -Y EXTERNAL -H ldapi:/// -f refint1.ldif

接下来新建一个refint2.ldif文件

[root@localhost ~]# vim refint2.ldif

dn: olcOverlay={1}refint,olcDatabase={2}hdb,cn=config # 在/etc/openldap/slapd.d/cn=config/olcDatabase={2}hdb目录下,再创建一个olcOverlay={1}refint.ldif文件
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcRefintConfig
objectClass: top
olcOverlay: {1}refint
olcRefintAttribute: memberof member manager owner

对这个文件执行ldapadd操作:

[root@localhost ~]# ldapadd -Y EXTERNAL -H ldapi:/// -f refint2.ldif

重启slapd服务

# systemctl restart slapd.service
# systemctl status slapd.service 
● slapd.service - OpenLDAP Server Daemon
   Loaded: loaded (/usr/lib/systemd/system/slapd.service; enabled; vendor preset: disabled)
   Active: active (running) since 一 2023-11-06 14:24:01 CST; 5s ago
     Docs: man:slapd
           man:slapd-config
           man:slapd-hdb
           man:slapd-mdb
           file:///usr/share/doc/openldap-servers/guide.html
  Process: 37076 ExecStart=/usr/sbin/slapd -u ldap -h ${SLAPD_URLS} $SLAPD_OPTIONS (code=exited, status=0/SUCCESS)
  Process: 37022 ExecStartPre=/usr/libexec/openldap/check-config.sh (code=exited, status=0/SUCCESS)
 Main PID: 37105 (slapd)
    Tasks: 2
   Memory: 15.6M
   CGroup: /system.slice/slapd.service
           └─37105 /usr/sbin/slapd -u ldap -h ldapi:/// ldap:///

11月 06 14:24:01 ad-passwd runuser[37042]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
11月 06 14:24:01 ad-passwd runuser[37042]: pam_unix(runuser:session): session closed for user ldap
11月 06 14:24:01 ad-passwd runuser[37044]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
11月 06 14:24:01 ad-passwd runuser[37050]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
11月 06 14:24:01 ad-passwd runuser[37054]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
11月 06 14:24:01 ad-passwd runuser[37060]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
11月 06 14:24:01 ad-passwd runuser[37069]: pam_unix(runuser:session): session opened for user ldap by (uid=0)
11月 06 14:24:01 ad-passwd slapd[37076]: @(#) $OpenLDAP: slapd 2.4.44 (Feb 23 2022 17:11:27) $
                                                  mockbuild@x86-01.bsys.centos.org:/builddir/build/BUILD/openldap-2.4.44/openldap-2.4.44/servers/slapd
11月 06 14:24:01 ad-passwd slapd[37105]: slapd starting
11月 06 14:24:01 ad-passwd systemd[1]: Started OpenLDAP Server Daemon.

(9)检查OpenLDAP状态

执行ldapsearch -x检查是否有如下输出

[root@localhost ~]# ldapsearch -x -b '' -s base'(objectclass=*)'
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: ALL
#

#
dn:
objectClass: top
objectClass: OpenLDAProotDSE

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

2、部署Saslauthd

(1)安装saslauthd服务

[root@localhost ~]# yum install -y cyrus-sasl
[root@localhost ~]# systemctl restart saslauthd.service
[root@localhost ~]# systemctl enable saslauthd.service

(2)测试ldapsearch搜索

微软Windows AD是否正常
如果能搜索到用户,说明openldap访问Windows AD正常

(3)配置sasl访问ad

编辑/etc/sysconfig/saslauthd

[root@localhost ~]# vim /etc/sysconfig/saslauthd

修改为下面两行

MECH=ldap
FLAGS="-O /etc/saslauthd2ad.conf"

然后新建一个 /etc/saslauthd2ad.conf ,写入下面内容
ldap_servers 为微软AD 域连接地址,
ldap_bind_dn 微软 AD 域 信息,本次使用管理员信息,生产环境可以新建一个账号,也是可以的,因为他们认证过程不需要管理员。
ldap_password 域内密码(本次使用管理员信息)

[root@localhost ~]# vim  /etc/saslauthd2ad.conf

ldap_servers: ldap://192.168.110.253  
ldap_search_base: DC=huawang,DC=com
ldap_timeout: 60
ldap_filter: sAMAccountName=%U
ldap_bind_dn: CN=Administrator,CN=Users,DC=huawang,DC=com
ldap_password: Windows AD域管理员密码
ldap_deref: never
ldap_restart: yes
ldap_scope: sub
ldap_use_sasl: no
ldap_start_tls: no
ldap_version: 3
ldap_auth_method: bind

重启saslauthd服务

[root@localhost ~]# systemctl restart saslauthd.service

使用testsaslauthd命令测试WindowsAD上的用户是否认证成功

[root@localhost ~]# testsaslauthd -u Administrator -p testAD
0: OK "Success."
#表示 已经能成功通过saslauthd进行认证

可进一步AD里面加用户、或改密码测试。需注意AD修改密码,老密码依然可用5分钟。如验证不通过检查 sasl的配置。

(4)配置openldap

配置openldap 使用Saslauthd

编辑 /etc/openldap/ldap.conf

[root@localhost ~]# vim /etc/openldap/ldap.conf
# 增加以下内容
TLS_REQCERT never

sasl-host localhost
sasl-secprops none
#这两行配置非常重要,是告诉openldap使用本机的sasl服务,
#看了好多文档,花费7天时间,反复踩坑才后发现很多文档没说需要加这两行,导致LDAP-的认证请求没发往AD :(

重启 openldap

systemctl restart slapd.service

新建 /etc/sasl2/slapd.conf

[root@localhost ~]# vim /etc/sasl2/slapd.conf
# 添加如下内容
mech_list: plain
pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux

最后重启saslauthd服务

[root@localhost ~]# systemctl restart saslauthd.service

验证openldap是否支持SASL

[root@localhost ~]# ldapsearch -x -H ldap://127.0.0.1 -ZZ -b "" -LLL -s base supportedSASLMechanisms
dn:
supportedSASLMechanisms: LOGIN
supportedSASLMechanisms: PLAIN
# 出现如上结果说明openldap已支持SASL认证

#在上面的AD示例中,首先检查saslauthd在连接到AD时将使用的DN和密码是否有效:
ldapsearch -x -H ldap://192.168.110.253/ \
  -D cn=Administrator,cn=Users,DC=huawang,DC=com \
  -w password \
  -b '' \
  -s base

检查用户是否可以绑定到AD:

ldapsearch -x -H ldap://192.168.110.253/ \
  -D cn=Administrator,cn=Users,DC=huawang,DC=com \
  -w password \
  -b cn=Users,DC=huawang,DC=com \
  -s base \
  "(objectclass=*)"

3、安装phpldapadmin

phpldapadmin提供了使用web页面管理OpenLDAP的方式,可直接安装,或Docker容器安装,

vim docker-compose.yaml

# dcoker-compose up -d

version: '3'
services:
  phpldapadmin:
    image: osixia/phpldapadmin
    container_name: phpldapadmin252
    hostname: phpldapadmin
    restart: always
    ports:
      - "8001:80"
    environment:
      - PHPLDAPADMIN_HTTPS=false
      - PHPLDAPADMIN_LDAP_HOSTS=192.168.110.252

(5)登录验证

使用浏览器登录phpldapadmin
http://192.168.110.x:8081
页面输入管理员的DN和密码即可登录

4、测试OpenLDAP使用AD密码进行认证

创建一个测试用户导入文件testuser.ldif

[root@localhost ~]# vim testuser.ldif
写入以下内容
dn: uid=ruijie,ou=people,dc=huawang,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
uid: ruijie
cn: ruijie
sn: ruijie
userpassword: {SASL}ruijie
givenname: ruijie
mail: ruijie@huawang.com

dn: uid=jhqinzicheng,ou=people,dc=huawang,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
uid: jhqinzicheng
cn: jhqinzicheng
sn: jhqinzicheng
userpassword: {SASL}jhqinzicheng
givenname: jhqinzicheng
mail: jhqinzicheng@huawang.com

导入测试用户

[root@localhost ~]# ldapadd -x -D "cn=Manager,dc=huawang,dc=com" -W -f testuser.ldif
Enter LDAP Password: 
adding new entry "uid=ruijie,ou=people,dc=huawang,dc=com"

使用命令测试

[root@localhost ~]# ldapsearch -w ruijie -H ldap://127.0.0.1 -D "cn=ruijie,dc=huawang,dc=com" -b "dc=huawang,dc=com"

ldapwhoami -x -D uid=ruijie,ou=People,dc=test,dc=winad,dc=com -w a542129333A
dn:uid=ruijie,ou=People,dc=lework,dc=com

ldapsearch -w ruijie -H ldap://127.0.0.1 -D "uid=ruijie,ou=People,dc=test,dc=winad,dc=com" -b "uid=ruijie,ou=People,dc=test,dc=winad,dc=com" 

这个测试命令,testuser用户在openldap和Windows AD上都存在,IP是本机openldap的IP,DN,查询DN也都是openldap的信息,但是密码却是在windows AD上管理的。如成功,到windows AD上修改用户密码,用新密码验证,再等5分钟,旧密码失效。到此配置完成

文章来源:
https://blog.csdn.net/shion0305/article/details/114934202
https://lework.github.io/2019/07/25/openldap-pass-through-ad/