OpenLDAP监控

OpenLDAP 是一款开源的轻型目录访问协议(Lightweight Directory Access Protocol,LDAP)服务器软件。提供了一个可定制、可扩展的目录服务,用于存储和管理各种类型的信息,如用户账户、组织结构、配置信息等,这些信息以树形结构进行组织和存储,方便快速查询和检索。 许多企业将 OpenLDAP 用于集中管理用户账户和权限,用户在访问公司的各种系统和资源时,可以通过 OpenLDAP 进行统一的身份认证和授权,如登录企业邮箱、VPN、Gitlab、Jenkins等。 当然也可以家用,比如说现在过年人多,你可以弄个Linux虚拟机跑OpenLDAP,让NAS接入,好像也有点用。

本文不讲OpenLDAP本身的部署维护,因为相关资料很多了,内容主要为如何接入OpenLDAP监控。

事情的背景时这样的,我年中的时候入职了个初创公司,前阵子突然看到技术群里面有人反馈,OpenLDAP无法登录,会影响业务。情况紧急相关同事快速重启OpenLDAP容器服务解决了问题。这种状况在小公司很常见,可能原来没什么服务接入,或者维护这个的人员早就提桶跑路了,或者没什么外部影响,重启还真的可能是最快速有效的解决方式😂。

当天早上盲猜问题就是FD默认配置1024不够了,维护的服务够多的话,这种情况还是有不少的,历史原因导致,无可非议,也许当场只有5个人使用,公司只打算开2年关门呢?

人和程序有一个能跑就行,恰巧你到的时候,不能跑又想高枕无忧,怎么办呢?接入监控吧。Google里面输入OpenLDAP监控,中文有效资料少得可怜,又到了填补空白的时候了。

监控系统现在选Prometheus很常见,功能易用,社区活跃,个人觉得比好多年前省事多了。

直白点,方案选用的Prometheus + openldap_exporter[https://github.com/tomcz/openldap_exporter]。可惜的是这个仓库作者也归档不维护了,不过能用,有能力的Fork自己玩吧。

由于原来的OpenlLDAP是采用容器化方式部署的,接入监控有点麻烦,也是难点所在。容器仓库为:https://github.com/osixia/docker-openldap

1. 如何接入监控

建议自己线找个测试环境测试,进入容器后。

  • 载入监控模块模块
 1	root@xxxxxxx:/# ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=module{0},cn=config"
 2	SASL/EXTERNAL authentication started
 3	SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
 4	SASL SSF: 0
 5	# extended LDIF
 6	#
 7	# LDAPv3
 8	# base <cn=module{0},cn=config> with scope subtree
 9	# filter: (objectclass=*)
10	# requesting: ALL
11	#
12
13	# module{0}, config
14	dn: cn=module{0},cn=config
15	objectClass: olcModuleList
16	cn: module{0}
17	olcModulePath: /usr/lib/ldap
18	olcModuleLoad: {0}back_mdb
19	olcModuleLoad: {1}memberof
20	olcModuleLoad: {2}refint
21
22	# search result
23	search: 2
24	result: 0 Success
25
26	# numResponses: 2
27	# numEntries: 1
28	root@9e93cb7f031d:/# ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF
29	> dn: cn=module{0},cn=config
30	> changetype: modify
31	> add: olcModuleLoad
32	> olcModuleLoad: back_monitor
33	> EOF
34	SASL/EXTERNAL authentication started
35	SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
36	SASL SSF: 0
37	modifying entry "cn=module{0},cn=config"
38
39	root@9e93cb7f031d:/# ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=module{0},cn=config"
40	SASL/EXTERNAL authentication started
41	SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
42	SASL SSF: 0
43	# extended LDIF
44	#
45	# LDAPv3
46	# base <cn=module{0},cn=config> with scope subtree
47	# filter: (objectclass=*)
48	# requesting: ALL
49	#
50
51	# module{0}, config
52	dn: cn=module{0},cn=config
53	objectClass: olcModuleList
54	cn: module{0}
55	olcModulePath: /usr/lib/ldap
56	olcModuleLoad: {0}back_mdb
57	olcModuleLoad: {1}memberof
58	olcModuleLoad: {2}refint
59	olcModuleLoad: {3}back_monitor
60
61	# search result
62	search: 2
63	result: 0 Success
64
65	# numResponses: 2
66	# numEntries: 1

上面操作过程输出确认,监控模块已载入

  • 添加监控用户

密码部分我用xxx代替了,操作示例:

 1	root@4433d2af4a1d:/# slappasswd -s your_password
 2	{SSHA}xxx
 3
 4	ldapadd -Y EXTERNAL -H ldapi:/// <<EOF
 5	dn: cn=monitor,dc=example,dc=org
 6	objectClass: simpleSecurityObject
 7	objectClass: organizationalRole
 8	cn: monitor
 9	description: LDAP monitor
10	userPassword: {SSHA}xxx
11	EOF

第一次显示没有权限,-w admin意为使用管理原权限写入

 1	root@9e93cb7f031d:/# ldapadd -Y EXTERNAL -H ldapi:/// <<EOF
 2	> dn: cn=monitor,dc=example,dc=org
 3	> objectClass: simpleSecurityObject
 4	> objectClass: organizationalRole
 5	> cn: monitor
 6	> description: LDAP monitor
 7	> userPassword: {SSHA}3W8Q0HWiBVRyy2qX47qPVZQxQvZ3/R9+
 8	> EOF
 9	SASL/EXTERNAL authentication started
10	SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
11	SASL SSF: 0
12	adding new entry "cn=monitor,dc=example,dc=org"
13	ldap_add: Insufficient access (50)
14	        additional info: no write access to parent
15
16	root@9e93cb7f031d:/# ldapadd -x -D cn=admin,dc=example,dc=org -w 'admin' <<EOF
17	> dn: cn=monitor,dc=example,dc=org
18	> objectClass: simpleSecurityObject
19	> objectClass: organizationalRole
20	> cn: monitor
21	> description: LDAP monitor
22	> userPassword: {SSHA}xxx
23	> EOF
24	adding new entry "cn=monitor,dc=example,dc=org"
  • 验证新添加用户读取信息是否正常
1	root@9e93cb7f031d:/# ldapwhoami -x -D "cn=monitor,dc=example,dc=org" -w "your_password"
2	dn:cn=monitor,dc=example,dc=org

如上所示,查询到了结果,表明用户信息正常,密码填你上面设置的。

  • 添加监控数据库
1ldapadd -Y EXTERNAL -H ldapi:/// <<EOF
2dn: olcDatabase={2}Monitor,cn=config
3objectClass: olcDatabaseConfig
4objectClass: olcMonitorConfig
5olcDatabase: {2}Monitor
6olcAccess: {0}to dn.subtree="cn=Monitor" by dn.base="cn=monitor,dc=example,dc=org" read by * none
7EOF

如果数据库是存在的:

1ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF
2dn: olcDatabase={2}Monitor,cn=config
3changetype: modify
4replace: olcAccess
5olcAccess: {0}to dn.subtree="cn=Monitor" by dn.base="cn=monitor,dc=example,dc=org" read by * none
6EOF
 1	root@9e93cb7f031d:/# ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF
 2	dn: olcDatabase=Monitor,cn=config
 3	changetype: modify
 4	replace: olcAccess
 5	olcAccess: {0}to dn.subtree="cn=Monitor" by dn.base="cn=monitor,dc=example,dc=org" read by * none
 6	EOF
 7	SASL/EXTERNAL authentication started
 8	SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
 9	SASL SSF: 0
10	modifying entry "olcDatabase=Monitor,cn=config"
11	ldap_modify: No such object (32)
12	        matched DN: cn=config

上面显示不存在数据库时的报错,没有数据库直接修改肯定不行啦(存在:ldapmodify,不存在:ldapadd,合理没毛病)

看起来很简单是不是,倘若第一次接触理解,上面的语句什么意思都要理解半天,我就是看了很久官方文档 + AI辅助 + 动手实践。

2. 部署监控组件openldap_exporter

上述不是有个监控模块吗?怎么这里又有个监控组件。不一样,上面的是服务端,这个是客户端,用来读取上面监控模块的信息,再吐给Prometheus的,大概是这样的链路:

Prometheus <--- openldap_exporter监控组件 <--- OpenLDAP server的监控模块

这部分很简单没什么好说的。看操作:

 1    xxx@xxx: cat /etc/systemd/system/openldap_exporter.service
 2    [Unit]
 3    Description=OpenLDAP Exporter
 4    After=network.target
 5
 6    [Service]
 7    Type=simple
 8    ExecStart=/opt/openldap_exporter/openldap_exporter --promAddr ":8080" --interval "10s" --config /opt/openldap_exporter/config.yml
 9    Restart=on-failure
10
11    [Install]
12    WantedBy=multi-user.target
13
14    xxx@xxx:~$ cat /opt/openldap_exporter/config.yml
15    ---
16    ldapUser: "cn=monitor,dc=example,dc=org"
17    ldapPass: "your_password"

 如果监控组件 没有正确显示指标,就要耐心慢慢排查,先确认服务端没有问题,再查看服务端日志,甚至要读监控组件的源码,别问,我就是这样过来的。读者比我幸运,没有中文用户在我之前写这些,反正没搜到。

3. 接入Prometheus

简单示例如下:

1  - job_name: "openldap"
2    static_configs:
3      - targets: ["10.10.20.98:8080"]

懒得截图了。

4. 接入Grafana

监控面板还是很有用的,领导上级都很喜欢,你应该懂的。

很遗憾,目前社区没什么制作好的面板,我自己动手制作了一个。要的话,可以关注我微信公众号,我发给你,真关注真发。

示例图片见下面的压测。

5. 压测

上文提到初步判断的是FD数目没配置导致的问题,需要压测验证。

压测程序放出来:

 1
 2import ldap
 3import time
 4
 5def main():
 6    connections = []
 7    target_connection_count = 1023
 8    try:
 9        while len(connections) < target_connection_count:
10            try:
11                # 尝试连接到 localhost:389 上的 openldap 服务
12                conn = ldap.initialize("ldap://localhost:389")
13                conn.simple_bind_s("cn=admin,dc=example,dc=org", "admin")  # 请使用有效的管理员 DN 和密码
14                connections.append(conn)
15                result = conn.search_s("dc=example,dc=org", ldap.SCOPE_SUBTREE)
16                print(result)
17                time.sleep(0.5)
18            except ldap.LDAPError as e:
19                print(f"LDAP error occurred: {e}")
20                break
21        while True:
22            # 保持程序运行,以保持占用文件描述符
23            pass
24    except Exception as e:
25        print(f"An error occurred: {e}")
26    finally:
27        # 关闭所有创建的 LDAP 连接
28        for conn in connections:
29            try:
30                conn.unbind()
31            except ldap.LDAPError:
32                pass
33
34
35if __name__ == "__main__":
36    main()

sleep 控制连接建立的速度,可调整,或者去掉。注意,ldap包有几个系统依赖的,不然安装不上。

压测结果图:

openldap

最后修改于: Tuesday, February 4, 2025
欢迎关注微信公众号,留言交流。

相关文章: