使用 OpenLDAP 搭建轻量级的统一身份认证服务,可以为 Grafana、JupyterHub、Airflow 等应用提供集中式用户管理。

Docker 部署

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: '3.8'

services:
openldap:
image: osixia/openldap:1.5.0
restart: always
container_name: ldap
hostname: ldap.example.com
ports:
- "389:389" # LDAP
- "636:636" # LDAPS
environment:
# 组织信息
- LDAP_ORGANISATION=MyCompany
- LDAP_DOMAIN=example.com
# 管理员密码
- LDAP_ADMIN_PASSWORD=adminPassword
- LDAP_CONFIG_PASSWORD=configPassword
# 日志级别
- LDAP_LOG_LEVEL=256
volumes:
- ${PWD}/ldap:/var/lib/ldap
- ${PWD}/slapd.d:/etc/ldap/slapd.d

启动

1
2
3
4
docker-compose up -d

# 查看日志
docker logs ldap

目录结构

启动后会自动创建以下 DN 结构:

1
2
3
4
dc=example,dc=com
├── cn=admin (管理员)
├── ou=People (用户)
└── ou=Groups (组)

管理用户和组

使用 ldapadd 添加用户

创建 add-user.ldif

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建 Users OU
dn: ou=Users,dc=example,dc=com
objectClass: organizationalUnit
ou: Users

# 添加用户
dn: uid=john,ou=Users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: john
cn: John Doe
sn: Doe
mail: [email protected]
userPassword: {SSHA}xxxxx # 使用 slappasswd 生成
uidNumber: 10000
gidNumber: 10000
homeDirectory: /home/john
loginShell: /bin/bash

添加到 LDAP:

1
docker exec ldap ldapadd -x -D "cn=admin,dc=example,dc=com" -w adminPassword -f /tmp/add-user.ldif

使用 ldapmodify 修改用户

1
2
3
4
5
6
7
# 修改用户信息
ldapmodify -x -D "cn=admin,dc=example,dc=com" -w adminPassword <<EOF
dn: uid=john,ou=Users,dc=example,dc=com
changetype: modify
replace: mail
mail: [email protected]
EOF

生成密码

1
2
docker exec ldap slappasswd
# 输入密码后会生成加密字符串

添加组

add-group.ldif

1
2
3
4
5
6
7
8
9
10
# 创建 Groups OU
dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups

# 添加管理员组
dn: cn=admins,ou=Groups,dc=example,dc=com
objectClass: groupOfUniqueNames
cn: admins
uniqueMember: uid=john,ou=Users,dc=example,dc=com

常用 LDAP 命令

搜索用户

1
2
3
4
5
6
7
8
9
# 搜索所有用户
ldapsearch -x -H ldap://localhost:389 \
-D "cn=admin,dc=example,dc=com" -w adminPassword \
-b "dc=example,dc=com" "(objectClass=person)"

# 搜索特定用户
ldapsearch -x -H ldap://localhost:389 \
-D "cn=admin,dc=example,dc=com" -w adminPassword \
-b "dc=example,dc=com" "(uid=john)"

测试用户认证

1
2
ldapwhoami -x -H ldap://localhost:389 \
-D "uid=john,ou=Users,dc=example,dc=com" -w userPassword

删除用户

1
2
ldapdelete -x -D "cn=admin,dc=example,dc=com" -w adminPassword \
"uid=john,ou=Users,dc=example,dc=com"

图形化管理工具

phpLDAPadmin

添加到 docker-compose.yml

1
2
3
4
5
6
7
8
9
10
phpldapadmin:
image: osixia/phpldapadmin:latest
container_name: phpldapadmin
ports:
- "8080:80"
environment:
- PHPLDAPADMIN_LDAP_HOSTS=ldap
- PHPLDAPADMIN_HTTPS=false
depends_on:
- openldap

访问:http://localhost:8080

Apache Directory Studio

桌面客户端,功能更强大:

  1. 下载:https://directory.apache.org/studio/
  2. 新建连接:
    • Hostname: localhost
    • Port: 389
    • Bind DN: cn=admin,dc=example,dc=com
    • Bind Password: adminPassword

应用集成示例

Grafana 集成

grafana.ini

1
2
3
[auth.ldap]
enabled = true
config_file = /etc/grafana/ldap.toml

ldap.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[[servers]]
host = "ldap.example.com"
port = 389
use_ssl = false
bind_dn = "cn=admin,dc=example,dc=com"
bind_password = "adminPassword"
search_filter = "(uid=%s)"
search_base_dns = ["ou=Users,dc=example,dc=com"]

[servers.attributes]
name = "cn"
surname = "sn"
username = "uid"
member_of = "memberOf"
email = "mail"

JupyterHub 集成

1
2
3
4
c.LDAPAuthenticator.server_address = 'ldap.example.com'
c.LDAPAuthenticator.bind_dn_template = [
'uid={username},ou=Users,dc=example,dc=com'
]

备份和恢复

备份

1
docker exec ldap slapcat -v -l backup.ldif

恢复

1
2
3
4
5
6
7
8
9
# 停止服务
docker-compose down

# 恢复数据
docker run --rm -v ${PWD}/ldap:/var/lib/ldap \
osixia/openldap:1.5.0 slapadd -l backup.ldif

# 启动服务
docker-compose up -d

注意事项

  • 生产环境建议启用 LDAPS(636 端口)
  • 定期备份 LDAP 数据和配置
  • 密码使用 slappasswd 生成加密格式
  • uidNumbergidNumber 需要唯一
  • 建议为不同应用创建独立的 OU

参考资料