1. 先想清楚再动手:统一认证的选型逻辑与LDAP目录设计思路
1.1 办公环境里的账号爆炸问题
做运维的这些年,我见过太多这样的场景:公司里十几个内部系统,每个系统一套账号密码,运维、开发、财务、人事各管各的。新同事入职要挨个系统开户,离职时还得挨个系统注销,漏掉一个就是安全隐患。更要命的是,很多人为了省事,所有系统都用同一个密码,一旦某个系统的密码泄露,全部沦陷。
这个问题的根子不在执行力,而在架构。每个系统各自维护一套身份信息,根本没有统一的身份源。所以当我负责的那家公司的系统规模从四五个膨胀到十几个时,我决定上统一认证,把OpenLDAP作为后端身份源,所有业务系统都对接它,账号密码集中管理,权限入口统一收敛。
1.2 OpenLDAP、AD、其他方案怎么选
选型的时候我认真对比过几条路线。微软AD功能最全,域控、组策略、Kerberos一把梭,但它的授权费用和部署维护成本对一家中型公司来说不算轻。直接用各云厂商的目录服务也行,省心,但数据要放在别人手里,而且很多内网系统走云上目录需要额外打通网络,反而绕。
OpenLDAP的优点是开源、稳定、轻量,协议是标准的LDAP,几乎所有支持LDAP认证的系统都能无缝对接。缺点是它只解决目录存储和认证问题,不提供AD那种复杂的组策略,你需要自己规划目录结构、访问控制、密码策略。换句话说,AD是即装即用的全家桶,OpenLDAP是一套需要自己拧螺丝的框架,但拧好了非常顺手。
我的结论是:如果你的环境是Linux为主、业务系统以Web应用和服务器为主,OpenLDAP足够;如果你有大量Windows域控需求,那AD更合适。不用一步到位,先把身份源统一起来,比纠结某个功能是否齐全重要得多。
1.3 目录树长什么样:LDAP基础概念补课
LDAP和关系型数据库的思路完全不同。你没法用SQL去查它,它是一个树状的目录结构,每个条目都有一个唯一标识叫DN,比如cn=admin,dc=example,dc=com。DN的写法从右往左看,就是树从根到叶子的路径,dc=example,dc=com相当于树的根域,ou=People是一级分支,uid=zhangsan是具体的一张叶子。
刚开始接触的人最容易搞混的就是DN和相对名RDN。RDN只是当前层级的名字,比如uid=zhangsan,而DN必须是从根开始的完整路径。后面所有客户端接入和权限配置,都是在和DN打交道,理解树状结构是必须过的一关。
还有几个术语必须提前讲清楚:条目、对象类、属性、Schema。对象类决定了这个条目能有哪些属性,比如用户条目通常用inetOrgPerson,组条目用posixGroup。Schema就是对象类和属性的定义集合,后面添加用户时如果报"unknown object class",八成是缺了对应的Schema文件。
2. 环境准备与安装环节:从包管理器到slapd进程跑起来
2.1 操作系统选型和包安装
我部署的这台用的是Debian系系统,直接走apt安装,方便省事。如果你们是CentOS/RHEL系,包名略有差异,逻辑是一样的。这里给两份命令对照:
# Debian/Ubuntu apt update apt install -y slapd ldap-utils # CentOS/RHEL yum install -y openldap-servers openldap-clients安装过程中Debian系会弹出一个配置界面,问管理员密码和域名后缀,这个先随便填,后面全部要改。安装完成先别急着用,需要确认两个关键路径:配置目录/etc/ldap/slapd.d/和数据库目录/var/lib/ldap/。OpenLDAP新版用的是在线配置方式,配置本身也存成LDAP条目,而不是传统的slapd.conf文本。
2.2 初始化数据库与管理员密码
安装完直接启动的话,数据库是空的,什么都干不了。第一步要把cn=config这个配置库的权限改一下,因为默认只有root才能改配置,用LDAP客户端是连不上的:
# 生成管理员密码哈希,建议用slappasswd slappasswd -s yourpassword这条命令会输出一串类似{SSHA}xxxxxxx的哈希值,记住它。然后编辑方式取决于你的系统。如果是新版在线配置,可以直接创建一个初始化LDIF,导入到slapd里,但更简单的方法是先用slapd的初始数据库,然后用ldapmodify逐步改。我更喜欢直接重建一套干净的配置目录结构,用下面这种方式初始化数据库:
# 停止服务再初始化 systemctl stop slapd rm -rf /var/lib/ldap/* cp /etc/ldap/slapd.d/DB_CONFIG.example /var/lib/ldap/DB_CONFIG chown -R openldap:openldap /var/lib/ldap新版Debian安装后会自动生成一套默认数据库,域名是安装时填的那个,并不一定是你业务真正要用的。我建议干脆删掉重新初始化。初始化之后要修改数据库的管理员密码,有一个更标准的方法,创建init_admin.ldif文件:
dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcRootDN olcRootDN: cn=admin,dc=example,dc=com - replace: olcRootPW olcRootPW: {SSHA}你的哈希然后执行:
ldapmodify -Y EXTERNAL -H ldapi:/// -f init_admin.ldif-Y EXTERNAL是走Unix socket认证,相当于用root身份去改LDAP配置,不需要输管理员密码。这个技巧我用得很频繁,因为在线配置库的很多操作必须先通过它来授权。
2.3 验证服务是否正常
服务起来以后,先做一个最简单的匿名查询,看能不能返回根条目:
ldapsearch -x -H ldap://localhost -b dc=example,dc=com正常情况下会返回一个DN和若干dc属性。如果报错说No such object,说明数据库是空的,属正常,后面导入基础条目即可。如果报连接拒绝,先检查slapd进程和监听端口:
systemctl status slapd ss -lnpt | grep 389这里我要多说一句,刚安装完最容易踩的坑是防火墙没放行389端口,结果客户端那边反复报Connection refused。部署第一步就应该把防火墙规则加好,不然等你配完一堆东西再排查,很难定位是防火墙还是配置问题。
3. 目录结构落地:base.ldif、组织单元与第一批用户
3.1 设计目录命名空间,别怕改主意
很多人上手就直接dc=example,dc=com,然后开始加用户,结果发现公司组织架构调整后,整个目录树要重画,迁移成本极高。我建议在上线前花半个小时做一个简单的命名空间规划,想清楚三个问题:域名后缀用什么、组织单元分几层、用户和分组放哪里。
域名后缀最好用公司真实拥有的域名,比如dc=example,dc=com,这样以后做证书和服务命名都省事,浏览器、邮件系统对接也自然。组织单元我这里分成三个:ou=People存人、ou=Groups存组、ou=Services存业务绑定账号。不要一开始就按部门拆OU,部门变动频繁,而LDAP的OU一旦承载了ACL规则,迁移条目就得跟着改权限,代价很大。
3.2 手工打造base.ldif
基础目录结构用一个base.ldif文件搞定:
dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: Example Inc. dc: example dn: cn=admin,dc=example,dc=com objectClass: organizationalRole cn: admin description: LDAP Administrator dn: ou=People,dc=example,dc=com objectClass: organizationalUnit ou: People dn: ou=Groups,dc=example,dc=com objectClass: organizationalUnit ou: Groups dn: ou=Services,dc=example,dc=com objectClass: organizationalUnit ou: Services导入命令:
ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f base.ldif输入前面设置的管理员密码即可。这里有个容易漏的点:如果之前数据库是空的,导入base.ldif后根条目才创建出来。如果你前面验证匿名搜索时能看到根条目,说明系统初始化模板已经帮你建了域名,此时再导入会报"Already exists"。两种情况处理方法不同,报错时先ldapsearch看清楚现状,别盲目重复导入。
3.3 用户和用户组条目怎么写
在目录里创建一个用户,至少需要三类对象类:inetOrgPerson提供通用人员属性,posixAccount提供Linux用户所需的uid、gid、home目录、shell,shadowAccount提供密码过期策略。三个对象类组合在一起,才能既满足企业通讯录需求,又满足Linux服务器登录需求。下面是一个标准用户条目:
dn: uid=zhangsan,ou=People,dc=example,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount objectClass: top uid: zhangsan cn: Zhang San sn: San givenName: Zhang displayName: Zhang San mail: zhangsan@example.com uidNumber: 10001 gidNumber: 10001 homeDirectory: /home/zhangsan loginShell: /bin/bash userPassword: {SSHA}xxxxx shadowLastChange: 19000 shadowMin: 0 shadowMax: 99999 shadowWarning: 7注意,userPassword不能是明文,必须用slappasswd -s 密码生成的哈希。有人图省事直接把明文写进去,个别客户端也能认证,但明文在目录里裸奔,一旦目录数据导出或授权不当泄露,所有密码全暴露。后面排障章节我会专门讲密码哈希的问题。
分组条目用posixGroup,同时为了便于在业务系统里做成员展示,可以加groupOfNames:
dn: cn=devteam,ou=Groups,dc=example,dc=com objectClass: posixGroup objectClass: groupOfNames cn: devteam gidNumber: 10001 member: uid=zhangsan,ou=People,dc=example,dc=com member: uid=lisi,ou=People,dc=example,dc=commember属性用于跨系统识别组成员,gidNumber用于Linux权限模型。两者的主数据都是这个组条目,业务系统读取它就能知道谁属于哪个组,不需要每个系统再单独维护一份成员清单。
3.4 ACL访问控制的第一次配置
创建完目录后必须马上设置ACL,否则默认权限下所有条目对匿名用户都不可见。ACL是LDAP里最劝退新人的部分,但绕不开。它的顺序极其敏感,第一条匹配了就生效,后面的不继续匹配。我常用的配置思路是:先显式拒绝匿名用户看到别人的密码哈希,再允许所有人读普通属性,只给管理员写权限。
修改ACL需要在线配置库操作,比如在olcDatabase={1}mdb,cn=config上追加olcAccess条目:
dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcAccess olcAccess: to attrs=userPassword by self write by anonymous auth by dn="cn=admin,dc=example,dc=com" write by * none - add: olcAccess olcAccess: to * by self read by dn="cn=admin,dc=example,dc=com" write by users read by * none执行后验证一下:
ldapsearch -x -D "cn=admin,dc=example,dc=com" -W -b dc=example,dc=com ldapsearch -x -b dc=example,dc=com uid=zhangsan userPassword第二行匿名查询应当返回userPassword: <no values>,如果明文能看到,说明第一条ACL没生效,优先检查ACL顺序和数据库编号。
4. 安全加固不能省:TLS加密、绑定账号与密码策略
4.1 自建CA之下签发证书,启用TLS
LDAP默认走明文,389端口上用户名密码全裸奔。如果只在纯内网且网络隔离严格,勉强能接受;但只要跨网段甚至经过办公Wi-Fi,密码就有被截获的风险。我当时部署是直接启用TLS,用内部CA签发证书,步骤分四步:生成CA私钥和根证书、为LDAP服务器生成密钥和CSR、签发服务器证书、在slapd中配置证书路径。
如果是测试环境,用OpenSSL自签一张证书也能跑通,但生产环境我建议还是搞一个内部CA,后面每台客户端机器和Web应用都要信任CA根证书,一次性下发根证书比人人手动信任一张自签证书要规范得多。证书相关的主要操作:
# 生成服务器私钥和CSR openssl req -new -newkey rsa:2048 -nodes -keyout ldap.key -out ldap.csr -subj "/CN=ldap.example.com" # 用CA签发 openssl x509 -req -in ldap.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -out ldap.crt -days 365然后让slapd用上TLS,在cn=config里加配置:
dn: cn=config changetype: modify add: olcTLSCertificateFile olcTLSCertificateFile: /etc/ldap/ldap.crt - add: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/ldap/ldap.key - add: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/ldap/ca.crt修改后重启slapd,用ldapsearch -ZZ强制TLS连接测试。-ZZ表示如果服务器不支持TLS就直接失败,比-Z更严格。这里有个坑:证书CN必须与LDAP服务器访问域名一致,否则客户端会报域名不匹配,很多人图省事直接用IP访问,还嫌证书报错,其实是访问方式就错了。
4.2 给业务系统配专属绑定账号,别共享admin
我见过不少团队把cn=admin直接发给各个业务系统配置为绑定DN,这不合适。cn=admin是全目录的超级管理员,它的密码只要能验证LDAP绑定就相当于拿到了目录的最高权限,任何业务系统被攻破或者绑定配置泄露,整个LDAP目录就拱手让人了。
正确的做法是给每个业务系统建一个专属绑定账号,放在ou=Services下,权限只限于该系统需要的OU。比如给某个运维平台建cn=svc-ops,ou=Services,ACL限制它只能读ou=People下的部分属性和ou=Groups下的组信息。创建条目如下:
dn: cn=svc-ops,ou=Services,dc=example,dc=com objectClass: organizationalRole objectClass: simpleSecurityObject cn: svc-ops userPassword: {SSHA}xxx description: Ops Platform service account然后在ACL里给这个绑定账号放开相应读权限,再测试它确实只能看该看的东西。这个习惯我从那之后一直保持,好处是出问题时能通过日志精准定位到底是哪个系统在用目录,回收权限也只需要删一个条目。
4.3 用ppolicy实现锁定、过期与密码复杂度
基础版的LDAP密码管理能力很弱,默认根本没有"连续输错几次锁定"和"密码过期强制修改"的概念,而这些对于企业安全审计几乎是硬需求。解决办法是启用ppolicy覆盖层。先在配置中加载模块和覆盖层:
dn: cn=module,cn=config changetype: modify add: olcModuleLoad olcModuleLoad: ppolicy.la dn: olcOverlay=ppolicy,olcDatabase={1}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcPPolicyConfig olcOverlay: ppolicy olcPPolicyDefault: cn=defaultPolicy,ou=Policies,dc=example,dc=com然后创建默认策略条目:
dn: cn=defaultPolicy,ou=Policies,dc=example,dc=com objectClass: pwdPolicy objectClass: person cn: defaultPolicy sn: defaultPolicy pwdAttribute: userPassword pwdMaxFailure: 5 pwdLockout: TRUE pwdLockoutDuration: 600 pwdMaxAge: 7776000 pwdExpireWarning: 2592000 pwdMinLength: 8 pwdCheckQuality: 2这里的值单位是秒,pwdLockoutDuration: 600就是锁定10分钟,pwdMaxAge: 7776000是密码90天过期。启用后,当连续五次认证失败,账户会被锁定,这个功能在遇到暴力破解时特别有用。
5. 让认证真正跑起来:Linux 服务器 PAM/SSH 与 Web 系统对接
5.1 Linux服务器用nslcd桥接LDAP与PAM
让一台Linux服务器用LDAP账号登录,核心是把LDAP作为NSS(名称服务切换)的数据源之一,同时配置PAM模块处理认证。Debian系安装libpam-ldapd和libnss-ldapd时会弹出交互界面询问LDAP地址和基础DN,这里手写配置更可控。主配置在/etc/nslcd.conf:
uri ldap://ldap.example.com base dc=example,dc=com binddn cn=svc-nslcd,ou=Services,dc=example,dc=com bindpw 你的密码 filter passwd uid=* filter shadow uid=* scope sub tls_reqcert allow ssl start_tls这里用了一个专门的svc-nslcd绑定账号,而不是cn=admin。然后修改/etc/nsswitch.conf:
passwd: files ldap group: files ldap shadow: files ldap改完后验证NSS是否生效:
getent passwd zhangsan如果正常输出用户信息,说明NSS链路已经通了。此时再配置PAM认证,Debian系通常修改/etc/pam.d/common-auth,在认证链中插入pam_ldap.so,但不同版本差异较大,我建议使用pam-auth-update工具勾选LDAP选项,它自动生成的PAM配置比我手动改可靠得多。这里要记住一点:PAM的顺序很重要,先pam_unix.so再pam_ldap.so,保证本地账号优先、LDAP兜底。
5.2 SSH登录接入LDAP,从第一步到全流程
SSH登录Linux服务器走LDAP认证,其实就是把SSH的登录流程交给PAM处理。上面配置完成后,理论上就可以直接SSH登录了,但有一个常见问题:首次SSH登录时,家目录还没创建。普通Linux服务器不会因为你出现在LDAP里就自动帮你建家目录,需要启用pam_mkhomedir模块,把它加在/etc/pam.d/common-session的最后:
session optional pam_mkhomedir.so skel=/etc/skel umask=0022加完之后,新用户第一次SSH登录会自动创建/home/zhangsan并生成目录骨架。有人会问了,密码过期、锁定怎么在SSH登录时生效?这些逻辑由pam_ldap.so负责查询和判断,nslcd只是数值解析,真正的策略判断还是LDAP端做的,所以前面配置ppolicy是有意义的。
SSH这里还有一个容易踩的坑:sshd默认可能启用UseDNS yes,登录时会做反向DNS解析,LDAP用户如果域名解析慢,登录会明显发卡,几十秒的重灾区。建议在生产环境把UseDNS no加上,登录响应能快一个量级。
5.3 Web应用对接LDAP的通用模式
绝大多数业务系统对接LDAP认证时,做得其实是同一件事:用户提交用户名密码后,系统用这个DN去LDAP服务器做一次绑定认证,绑定成功即视为认证通过。所以你在Java应用里会看到InitialDirContext,在Python应用里会看到python-ldap的simple_bind_s,在nginx里可能看到auth_ldap模块,本质上都是绑定操作。
对接前先用ldapsearch模拟一遍,确认一下你手里那套账号密码确实能绑上:
ldapsearch -x -H ldap://ldap.example.com -D "uid=zhangsan,ou=People,dc=example,dc=com" -W -b "uid=zhangsan,ou=People,dc=example,dc=com" uid如果系统对接时要求配置用户搜索基础DN,通常填ou=People,dc=example,dc=com;要求过滤条件,通常填(&(objectClass=posixAccount)(uid={0}));要求组成员关系查询,可以从ou=Groups下读取member。掌握这个绑定+搜索的模式后,任何系统拿个LDAP对接文档你都能看懂它要你填什么。
6. 上线之后的运维功课:备份恢复、日志定位与性能索引
6.1 用slapcat做全量备份,别直接拷贝数据库文件
LDAP的数据备份最推荐slapcat导出LDIF文件,而不是停服务拷贝/var/lib/ldap/目录。原因有两点:一是热拷贝数据库目录很容易在服务运行时产生数据不一致,二是LDIF是文本,可以直接diff和部分还原。备份命令很简单:
slapcat -b dc=example,dc=com -l backup_$(date +%F).ldif恢复的时候,先停slapd,清空数据库目录,然后用slapadd导入,最后调整属主和启动服务:
systemctl stop slapd rm -rf /var/lib/ldap/* slapadd -l backup_20250101.ldif chown -R openldap:openldap /var/lib/ldap systemctl start slapd这里牢记一点:别恢复base.ldif,它只是初始化结构,直接恢复完整快照即可。备份策略上,我建议至少保留最近7天的全量备份,并定期做一次恢复演练。没验证过的备份等于没有备份,这话在LDAP这种核心身份源上应验得特别彻底。
6.2 日志怎么开,问题怎么查
slapd默认日志输出到系统日志,但你配完想追踪具体某次认证失败的原因时,默认的loglevel通常不够细。在cn=config里设置日志级别:
dn: cn=config changetype: modify replace: olcLogLevel olcLogLevel: stats syncstats级别会输出连接建立、绑定成功失败这类摘要,一般够用;再往上就是acl、filter甚至trace级别,能输出ACL匹配细节和过滤表达式解析过程,但日志量巨大,排障完记得调回来。实际排查认证失败时,用journalctl -u slapd -f实时看日志,重点找"invalid credentials"和"No such object"这两类关键字。
invalid credentials表示绑定认证被拒绝,要么密码不对,要么账户被锁定;No such object表示要绑定的DN路径不存在,多半是用户搜索基础DN配错了。我看过很多人在Web应用里报认证失败,跑到LDAP服务端一看日志,问题是应用把用户DN的ou=People写成了ou=user,这种一眼就能定位的错,就是靠日志对比才发现的。
6.3 索引设置与性能优化
LDAP数据量规模上来之后,搜索性能会明显下滑。索引的作用相当于数据库的索引,没有索引的搜索会全表扫描。默认OpenLDAP只给uid等少量属性建了索引,如果Web应用频繁按mail、member、cn搜索,建议手动补索引:
dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: uid pres,eq,sub - add: olcDbIndex olcDbIndex: cn pres,eq,sub - add: olcDbIndex olcDbIndex: mail pres,eq,sub - add: olcDbIndex olcDbIndex: member eq性能还有一个容易被忽视的瓶颈:客户端连接数。slapd默认的线程数和连接数上限不高,当十几套业务系统同时连接时,可能会遇到连接被拒绝。调高olcThreads和数据库的olcConnMaxPending等参数,需要根据实际并发量来定,别乱调,先用ss -s观察当前连接情况再决定。另一个大坑是客户端侧的连接池,很多Web应用的LDAP客户端没有正确复用连接,每次都新建连接,造成LDAP服务端大量TIME_WAIT,这种情况下服务端参数再大也扛不住,得从应用侧改。
7. 真实环境里最容易踩的坑:部署与对接的排障清单
7.1 ACL顺序问题:第一条匹配就生效
ACL顺序问题我反复踩过,必须单独拿出来说。OpenLDAP的ACL规则从上到下逐条匹配,第一条匹配后就不再往下执行,所以如果你把一条宽泛的to * by users read写在前面,后面加的任何对userPassword的限制都不会生效,因为宽泛规则已经先行匹配并放行了。
我遇到过的情况是:明明配置了to attrs=userPassword by anonymous auth,但匿名用户依然能读到哈希。查了很久才发现,系统初始化模板里已经有一条默认的to * by * read放在前面,我的新规则追加在它后面,根本轮不到执行。解决办法是用ldapmodify把olcAccess整个替换成你想要的完整规则集,而不是add,并且在规则里显式把所有场景都覆盖掉。
7.2 密码哈希与明文问题
很多从传统Unix转过来的管理员以为LDAP的userPassword存的是和/etc/shadow一样的哈希,错。OpenLDAP有自己的密码存储格式,常见的有{SSHA}、{SHA}、{CRYPT}等。导入用户条目时如果你用明文密码,服务端不一定给你自动转换为哈希,认证时还能工作,但安全性极差。
建议用slappasswd生成哈希后填入LDIF。另外还要注意,某些Web应用对接LDAP做密码修改时,会直接把应用里用户输入的明文密码通过modify操作写进userPassword,这会把服务端好不容易建立的密码哈希机制绕过去,变成明文存储。对接上线前,务必用ldapsearch抽查几个用户的userPassword,确认是哈希格式再放行。
7.3 连接数瓶颈与客户端超时
我用过的几个业务系统在对接LDAP时都有过"偶发登录缓慢"的投诉。排查链路一般是:先看slapd日志有无超时,再看客户端的LDAP连接池配置,最后看网络和DNS。最常见的问题倒是出在客户端:有些框架默认LDAP连接超时是无限等待,LDAP服务端一旦不响应,应用线程就全部卡在认证上,最终拖垮整个服务。
对接时一定要要求业务方设置合理的连接超时和读取超时,Java里是com.sun.jndi.ldap.connect.timeout和com.sun.jndi.ldap.read.timeout,Python的ldap3有connect_timeout参数。我的建议是:连接超时3秒,读取超时5秒,失败后快速降级,不要再把请求打进LDAP,避免雪崩。
7.4 客户端信任与StartTLS的方向误区
用TLS对接时,客户端必须信任LDAP服务器的CA根证书,这个动作漏掉后,很多系统会报"SSL Peer certificate verification failed"或"TLS certificate is not trusted"。遇到这种报错,先检查根证书是否放在客户端的CA信任库,常见路径是/etc/ssl/certs/ca-certificates.crt(Debian系)或应用自带的truststore,而不是急着在LDAP端改olcTLSCACertificateFile。
再一个细节是加密模式的区分:有的系统支持ldap://配合StartTLS,有的支持ldaps://(636端口直连TLS)。如果两边的模式不匹配,也是典型的"配置看着都对但就是连不上"。我倾向于统一使用ldaps://,因为连接建立即加密,逻辑更简单,不容易搞混。
7.5 时间校验与目录长期稳定
最后提醒一个不是LDAP本身却直接影响认证的环节:服务器时间同步。LDAP的密码策略、锁定时间都依赖本地时间,如果slapd所在机器时钟漂移严重,可能出现密码提前过期、锁定时间错乱这类让人摸不着头脑的问题。所以把NTP时钟同步配置好,比盯着LDAP配置还重要。我跑过的一台虚拟机,时钟快了十分钟,所有用户的密码策略全乱套,最后发现根源就是虚拟化平台的时间同步没开。
目录服务上线后还有一个常被忽略的点:定期做索引分析。LDAP数据量增长后,哪些属性因未建索引导致全表扫描,日志里其实会输出<= mdb_search: ... (db index missing)之类的提示,看到它就该补索引了,亡羊补牢不丢人。
这套部署流程走下来,我最大的体会是OpenLDAP本身不复杂,复杂的是它周边的目录结构设计、ACL权限模型、TLS安全体系和客户端对接规范。只要前期把命名空间和管理员权限设计清楚,中间每一步都验证通过再走下一步,这个统一认证底座能稳定运行很久,后续再加新系统,对接成本几乎可以忽略不计。