ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenLDAP 部署与 AD 认证整合:基于 back-ldap 的代理实践

OpenLDAP 部署与 AD 认证整合:基于 back-ldap 的代理实践 把 OpenLDAP 部署起来再让它接管 Windows AD 里的账号认证这件事听起来像是把两个目录服务硬拼在一起实际上它在企业内网里非常常见。很多遗留业务系统只认标准 LDAP 协议压根不支持 Kerberos也处理不了 AD 那套 SMB 风格的域控交互还有一些系统被隔离在独立网段只允许访问一个固定的 LDAP 入口。这时候用一台 OpenLDAP 做前端认证门面背后把绑定请求原样转发给 AD既能满足应用的协议要求又不用真的去改 AD 的架构更不用把域控端口暴露到业务区。这篇内容会从为什么这样设计开始把 OpenLDAP 的部署基线、back-ldap 代理层的完整配置、AD 侧的配合条件、逐条验证的顺序以及上线后才会暴露的那些麻烦一条条拆开讲清楚。适合已经接触过 LDAP 基础概念、需要把认证链路真正跑通的运维和中间件同学参考。1. 先想清楚一件事为什么不让应用直接连 AD在动手配 OpenLDAP 之前我见过太多团队上来就装包、改配置结果两周后卡在一个 DN 大小写或者 referral 上原地打转。这个章节先说清楚设计动机因为方案选型错了后面再怎么调参都是白搭。1.1 直连 AD 的三个现实障碍第一个障碍是协议能力不匹配。AD 对外的 LDAP 接口虽然兼容 RFC 4511但它在几个地方做了自己的实现DN 是大小写不敏感的、属性名有大量变体sAMAccountName、userPrincipalName、displayName、搜索结果默认返回 referral 而很多老客户端不懂跟、超过一千条结果必须用分页控制否则直接截断。一个用 Java 的 JNDI 或者老 PHP 的ldap_*函数写出来的系统往往处理不了这些。第二个障碍是网络分区。域控一般放在核心管理区业务区到域控的 389/636 通常是要单独开策略的。如果每个业务系统都单独申请一条到域控的通道安全团队会疯掉——审计面太大、爆炸半径不可控。而在一台 OpenLDAP 上收口只需要业务区到这一台的访问策略域控那边只需要放行这一台链路清晰得多。第三个障碍是账号口径。有些系统需要读一份应用专用的目录数据字段结构和 AD 的原始 schema 对不上。如果直连 AD就得让应用自己去拼 filter 和映射字段有了中间的 OpenLDAP可以在代理层把属性做一次重写或者只暴露一部分子树应用侧配置就干净了。1.2 OpenLDAP 在这一层到底扮演什么角色很多人误以为 OpenLDAP 在这里是同步一份账号数据过来。这是最常见的方向性错误。如果只做同步syncrepl 或者导出导入你拿到的是属性数据拿不到密码——AD 的unicodePwd是加密存储的永远不会通过 LDAP 明文返回。也就是说同步方案只能做查询和展示做不了认证。所以正确姿势是让 OpenLDAP 做认证代理客户端把 DN 和密码交给 OpenLDAPOpenLDAP 用同一套凭证去 AD 上再绑定一次绑定成功就说明密码对绑定失败就把 AD 的错误码原样或转换后返回。密码从头到尾没有在 OpenLDAP 侧落过盘这也是它比同步方案更安全的地方。OpenLDAP 在这个架构里承担三件事协议适配把老应用的各种奇怪查询翻译成 AD 能接受的形式、拓扑收敛只暴露一个入口隐藏域控清单、访问控制在代理数据库上挂 ACL控制谁能查什么。1.3 四种整合路径的取舍对比网上关于OpenLDAP 整合 AD的资料很杂容易把人带偏。我把常见路线列个表你对照自己的场景选方案认证能力实现复杂度主要限制back-ldap 代理直通支持中需要服务账号AD 侧要放行syncrepl 同步账号不支持低拿不到密码只能查询saslauthd 转发认证支持中高只在 SASL 绑定路径生效配置分散客户端侧 SSSD 直连支持低绕过了 OpenLDAP不符合本文目标这里要重点说一句back-ldap 和 saslauthd 的区别不在于能不能认证而在于认证发生在哪一层。saslauthd 是把用户名密码交给一个外部守护进程去 AD 校验OpenLDAP 自己并不知道这次绑定意味着什么而 back-ldap 是在 LDAP 协议内部完成重绑定错误码、SASL 机制、控制字都能透传行为更接近真正的目录。代价是配置量更大需要对 AD 的行为有预期。考虑到本文标题明确指向部署并整合 AD 认证后面的内容以 back-ldap 为主线saslauthd 只在对比和排错时提一下。2. OpenLDAP 服务端的落地从安装到 cnconfig 基线代理层能不能稳取决于底座搭得好不好。这个章节把安装、后缀设计、配置基线和几个容易被忽略的开关讲透。2.1 安装方式与版本选择我个人的建议是能用发行版仓库就用仓库能用 2.5 就别停在 2.4。原因很实际。OpenLDAP 2.4 的 back-ldap 在连接池和超时处理上有几个已知的边界问题尤其是当 AD 那边做负载均衡多个 DC 轮询时2.4 偶尔会出现连接复用后身份错乱的现象——表现为 A 用户的查询偶尔返回 B 用户能看到的字段。2.5 对olcDbRebindAsUser的处理明显更严谨。Ubuntu 22.04 / 24.04 自带的是 2.5.xDebian 12 也是 2.5RHEL 9 系则是 2.6。直接用# Debian / Ubuntu apt-get update DEBIAN_FRONTENDnoninteractive apt-get install -y slapd ldap-utils libsasl2-modules-gssapi-mit # RHEL / Rocky dnf install -y openldap-servers openldap-clients装完先别急着改配置确认服务在跑、slapd -VV输出的版本和模块路径符合预期。模块路径这个细节很重要后面加载back_ldap.la时要写对位置不同发行版差异挺大Debian 系在/usr/lib/ldap/RHEL 系在/usr/lib64/openldap/。注意不要把 OpenLDAP 装在一台同时跑 AD 域控角色的机器上。角色冲突不是理论风险端口和 schema 都会打架。2.2 目录后缀与 schema 设计这里有个决定后面所有配置走向的选择OpenLDAP 的 suffix 要不要和 AD 的域名一致。两种做法一致OpenLDAP 的olcSuffix直接写成dccorp,dclocal和 AD 的域名完全相同。优点是不需要做 DN 重写配置最简单客户端看到的 DN 和 AD 里的完全一致。缺点是语义上这台 OpenLDAP 就冒充了域控的身份容易让后续维护的人困惑也可能和 AD 端的某些引用产生歧义。不一致OpenLDAP 用dcexample,dccom之类独立后缀靠suffixmassage做映射。优点边界清楚缺点是每个 DN 都要过一次重写规则属性里的 DN 引用也要处理。我的经验是如果没有特殊要求选一致。重写规则看起来优雅实际维护起来是坑——AD 里一个组的member属性返回的是 AD 域名的 DN你不做属性重写就会露馅做了属性重写又是另一堆配置。省下来的时间够你多测两轮。schema 方面代理数据库本身不需要导入inetOrgPerson那一堆因为你不会在本地存用户。但如果你打算在同一个 slapd 实例上再挂一些本地数据比如应用配置、服务注册那就要正常引入core、cosine、nis、inetorgperson。2.3 用 cnconfig 建立可维护的基线配置slapd.conf已经是过去式了。所有新配置都走cnconfig用ldapmodify下发。下面是我常用的一套基线假设你的 OpenLDAP 管理 DN 是cnadmin,dccorp,dclocaldn: cnconfig changetype: modify replace: olcLogLevel olcLogLevel: stats - replace: olcToolThreads olcToolThreads: 2 - replace: olcThreads olcThreads: 16几个值的说明olcThreads我一般给到 CPU 核数的两倍因为 back-ldap 的瓶颈在等 AD 响应线程多一点能扛住并发olcToolThreads保持默认或者 2 就行它是给slapadd这类工具用的olcLogLevel联调期用stats或者-1全开稳定性上线之后一定要降回来日志会把磁盘吃干。然后是索引。代理数据库本地不存数据但有一个例外如果你配了olcDbCacheFree或者用了连接池本地会有一些会话状态。这部分不需要建索引所以代理数据库上可以完全不写olcDbIndex。这一点经常被误解很多模板无脑塞一堆olcDbIndex: objectClass eq对代理数据库毫无意义。2.4 TLS、日志与索引这三件事别省服务端的 TLS 分两块要分清楚入站 TLS客户端连 OpenLDAP由olcTLSCertificateFile、olcTLSCertificateKeyFile、olcTLSCACertificateFile控制。这个必须配否则客户端密码是明文传的。出站 TLSOpenLDAP 连 AD由 libldap 的配置文件控制也就是/etc/ldap/ldap.conf。back-ldap出站连接走的是这套配置不是cnconfig。这个区别我第一次踩的时候找了半天非常反直觉。出站配置大致长这样# /etc/ldap/ldap.conf TLS_CACERT /etc/ldap/certs/ad-ca.crt TLS_REQCERT demand TLS_CIPHER_SUITE HIGH:!aNULL:!MD5TLS_REQCERT demand表示严格校验证书。有人为了图省事写成never这在测试环境无所谓生产环境等于把中间人攻击的门敞开别这么干。日志级别我建议联调期先开stats需要看详细握手过程时再叠加packets和args。-1全开只在定位疑难杂症时短时间用跑完立刻改回来。3. back-ldap 代理层把绑定请求原样送进 AD这一章是全文的核心也是最容易配错的地方。我会把每一行的作用讲清楚而不是丢一段配置让你抄。3.1 模块加载与数据库实例的创建第一步是让 slapd 有能力加载back_ldap这个后端dn: cnmodule{0},cnconfig changetype: modify add: olcModuleLoad olcModuleLoad: back_ldap.laback_ldap.la这个文件名要和你系统里的实际文件对上。如果olcModuleLoad指令写错了名字slapd 重启时不会报致命错误只是在日志里留一行 warning然后你后面配的 ldap 数据库全都加载不了——这是最隐蔽的一类失败建议加完之后立刻重启并grep日志确认。接着创建代理数据库实例dn: olcDatabase{-1}ldap,cnconfig changetype: add objectClass: olcDatabaseConfig objectClass: olcLDAPConfig olcDatabase: {-1}ldap olcSuffix: dccorp,dclocal olcDbURI: ldaps://dc01.corp.local:636 olcDbRebindAsUser: TRUE olcDbChaseReferrals: TRUE olcDbProtocolVersion: 3 olcDbTimeout: 15 olcDbNetworkTimeout: 15{-1}表示这个数据库的加载顺序是最后。这一点很关键代理数据库必须放在所有本地数据库之后因为 slapd 是按顺序匹配 suffix 的。如果本地已经有一个dccorp,dclocal的 mdb 数据库代理根本不会被命中表现就是查询返回空但没报错非常难查。3.2 olcDbURI、rebindAsUser 与直通认证的关系olcDbURI写的是 AD 的地址。如果你有多个域控可以写多个 URI 用空格分隔back-ldap 会做简单轮询olcDbURI: ldaps://dc01.corp.local:636 ldaps://dc02.corp.local:636olcDbRebindAsUser: TRUE是整个方案的关键开关。它的语义是当连接池里的连接被交给另一个用户使用时必须用该用户的凭证重新绑定一次。不设这个值默认 FALSE在某些负载下会出现上一个用户的身份被下一个用户继承的问题权限串号。不过要提醒一句olcDbRebindAsUser: TRUE会显著增加 AD 侧的绑定次数。因为每次连接复用都要重绑AD 的 4769 事件日志会刷得很快。如果你的业务 QPS 很高需要评估域控能不能扛或者考虑在 OpenLDAP 侧做连接池优化。3.3 ID Assert 与服务账号的授权链只配olcDbURI和rebindAsUser还不够还有一个必须配的东西是服务账号。原因是 back-ldap 在执行搜索而不是绑定的时候需要以一个预先认证的身份连到 AD。用户的密码只在绑定那一刻用一次之后的搜索谁来查就是服务账号。olcDbIDAssertBind: bindmethodsimple binddnCNsvc-openldap,OUServiceAccounts,DCcorp,DClocal credentialsYourSecretHere olcDbIDAssertMode: noneolcDbIDAssertMode的三个取值要理解清楚none代理不声明自己的授权身份用服务账号做完搜索后直接返回不附加代理授权控制。AD 环境下推荐这个因为 AD 对 RFC 4370Proxy Authorization Control支持不完整强行用supported或required大概率报 Operations error。supported如果远程支持就带控制字。required必须带不带就失败。除了olcDbIDAssertBind还有一个olcDbACLBind用于处理 ACL 相关的身份。AD 场景下大部分时候不需要单独配但如果你的搜索出现insufficient access可以补上olcDbACLBind: bindmethodsimple binddnCNsvc-openldap,OUServiceAccounts,DCcorp,DClocal credentialsYourSecretHere注意服务账号的密码明文写在cnconfig里。一定要把/etc/ldap/slapd.d目录的权限收紧chown -R openldap:openldap且目录700否则同机器上的普通用户能直接读到 AD 服务账号密码。3.4 suffixmassage两边域名不一致时的映射如果你按 2.2 里说的选了后缀一致这一段可以跳过。但如果确实需要做映射规则是这样写的olcDbRewrite: suffixmassage dcexample,dccom dccorp,dclocal它的作用是客户端用dcexample,dccom的 DN 来查OpenLDAP 在转发给 AD 之前把后缀替换成dccorp,dclocal返回结果再替换回来。只有这一条是不够的。AD 返回的memberOf、member、manager、distinguishedName这些属性里都嵌着 DN你需要额外做属性值的重写olcDbRewrite: map attribute memberOf member olcDbRewrite: map attribute objectClass objectClass准确地说属性值重写要用olcDbRewrite的map指令配合正则写法复杂且容易出边界问题。我的建议还是尽量避免走这条路——省下的时间真的不如统一后缀。3.5 ACL 与只读保护代理数据库上的 ACL 决定谁能查什么。一个最小可用的配置olcAccess: {0}to attrsuserPassword by self write by anonymous auth by * none olcAccess: {1}to dn.subtreedccorp,dclocal by dn.exactcnadmin,dccorp,dclocal manage by users read by * noneto attrsuserPassword那条是必须的即使 OpenLDAP 不存密码绑定请求还是会带着密码字段进来这条 ACL 确保匿名用户只能用它做认证auth不能读出来。另外强烈建议给代理数据库加写保护。因为 back-ldap 默认会把写操作也转发给 AD一个配错了的应用ldapadd一下就能往 AD 里灌垃圾数据olcAccess: {2}to dn.subtreedccorp,dclocal by dn.exactcnadmin,dccorp,dclocal write by * none这样除了管理员其他身份都只能读。要开放写的话针对特定 OU 单独开口子。4. AD 侧必须配合的几件事代理配完了AD 那边不通照样白搭。这一章讲 AD 侧的几个前置条件都是不满足就完全跑不起来的硬要求。4.1 服务账号、委派与最小权限在 AD 里建一个专门的服务账号我习惯命名成svc-openldap放在独立的 OU 里。这个账号需要什么权限读取目标子树的权限。如果只是认证理论上只需要读取用户对象的最小权限集。但因为我们还要做搜索比如按sAMAccountName查用户 DN需要能遍历目标 OU。不需要域管理员权限。给 Domain Admin 是典型的过度授权一旦这台 OpenLDAP 被打穿攻击者直接拿到域控。委派一个只读权限就够。具体做法在目标 OU 上右键 → 委派控制 → 创建自定义任务 → 只勾读取所有用户信息和相关属性。或者更精细地用dsacls命令逐条给权限。一个常见的坑服务账号的密码如果设了下次登录必须改密码或者过了密码有效期代理会在某个时间点突然全军覆没。表现是所有搜索都报49 Invalid credentials。所以建账号时务必勾掉用户下次登录时必须更改密码并把密码设为永不过期或者纳入你的密码轮换流程。4.2 端口、LDAPS 与证书信任端口就两个选择端口协议说明389LDAP明文或 StartTLS 升级636LDAPS原生加密3268LDAP GC全局编录跨域搜索用3269LDAPS GC全局编录加密认证场景一律走 636。原因很直接简单绑定simple bind在 389 上密码是明文传输的中间任何一个环节都能抓走。AD 从某个版本开始对 389 上的简单绑定默认有告警甚至拒绝策略所以 LDAPS 是必须的。用 LDAPS 就要让 OpenLDAP 信任 AD 的证书。导出 AD 的根 CA 证书# 在域控上导出或者从证书服务下载 certutil -ca.cert ad-ca.crt把ad-ca.crt放到 OpenLDAP 服务器上然后在/etc/ldap/ldap.conf里指向它见 2.4。验证证书链openssl s_client -connect dc01.corp.local:636 -CAfile /etc/ldap/certs/ad-ca.crt -showcerts /dev/null如果这条命令报verify error不用急着继续先把证书链理顺。证书问题在 slapd 日志里表现得非常含糊经常只留一行TLS: could not initialize session很难定位。4.3 dSHeuristics 与匿名查询的取舍网上有些资料会教你改 AD 的dSHeuristics来允许匿名 LDAP 查询。我要明确说能不用就别用。匿名查询意味着任何人只要能连上 389 端口就能把域里的用户列表、组成员关系全部拉走。这是严重的目录信息泄露。正确做法是给 OpenLDAP 配一个已认证的服务账号所有搜索都以该账号身份执行。如果确实遇到某些必须匿名的场景比如老式设备只支持匿名也要把这个口子限制在一个专门的只读子树上绝不放在域根。具体实现是在 AD 侧建一个专门的 OU然后把匿名可读的权限只授予这个 OU其余一律拒绝。4.4 域控返回 referral 与全局编录AD 在多域环境下有个很烦的行为查询一个不存在的对象AD 会返回一个 referral 指向其他域或 GC。如果你的 OpenLDAP 没开olcDbChaseReferrals客户端会收到一个10 Referral错误很多应用处理不了直接报认证失败。开olcDbChaseReferrals: TRUE可以让 back-ldap 自动跟随引用。但要注意跟随引用意味着一次客户端请求可能变成多次跨域查询延迟会翻倍。在单域环境下这个问题不存在跨域场景要评估网络时延。另一个相关的坑是搜索基准。如果客户端拿dccorp,dclocal做基准去搜一个实际在子域里的用户AD 会返回 referral 或者干脆返回空。解决办法是在 AD 侧确认用户的真实 DN 位置或者干脆把olcDbURI指向全局编录3268/3269。全局编录包含整个森林的用户信息跨域查询时比单域控省心。5. 联调顺序从 ldapwhoami 到真实应用登录配完之后别急着接应用按下面的顺序一步步验证。每一步都确认通过再进下一步否则出错时你无法判断是哪一层的锅。5.1 先用 ldapsearch 验证搜索路径第一步验证的是服务账号能不能正常搜索ldapsearch -x -H ldaps://openldap.corp.local -D cnadmin,dccorp,dclocal -W \ -b dccorp,dclocal (sAMAccountNamezhangsan) dn cn mail memberOf这里用管理员 DN 绑定 OpenLDAP走的却是 back-ldap 的服务账号去 AD 查。如果返回了用户的dn、cn、memberOf说明搜索链路是通的。如果返回No such object (32)先检查 suffix 和 base 对不对如果返回Operations error (1)八成是 ID Assert 配置有问题回头看 3.3。5.2 用 ldapwhoami 验证绑定走向搜索通了不代表认证通了。第二步单独验证绑定ldapwhoami -x -H ldaps://openldap.corp.local -D CN张三,OUUsers,DCcorp,DClocal -W输入正确的密码如果返回dn:CN张三,OUUsers,DCcorp,DClocal说明绑定请求成功穿透到了 AD。再故意输错密码试一次确认返回的是49 Invalid credentials而不是其他错误码。这一步很重要——如果错误密码返回的是 1 或者 80说明 back-ldap 在处理绑定失败时出了别的问题直接上线会引发应用侧误判。5.3 打开合适日志级别看 rebind 过程如果前面两步都不顺打开日志看细节# 临时提升日志 ldapmodify -Y EXTERNAL -H ldapi:/// EOF dn: cnconfig changetype: modify replace: olcLogLevel olcLogLevel: stats packets args EOF # 观察日志 journalctl -u slapd -f日志里你会看到do_bind、ldap_back_dobind、send_ldap_result这类调用链。重点关注 BIND 请求的目标 DN 是不是被正确转换了suffixmassage 场景以及 AD 返回的 result code 是什么。看完记得把日志级别降回来ldapmodify -Y EXTERNAL -H ldapi:/// EOF dn: cnconfig changetype: modify replace: olcLogLevel olcLogLevel: stats EOF5.4 应用侧 PAM/NSS 接入如果 OpenLDAP 前面挂的是 Linux 主机用 PAM 登录还需要配nss-pam-ldapd或者sssd。这里有个容易翻车的点nss-pam-ldapd的默认行为是先匿名搜索再把 DN 拿去绑定而 OpenLDAP 的 ACL 如果不允许匿名搜索登录直接失败。在/etc/nslcd.conf里显式配置绑定账号uri ldaps://openldap.corp.local base dccorp,dclocal binddn cnsvc-nslcd,dccorp,dclocal bindpw YourSecret ssl on tls_reqcert demand或者更省事直接用 SSSD 的ldapprovider注意不是adprovider因为目标是 OpenLDAP 而不是 AD[domain/corp] id_provider ldap auth_provider ldap ldap_uri ldaps://openldap.corp.local ldap_search_base dccorp,dclocal ldap_default_bind_dn cnsvc-nslcd,dccorp,dclocal ldap_default_authtok YourSecret ldap_id_use_start_tls false6. 那些报错码背后的真实原因49/1/32 的排查链路前面配置都对了不代表运行中不出问题。这一章把我在现场踩过的几个典型错误码串成排查链路你可以直接当 checklist 用。6.1 49 的五种成因49 Invalid credentials是最高频的错误但成因不止一种用户密码确实错了。这是最正常的也是你想要的。用户的 DN 大小写不匹配。AD 对 DN 大小写不敏感但如果你在 OpenLDAP 侧做了 DN 规范化比如大小写转换传过去的 DN 可能变成一个不存在的对象。检查方式是看日志里实际发出的 bind DN。服务账号密码过期或者被改。表现是所有查询都失败不只是某个用户。域账号被锁定。AD 默认策略是连续 5 次错误密码锁定 30 分钟。如果你的 OpenLDAP 侧做了重试比如客户端重试了 3 次一次用户输错就可能导致账号锁定。AD 侧限制了这个客户端的简单绑定。有些域控策略会拒绝来自非域成员的简单绑定需要检查域控的Network security: Restrict NTLM之类的策略。排查手段在域控的事件查看器里找 4625登录失败和 4740账号锁定事件能看到是哪个账号、什么原因。6.2 1 Operations error 与 ID Assert 配置1 Operations error在 back-ldap 场景下的典型成因是 ID Assert 模式不匹配。前面提过AD 对 RFC 4370 支持不完整如果你把olcDbIDAssertMode设成了required每次搜索都会失败ldap_back_search: ldap_back_is_proxy_authz returned 1 send_ldap_result: err1解决办法就是把模式改成none。另一个成因是服务账号在目标 OU 上没有搜索权限AD 返回00000005: SecErr: DSID-031A1248之类的错误被 back-ldap 转成了1。这时候要去 AD 侧检查委派权限。6.3 32 与 34 的后缀问题32 No such object和34 Invalid DN syntax通常都是后缀或者 base 写错了。一个隐蔽的情形OpenLDAP 里有本地数据库的 suffix 是dccorp,dclocal代理数据库也配了同样的 suffix。这时候 slapd 会优先匹配先加载的 mdb 数据库代理永远不会被命中返回32。检查方式是slapcat -n 0 | grep -A3 olcDatabase看看加载顺序确认代理数据库确实在最后。如果是{0}mdb和{-1}ldap顺序就是对的了。6.4 10 Referral 与超时10 Referral前面说过靠olcDbChaseReferrals解决。但还有一个相关错误是52 Unavailable或者直接超时这通常意味着AD 那边的响应超过了olcDbTimeout默认 15 秒。如果你的域控负载很重或者查询的是大结果集15 秒不够用。可以适当调大olcDbTimeout: 30 olcDbNetworkTimeout: 30但不要把超时设得特别长因为 OpenLDAP 的线程是阻塞等 AD 响应的超时太长会导致线程池被打满整体不可用。我一般控制在 30 秒以内超过就说明该优化 AD 侧的查询了。7. 上线之后才暴露的问题配完、测完、上线故事还没结束。下面这三类问题都是上线一两周之后才冒出来的提前知道能少熬几个夜。7.1 域账号被锁死这是 back-ldap 方案里最容易造成生产事故的问题。典型场景是某个应用做登录校验时因为自身逻辑问题比如缓存失效后重试短时间内对同一个账号连续发起了十几次绑定请求。OpenLDAP 忠实地把每次都转发给 ADAD 一看连续 5 次密码错误直接把账号锁了。而 AD 的锁定策略是针对账号而不是来源 IP的也就是说这个账号在其他所有系统上也都登不上了——包括 Outlook、共享盘、域内单点登录。用户会疯狂打电话。防御手段有几个在 OpenLDAP 侧加绑定频率限制。可以用olcLimits对绑定操作做限速olcLimits: dn.exactcnadmin,dccorp,dclocal time.softunlimited time.hardunlimited size.softunlimited size.hardunlimited对普通用户段设更严的限制olcLimits: users time.soft100 time.hard200 size.soft500 size.hard1000在应用侧做失败重试抑制。密码错就是错不要重试。这一点需要和开发同学明确沟通。和 AD 管理员协调锁定策略。如果实在冲突可以把锁定阈值适当调高比如 10 次但这治标不治本。7.2 性能与缓存back-ldap 是同步阻塞的一个查询进来它开一路到 AD 的连接等结果。这意味着 OpenLDAP 的并发能力直接受制于 AD 的响应速度。如果你发现高峰期 OpenLDAP 响应慢先看 AD 那边的延迟。用ldapsearch直接在 OpenLDAP 服务器上打 AD测一次典型查询的耗时time ldapsearch -x -H ldaps://dc01.corp.local:636 \ -D CNsvc-openldap,OUServiceAccounts,DCcorp,DClocal -W \ -b dccorp,dclocal (sAMAccountNamezhangsan) dn如果单次查询就要几百毫秒那 OpenLDAP 的并发上限基本就是olcThreads / 0.3。这时候能做的优化提高olcThreads但要配合ulimit -n文件描述符限制一起调否则连接开不出来。在 OpenLDAP 前面加一层查询缓存。可以用memcached之类做应用侧的缓存因为目录数据的变更频率通常很低。把只读查询路由到全局编录。GC 的读性能通常比单域控好而且节省了跨域引用。7.3 变更管理最后一件事也是很多团队忽略的AD 侧的变更会直接影响 OpenLDAP 的行为。我遇到的真实案例AD 管理员做了一次域控加固把 LDAP 的简单绑定策略收紧了结果第二天 OpenLDAP 的所有认证全部失败。排查了两天才定位到是 AD 侧的策略变更。所以一定要做两件事监控双向可用性。不要只监控 OpenLDAP 进程活着要定期用真实账号做一次ldapwhoami探测失败报警。和 AD 团队建立变更通知机制。任何涉及 LDAP 策略、证书、密码策略的调整都要同步给 OpenLDAP 的负责人。一个简单的探测脚本可以这样写#!/bin/bash # check_ldap_ad_auth.sh RESULT$(ldapwhoami -x -H ldaps://openldap.corp.local \ -D CNprobe,OUServiceAccounts,DCcorp,DClocal \ -w $PROBE_PASSWORD 21) if [[ $RESULT ! dn:* ]]; then echo CRITICAL: LDAP-AD auth chain broken: $RESULT exit 2 fi echo OK: auth chain healthy exit 0挂到监控系统上每 5 分钟跑一次。这条探测链路一旦断问题往往比日志里看到的更严重。这套组合我在几个不同规模的域环境里都跑过从几百人到几万人的规模都稳定。经验是配置本身不难难的是两边团队的协调——AD 那边的人不理解 OpenLDAP 为什么要做代理OpenLDAP 这边的人不熟悉 AD 的策略边界。把第 4 章和第 7 章的内容提前和域管对齐一次能省下大量来回扯皮的时间。
返回列表