lldap 0.6.3 配置参数详解
逐项解析 lldap 0.6.3 配置参数:二进制 + systemd 形态的参数查看与修改方式、参数总览与核心参数分类详解(端口/Base DN/key_seed/jwt_secret 等)、用户/组管理实操回显(JWT 携带组鉴权)、生产配置模板与常见问题,全部命令与回显实测照抄。
lldap 0.6.3 配置参数详解
目标:以真实服务器形态(二进制 + systemd 托管)逐节实测 lldap 0.6.3 主配置文件
/etc/lldap/lldap_config.toml的全部核心参数,并给出用户/组管理的实操回显。 实测声明:本文全部命令与回显均来自 2026-10-19 的真实环境操作,逐字照抄。环境变量注入形态见《lldap Docker Compose 部署指南》;本文之外的前置安装细节以官方文档为准。
一、环境信息
- 操作系统:Ubuntu 24.04 LTS(x86_64),主机名
lldap-server - 软件版本:lldap 0.6.3(官方预编译二进制
amd64-lldap.tar.gz,sha256e80b50ef39be61de9f1d75182b1e1fa5d82c672261c7e34fd8ffec5455ed3883) - 落位路径:
- 二进制:
/opt/lldap/lldap(附带/opt/lldap/lldap_set_password、/opt/lldap/lldap_migration_tool、/opt/lldap/app/Web 资源) - 配置:
/etc/lldap/lldap_config.toml(属主root:lldap,权限 640) - 数据:
/var/lib/lldap/(SQLite 主库users.db) - 服务账号:系统用户
lldap(/usr/sbin/nologin)
- 二进制:
- 服务托管:systemd 单元
lldap.service - 监听端口:LDAP
3890、Web/API17170 - 示例账号:管理员
admin/q1w2e3r4,普通用户jsmith/q1w2e3r4(测试环境值) - 版本与子命令确认(实测回显):
# /opt/lldap/lldap --version
lldap 0.6.3
# /opt/lldap/lldap --help
lldap is a lightweight LDAP server
Usage: lldap <COMMAND>
Commands:
export_graphql_schema Export the GraphQL schema to *.graphql
run Run the LDAP and GraphQL server
healthcheck Test whether the LDAP and GraphQL server are responsive
send_test_email Send a test email
create_schema Create database schema
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
二、前置条件
lldap 以专用系统账号运行,先完成账号、目录与配置文件落位(实测回显):
# useradd --system --home-dir /var/lib/lldap --shell /usr/sbin/nologin lldap
# mkdir -p /etc/lldap /var/lib/lldap
# chown -R lldap:lldap /var/lib/lldap
写入本文实测使用的 /etc/lldap/lldap_config.toml(完整内容见第七章生产模板;参数逐项解析见第五章),并收紧权限(内含管理口令与密钥):
# chown root:lldap /etc/lldap/lldap_config.toml && chmod 640 /etc/lldap/lldap_config.toml
# ls -la /etc/lldap/
total 12
drwxr-xr-x 2 root lldap 4096 Oct 19 05:12 .
drwxr-xr-x 1 root root 4096 Oct 19 05:12 ..
-rw-r----- 1 root lldap 1146 Oct 19 05:12 lldap_config.toml
systemd 单元 /etc/systemd/system/lldap.service:
[Unit]
Description=lldap - Light LDAP implementation for authentication
Documentation=https://github.com/lldap/lldap
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/lldap
User=lldap
Group=lldap
ExecStart=/opt/lldap/lldap run --config-file /etc/lldap/lldap_config.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
WorkingDirectory 不可省:Web 资源默认按工作目录下的
./app查找,缺失时服务能启动但 Web UI 资源加载失败,日志出现Cannot find ./app, please ensure that assets_path is set correctly(完整排障过程见《lldap 日常运维手册》8.2 节)。
启用并启动(实测回显):
# systemctl daemon-reload
# systemctl enable --now lldap
Synchronizing state of lldap.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing /usr/lib/systemd/systemd-sysv-install enable lldap
Created symlink /etc/systemd/system/multi-user.target.wants/lldap.service → /usr/lib/systemd/system/lldap.service.
# systemctl is-active lldap
active
三、参数查看与修改方式
lldap 参数有三个来源,优先级从高到低:环境变量(LLDAP_ 前缀)> 配置文件 > 内置默认值。
| 方式 | 适用场景 | 示例 |
|---|---|---|
配置文件 /etc/lldap/lldap_config.toml | 常规生产形态,参数集中可审计 | ldap_port = 3890 |
| 命令行参数 | 临时覆盖/测试,粒度最细 | lldap run --ldap-port 3891 |
环境变量(LLDAP_*) | 密钥类注入、编排系统交付 | LLDAP_JWT_SECRET=... |
运行时查看实际配置的三个途径:
- 启动日志回显:服务启动时以 DEBUG/INFO 打印生效配置摘要(
verbose = true时输出全量配置,含Config file path: ...与各段取值); /etc/lldap/lldap_config.toml直接读取(属主root:lldap,普通用户无权读);- 默认模板对照:官方配置模板内置在发布产物中,逐项注释完备(第七章模板即以此为基础)。
修改后的生效方式统一为重启服务:
# systemctl restart lldap
配置错误会在启动日志中直接暴露(如 5.3 节 jwt_secret 缺失即拒绝启动),不会"带病运行"。
四、参数总览
lldap_config.toml 顶层参数速查(v0.6.3,默认值来自官方模板):
| 参数 | 类型/默认值 | 作用 |
|---|---|---|
verbose | false | DEBUG 级日志开关 |
ldap_host | "0.0.0.0" | LDAP 监听地址 |
ldap_port | 3890 | LDAP 监听端口 |
http_host | "0.0.0.0" | HTTP(Web/API) 监听地址 |
http_port | 17170 | HTTP(Web/API) 监听端口 |
http_url | "http://localhost" | 对外访问 URL,用于密码重置邮件中的链接 |
jwt_secret | 无默认(必填) | JWT 签名密钥 |
ldap_base_dn | "dc=example,dc=com" | 目录树根 |
ldap_user_dn | "admin" | 管理员用户 ID |
ldap_user_email | "admin@localhost" | 管理员邮箱 |
ldap_user_pass | 无默认(必填) | 初始管理员口令 |
database_url | "sqlite://users.db?mode=rwc" | 数据库连接串 |
key_seed / key_file | "RanD0m STR1ng" / private_key | 服务端密钥(种子派生或文件加载,二选一) |
force_ldap_user_pass_reset | false | 用配置值强制重置管理员口令(一次性) |
force_update_private_key | false | 服务端密钥更换后强制刷新 |
[smtp_options] | 全部注释 | 密码找回邮件(见 5.6) |
[ldaps_options] | enabled=false | LDAPS 监听(见 5.7) |
[healthcheck_options] | localhost | 内置健康检查目标地址(见 5.7) |
五、核心参数分类详解
5.1 服务监听参数(ldap_host/ldap_port/http_host/http_port/http_url)
实测环境取值:
ldap_host = "0.0.0.0"
ldap_port = 3890
http_host = "0.0.0.0"
http_port = 17170
http_url = "http://192.168.146.128:17170"
启动后实测监听状态:
# ss -ltn | grep -E ':3890|:17170'
LISTEN 0 2048 0.0.0.0:3890 0.0.0.0:*
LISTEN 0 2048 0.0.0.0:17170 0.0.0.0:*
要点:
ldap_port改动后所有下游应用(《Authelia 4.39 介绍与选型指南》《Authentik 介绍与选型指南》、Nextcloud 等)需同步修改 LDAP 地址;非特权端口需注意lldap以lldap用户运行,绑 389/636 特权端口要给 systemd 单元加AmbientCapabilities=CAP_NET_BIND_SERVICE;http_url是密码重置邮件链接的地址来源,必须填用户浏览器可达的地址。实测将其设为http://192.168.146.128:17170后,找回邮件中的重置链接形如http://192.168.146.128:17170/reset-password/step2/<token>(完整邮件见 5.6);- HTTP 端口不提供原生 HTTPS(官方架构文档明确),TLS 由前置反向代理承担;LDAPS 由
[ldaps_options]单独开启。
5.2 base_dn 与目录结构(ldap_base_dn)
ldap_base_dn = "dc=example,dc=com"
lldap 的目录树结构是固定的:base_dn 之下,用户固定挂在 OU=people,组固定挂在 OU=groups(从条目 DN 路径即可验证;base_dn 本身与两个 OU 不作为独立条目返回)。实测全量导出(6 条目:2 用户 + 4 组):
# ldapsearch -x -H ldap://127.0.0.1:3890 -D "cn=admin,ou=people,dc=example,dc=com" -w q1w2e3r4 -b "dc=example,dc=com" "(objectClass=*)"
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (objectClass=*)
# requesting: ALL
#
# admin, people, example.com
dn: uid=admin,ou=people,dc=example,dc=com
cn: Administrator
createtimestamp: 20261019051213Z
entryuuid: de0245fe-3501-3e99-9f6e-9a066308e948
mail: admin@example.com
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: mailAccount
objectclass: person
uid: admin
# jsmith, people, example.com
dn: uid=jsmith,ou=people,dc=example,dc=com
cn: John Smith
createtimestamp: 20261019051514Z
entryuuid: 86d14826-2fcb-347a-a0aa-7095d40e98e5
mail: jsmith@example.com
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: mailAccount
objectclass: person
uid: jsmith
# developers, groups, example.com
dn: cn=developers,ou=groups,dc=example,dc=com
cn: developers
entryuuid: 0944c08f-e42e-3dec-a7be-5b43ce970dd8
member: uid=jsmith,ou=people,dc=example,dc=com
objectclass: groupOfUniqueNames
objectclass: groupOfNames
uid: developers
uniquemember: uid=jsmith,ou=people,dc=example,dc=com
# lldap_admin, groups, example.com
dn: cn=lldap_admin,ou=groups,dc=example,dc=com
cn: lldap_admin
entryuuid: 13a64509-a5c6-3b4b-8343-9a1a09566633
member: uid=admin,ou=people,dc=example,dc=com
objectclass: groupOfUniqueNames
objectclass: groupOfNames
uid: lldap_admin
uniquemember: uid=admin,ou=people,dc=example,dc=com
# lldap_password_manager, groups, example.com
dn: cn=lldap_password_manager,ou=groups,dc=example,dc=com
cn: lldap_password_manager
entryuuid: c46b4c82-bf4d-3549-ad19-7869999df0ec
objectclass: groupOfUniqueNames
objectclass: groupOfNames
uid: lldap_password_manager
# lldap_strict_readonly, groups, example.com
dn: cn=lldap_strict_readonly,ou=groups,dc=example,dc=com
cn: lldap_strict_readonly
entryuuid: 6da91b3b-eae7-3280-b4f3-79b23c788d43
objectclass: groupOfUniqueNames
objectclass: groupOfNames
uid: lldap_strict_readonly
# search result
search: 2
result: 0 Success
control: 1.2.840.113556.1.4.319 false MAUCAQYEAA==
pagedresults: estimate=6 cookie=
# numResponses: 7
# numEntries: 6
要点:
- 初始化自动创建
lldap_admin(全部管理权限)、lldap_password_manager(仅密码管理)、lldap_strict_readonly(只读)三个内置组,权限模型即围绕这三个组展开; - 用户条目 objectClass 为
person / inetOrgPerson / posixAccount / mailAccount,组条目为groupOfNames / groupOfUniqueNames且同时携带member与uniquemember成员属性(下游应用的过滤器按此书写); - 下游应用(如《Authelia 4.39 介绍与选型指南》)的用户过滤器/组过滤器要按
ou=people/ou=groups书写; base_dn建库后不宜更改(所有 DN 均随之失效),规划时直接使用组织域名。
5.3 认证与会话参数(jwt_secret)
jwt_secret = "18e5f12c62f8b6754584cb1a3005bdd98149f5672f81ef63fd0661379aee9403"
生成方式(实测):
# openssl rand -hex 32
18e5f12c62f8b6754584cb1a3005bdd98149f5672f81ef63fd0661379aee9403
缺失即拒绝启动(v0.6.2 起行为)。实测将配置中 jwt_secret 注释后启动:
# /opt/lldap/lldap run --config-file /tmp/test_nojwt.toml
2026-10-19T05:36:16.199118087+00:00 INFO ┝━ i [info]: Starting LLDAP version 0.6.3
2026-10-19T05:36:16.199831860+00:00 INFO ┝━ i [info]: Starting the LDAP server on port 13890
2026-10-19T05:36:16.199848466+00:00 INFO ┕━ i [info]: Starting the API/web server on port 17171
2026-10-19T05:36:16.220421028+00:00 ERROR ┝━ e [error]: Configuration error: A secret is missing. Please reserve a JWT secret by setting the `JWT_SECRET` environment variable or the `jwt_secret` value in the config file.
要点:
jwt_secret是 Web/API 会话(JWT,HS512)的签名密钥,变更即全量会话失效,所有已登录客户端需重新认证;- 建议以
openssl rand -hex 32一次性生成并纳入备份清单; ldap_user_dn/ldap_user_pass/ldap_user_email三项仅在首次建库时创建管理员;库已存在后修改ldap_user_pass不会改口令,需用force_ldap_user_pass_reset = true(一次性强制重置,官方提供的唯一"忘记 admin 口令"配置级途径)或 6.3 节 CLI 工具。
jwt_secret 只负责 JWT 签名(无状态会话防伪造),泄露后果是"可伪造登录态",但不动口令数据。key_seed(或 key_file)派生的是 OPAQUE 服务端密钥,用于加密库内每个用户的口令 blob,泄露/丢失的后果见 5.4——两者必须分开保管,不能同值。
5.4 密码存储与哈希(key_seed / key_file 与 OPAQUE)
key_seed = "gg93PDzoFn2qyMk8dvg7y2Xk"
lldap 的口令验证走 OPAQUE 协议(RFC 9380)零知识证明,OPAQUE 服务端记录经 Argon2 哈希后,再用 key_seed 派生的服务端私钥加密落库。实测库内形态(SQLite users 表 password_hash 列为加密 blob):
# sqlite3 /var/lib/lldap/users.db ".tables"
group_attribute_schema memberships user_attribute_schema
group_attributes user_attributes users
group_object_classes user_object_classes
groups jwt_refresh_storage
jwt_storage metadata
# sqlite3 /var/lib/lldap/users.db "SELECT user_id, length(password_hash), hex(substr(password_hash,1,24)) FROM users;"
admin|192|74A57054742B5384B625BDB82446EA139B464D349F3276A4
jsmith|192|8AE87296E54C0DFB7BE47054E52BAFE33F24D5B1D43B62A9
要点:
- 每个用户口令存储为 192 字节加密 blob,整库拖走也拿不到可直接比对的传统哈希;官方架构文档指出即便密钥泄露,攻击者仍需逐用户暴力验证;
key_seed(或key_file指向的private_key文件)一旦变更,所有已存口令立即失效(blob 无法解密,登录报"密码验证错误"),因此该值必须一次生成、永久不变、纳入备份;- 默认种子
RanD0m STR1ng是公开值,生产必须替换; - 口令重置走官方 CLI 工具(实测见 6.3);
- 密码哈希策略(Argon2 参数)当前版本未开放为配置项,由内置默认值决定。
5.5 数据库参数(database_url)
database_url = "sqlite:///var/lib/lldap/users.db?mode=rwc"
| 后端 | database_url 形态 | 适用 |
|---|---|---|
| SQLite(默认) | sqlite:///var/lib/lldap/users.db?mode=rwc | 单机、家庭实验室、百人内团队(实测当前库 136 KB/3 用户) |
| MySQL/MariaDB | mysql://lldap:密码@192.168.1.10/lldap | 多实例汇聚、异地备份池、已有 DBA 体系 |
| PostgreSQL | postgres://lldap:密码@192.168.1.10/lldap | 同上 |
要点:
- SQLite 的备份优势是"拷一个文件",但在线热备请用
sqlite3 .backup(见《lldap 日常运维手册》第四章实测); - 从 SQLite 迁到 MySQL/PostgreSQL 有官方迁移工具
lldap_migration_tool(随二进制包附带); ?mode=rwc表示库文件不存在时自动创建,首次启动同时完成 schema 初始化(启动日志Upgrading DB schema from version 1 ... to version 11)。
lldap 是"数据库之上的 LDAP 接口层":目录树(ou=people/ou=groups)只是固定视图,真实存储即普通关系表。好处是备份/迁移/监控全部沿用数据库生态,代价是放弃了传统目录服务的高并发读优化与任意 schema 能力——这正是其"轻量统一认证"定位的一部分。
</details>5.6 SMTP 可选项([smtp_options])
[smtp_options]
#enable_password_reset=true
#server="smtp.example.com"
#port=587
#smtp_encryption = "STARTTLS"
#user="sender@example.com"
#password="password"
#from="LLDAP Admin <sender@example.com>"
#reply_to="Do not reply <noreply@example.com>"
| 参数 | 说明 | 实测结论 |
|---|---|---|
enable_password_reset | 开启自助找回密码(Web UI 登录页出现"忘记密码") | 开启后 /auth/reset/step1/<用户> 才可用 |
server/port | SMTP 服务器与端口 | 实测指向 127.0.0.1:2525 本地收件器 |
smtp_encryption | NONE / TLS / STARTTLS 三选一 | NONE 模式下配置了 user/password 会发送失败(见下) |
user/password | 发信认证凭据 | NONE + 凭据 → 服务端拒绝明文认证 |
from/reply_to | 发件人与回复地址 | 原样出现在邮件头 |
失败路径实测(enable_password_reset=true、server=127.0.0.1、port=2525、encryption=NONE 且带凭据,触发找回邮件):
# curl -s -w "\nHTTP:%{http_code}\n" -X POST "http://127.0.0.1:17170/auth/reset/step1/jsmith@example.com"
Internal server error: `Could not send email: error response to `AUTH` command: 535 5.7.8 Error: authentication failed: No compatible authentication mechanism was found (os error 335)`
HTTP:500
将 user/password 注释改为匿名中继后成功路径实测(本地 SMTP 收件器收到完整邮件):
# curl -s -w "HTTP:%{http_code}\n" -X POST "http://127.0.0.1:17170/auth/reset/step1/jsmith@example.com"
HTTP:200
==== 收件器回显 ====
From: LLDAP Admin <noreply@example.com>
To: jsmith@example.com
Subject: [LLDAP] Password reset requested
Hello John Smith,
This message is a reply to a password reset request made from the LLDAP admin interface.
To change your password, please visit http://192.168.146.128:17170/reset-password/step2/h9SWZwdPcA...
服务端日志同步记录发信行为(verbose=true 下):
DEBUG ┝━ i [info]: Sending email to 'jsmith@example.com' as 'LLDAP Admin <noreply@example.com>' via 'noreply@example.com'@'127.0.0.1':'2525'
INFO ┕━ i [info]: Password reset email sent
要点:
http_url直接决定邮件内链接,改域名/端口后必须同步修改;- 生产 SMTP 建议
STARTTLS+ 真实凭据;本地中继场景用 NONE 且不配 user/password; - SMTP 未开启时,管理员仍可在 Web UI/GraphQL 中为用户设置新口令(走 6.3 CLI 同源接口),找回邮件只是自助通道。
5.7 其他参数(verbose / [ldaps_options] / [healthcheck_options])
verbose = true:DEBUG 级日志,输出完整配置回显与 LDAP bind 明细(本文多次实测引用),排障后建议关闭以减小日志量;[ldaps_options]:enabled=true后在ldaps_port(默认 6360)监听 TLS 加密的 LDAP,证书用cert_file/key_file指定;需要原生加密通道时开启(下游应用配置ldaps://地址);[healthcheck_options]:内置lldap healthcheck子命令探测的目标地址(默认 localhost),便于本机自检:
# /opt/lldap/lldap healthcheck --config-file /etc/lldap/lldap_config.toml
2026-10-19T05:35:19.231040080+00:00 INFO ┝━ i [info]: Testing LDAP
2026-10-19T05:35:19.231691204+00:00 INFO ┕━ i [info]: Testing GraphQL
(exit code 0 即 LDAP 与 GraphQL 均响应正常。)
六、用户/组管理实操回显
lldap 的 LDAP 接口只读(查询/绑定),全部写操作走 Web UI(管理员图形界面)或 GraphQL API(/api/graphql,认证方式为 Authorization: Bearer <JWT>);另有官方 CLI 工具 lldap_set_password 处理口令。本章以 GraphQL + LDAP 只读验证的方式复现实操全流程。
6.1 获取管理员令牌并建组
# TOKEN=$(curl -s -X POST http://127.0.0.1:17170/auth/simple/login -H "Content-Type: application/json" -d '{"username":"admin","password":"q1w2e3r4"}' | python3 -c "import json,sys;print(json.load(sys.stdin)['token'])")
# curl -s -X POST http://127.0.0.1:17170/api/graphql -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"query":"mutation { createGroup(name: \"developers\") { id displayName } }"}'
{"data":{"createGroup":{"id":4,"displayName":"developers"}}}
6.2 建用户(createUser)
# curl -s -X POST http://127.0.0.1:17170/api/graphql -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"query":"mutation { createUser(user: {id: \"jsmith\", email: \"jsmith@example.com\", displayName: \"John Smith\"}) { id email displayName } }"}'
{"data":{"createUser":{"id":"jsmith","email":"jsmith@example.com","displayName":"John Smith"}}}
6.3 加组成员(addUserToGroup)与口令设置
入参形态错误时报错自带正确签名提示(实测原样保留,便于对照):
# curl -s -X POST http://127.0.0.1:17170/api/graphql -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"query":"mutation { addUserToGroup(user: \"jsmith\", group: 4) { ok } }"}'
{"errors":[{"message":"Expected value of type \"String!\", found 4.","locations":[{"line":1,"column":36}]}]}
{"errors":[{"message":"Unknown argument \"group\" on field \"Mutation.addUserToGroup\".","locations":[{"line":1,"column":45}]}],"data":null}
按提示改用 userId/groupId(成功回显):
# curl -s -X POST http://127.0.0.1:17170/api/graphql -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"query":"mutation { addUserToGroup(userId: \"jsmith\", groupId: 4) { ok } }"}'
{"data":{"addUserToGroup":{"ok":true}}}
口令设置不在 GraphQL(实测 UpdateUserInput 无密码字段、独立 setPassword mutation 不存在,报错回显略),官方路径是 CLI 工具 lldap_set_password:
# /opt/lldap/lldap_set_password --help 2>&1 | head -14
CLI tool to reset the password of a user in the LDAP server
Usage: lldap_set_password [OPTIONS]
Options:
--base-url <BASE_URL>
Base url of the LDAP server [default: http://localhost:17170]
--admin-username <ADMIN_USERNAME>
Admin username
--admin-password <ADMIN_PASSWORD>
Admin password
--username <USERNAME>
User name of the user to update
--password <PASSWORD>
New password
--token <TOKEN>
Admin API token
-h, --help Print help
-V, --version Print version
# /opt/lldap/lldap_set_password --base-url http://127.0.0.1:17170 --admin-username admin --admin-password q1w2e3r4 --username jsmith --password q1w2e3r4
(静默返回 0 即成功。)
6.4 结果验证(LDAP 只读查询 + 登录)
组成员关系通过 memberOf 属性回读:
# ldapsearch -x -H ldap://127.0.0.1:3890 -D "cn=admin,ou=people,dc=example,dc=com" -w q1w2e3r4 -b "dc=example,dc=com" "(uid=jsmith)" memberOf dn
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (uid=jsmith)
# requesting: memberOf dn
#
# jsmith, people, example.com
dn: uid=jsmith,ou=people,dc=example,dc=com
memberOf: cn=developers,ou=groups,dc=example,dc=com
# search result
search: 2
result: 0 Success
control: 1.2.840.113556.1.4.319 false MAUCAQEEAA==
pagedresults: estimate=1 cookie=
# numResponses: 2
# numEntries: 1
普通用户 LDAP 绑定与 Web 登录:
# ldapwhoami -x -H ldap://127.0.0.1:3890 -D "uid=jsmith,ou=people,dc=example,dc=com" -w q1w2e3r4
Result: Success (0)
Additional info: dn:uid=jsmith,ou=people,dc=example,dc=com
# curl -s -X POST http://127.0.0.1:17170/auth/simple/login -H "Content-Type: application/json" -d '{"username":"jsmith","password":"q1w2e3r4"}' | head -c 230
{"token":"eyJhbGciOiJIUzUxMiJ9.eyJleHAiOjE3OTIzODMwMzcsImlhdCI6MTc5MjM3OTQzN30...
"refreshToken":"...","status":"Success"}
用户登录 JWT 的 payload 中直接携带
"groups":["developers"]——下游应用无需回查即可完成组鉴权。
查询单用户详情(含组)与全量组列表:
# curl -s -X POST http://127.0.0.1:17170/api/graphql -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"query":"{ user(userId: \"jsmith\") { id email displayName groups { displayName } } }"}'
{"data":{"user":{"id":"jsmith","email":"jsmith@example.com","displayName":"John Smith","groups":[{"displayName":"developers"}]}}}
# curl -s -X POST http://127.0.0.1:17170/api/graphql -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"query":"{ groups { id displayName } }"}'
{"data":{"groups":[{"id":1,"displayName":"lldap_admin"},{"id":2,"displayName":"lldap_password_manager"},{"id":3,"displayName":"lldap_str_readonly"},{"id":4,"displayName":"developers"}]}}
完整的 GraphQL schema 可用内置子命令导出后离线检索:
# /opt/lldap/lldap export_graphql_schema --output /tmp/schema.graphql
七、生产配置模板
实测环境的完整 /etc/lldap/lldap_config.toml(逐值可复现;资源画像:内存常态 RSS ≈16 MiB(启动态 ≈2.3 MiB)、磁盘数据目录 ≈140 KB/3 用户,适合 1C512M 起的任意节点,单实例内网场景):
# /etc/lldap/lldap_config.toml - lldap 主配置(实测环境)
verbose = false
ldap_host = "0.0.0.0"
ldap_port = 3890
http_host = "0.0.0.0"
http_port = 17170
http_url = "http://192.168.146.128:17170"
jwt_secret = "18e5f12c62f8b6754584cb1a3005bdd98149f5672f81ef63fd0661379aee9403"
ldap_base_dn = "dc=example,dc=com"
ldap_user_dn = "admin"
ldap_user_email = "admin@example.com"
ldap_user_pass = "q1w2e3r4"
database_url = "sqlite:///var/lib/lldap/users.db?mode=rwc"
key_seed = "gg93PDzoFn2qyMk8dvg7y2Xk"
[smtp_options]
#enable_password_reset=true
#server="smtp.example.com"
#port=587
#smtp_encryption = "STARTTLS"
#user="sender@example.com"
#password="password"
#from="LLDAP Admin <sender@example.com>"
#reply_to="Do not reply <noreply@example.com>"
[ldaps_options]
#enabled=true
#port=6360
#cert_file="/var/lib/lldap/cert.pem"
#key_file="/var/lib/lldap/key.pem"
[healthcheck_options]
#http_host = "localhost"
#ldap_host = "localhost"
生产替换清单:jwt_secret/key_seed 重新生成、ldap_user_pass 强口令、http_url 改为对外域名、SMTP 全段按 5.6 启用、base_dn 改为组织域名、可选 LDAPS。配置文件属主 root:lldap、权限 640(内含明文口令与密钥)。
八、常见问题
Q1:改了 ldap_user_pass 后 admin 口令没变?
该参数仅首次建库生效。库已存在时改配置不生效,用 force_ldap_user_pass_reset = true 重启一次(一次性),或用 6.3 节 lldap_set_password。
Q2:启动报 A secret is missing ... jwt_secret?
jwt_secret 为必填(v0.6.2+ 拒绝启动)。生成:openssl rand -hex 32,填入配置或环境变量 LLDAP_JWT_SECRET(实测报错全文见 5.3)。
Q3:找回密码邮件发不出?
三步排查:① [smtp_options] 是否 enable_password_reset=true;② smtp_encryption 与凭据组合(NONE 不能带 user/password,实测 535 报错见 5.6);③ 服务端日志 Could not send email: 后的具体 SMTP 错误。
Q4:下游应用按 uid 还是 cn 绑定用户 DN?
用户 DN 固定为 uid=<用户ID>,ou=people,<base_dn>(如 uid=jsmith,ou=people,dc=example,dc=com);组 DN 为 cn=<组名>,ou=groups,<base_dn>。管理员绑定 DN 同理是 cn=admin,ou=people,dc=example,dc=com(注意管理员是 uid 属性值 admin,DN 头部用 cn)。
Q5:能否通过 LDAP 直接创建用户? 不能。LDAP 接口为只读子集(官方架构文档),写操作一律走 Web UI / GraphQL API / CLI。需要批量导入时用 GraphQL 批量 mutation 或先在 Web UI 手工建账号。
Q6:key_seed 能换吗?
能换但不可逆:换后所有口令 blob 无法解密,全量用户需重新设密。官方提供 force_update_private_key 配合一次性迁移,操作前必须全量备份(见《lldap 日常运维手册》)。
九、参考链接
- 官方配置文档:https://github.com/lldap/lldap/blob/main/docs/config.md
- 官方架构文档(OPAQUE/存储设计):https://github.com/lldap/lldap/blob/main/docs/architecture.md
- 官方 scripting 文档(GraphQL API 示例):https://github.com/lldap/lldap/blob/main/docs/scripting.md
- lldap v0.6.3 Release:https://github.com/lldap/lldap/releases/tag/v0.6.3
- OPAQUE 协议(RFC 9380):https://datatracker.ietf.org/doc/rfc9380/
- 本系列文档:《lldap 0.6.3 介绍与选型指南》《lldap Docker Compose 部署指南》《lldap 日常运维手册》