即便 OIDC 已经是现代系统的主流,但在内网里总有那么几个“钉子户”只认 LDAP:老版本的 JumpServer、沉淀多年的内部工具、或者需要统一管控登录账号的 Linux 主机。在 authentik 统一身份认证 的四种接入方式里,LDAP 就是给这些系统准备的终极兜底方案。
authentik 会对外伪装成一个标准的 LDAP 目录服务器。有了它,你不需要再单独去搭一套 OpenLDAP;这套虚拟目录里的账号、组结构和禁用状态,会与 OIDC 完美共用底层数据。
本篇我们将带你快速补齐 LDAP 的核心概念,拆解 authentik 这个“虚拟目录”与传统 LDAP 究竟有何不同。我们还会以 JumpServer 为例走一遍接入流程,并重点盘点那些一旦选错就会留下安全漏洞的危险配置。内容基于 authentik 2026.8 的官方文档。
TL;DR
- authentik 的 LDAP 是只读的虚拟目录:没有单独的 LDAP 数据库,bind 就是在 authentik 里执行一次 bind flow,search 是实时读 authentik 的用户和组。
- 密码会经过应用:员工要先在 authentik 设密码,不能飞书扫码,应用能拿到明文密码。系统支持 OIDC 就优先用 OIDC。
- 服务账号也要在应用绑定范围内,还要单独授予 “Search full LDAP directory” 权限才能查别人。
- Bind mode 一定选 Direct:Cached bind 下,禁用的账号在缓存过期前仍能登录。
- MFA 写法是
密码;123456,只支持 TOTP、Duo 和静态码。 - 只开 LDAPS(636),排查先用
ldapsearch绕过应用。
Table of contents
Open Table of contents
1. 快速上手 LDAP 基础概念
LDAP 本质上是一种专门用来查询和验证“目录信息”的协议。你可以把目录想象成一棵按照组织架构排列的树,这棵树上的每一个节点就是一个“条目”(用户、部门、设备等)。
当你把 Base DN 设为 dc=ldap,dc=company,dc=com 时,authentik 对外提供的那棵树长这样:
dc=ldap,dc=company,dc=com # Base DN,整棵树的树根
├── ou=users # 存放所有用户
│ ├── cn=charles.shao # 一个普通员工
│ └── cn=svc-jumpserver # JumpServer 用来查询目录的服务账号
├── ou=groups # 存放所有组
│ ├── cn=飞书/技术中心
│ └── cn=ops-admin
└── ou=virtual-groups # 兼容 Linux 习惯:为每个用户建一个同名的虚拟组
跟这棵树打交道,你需要掌握几个核心术语:
| 术语 | 含义 | 例子 |
|---|---|---|
| DN | 唯一路径(Distinguished Name):从下往上写,精确指向一个条目 | cn=charles.shao,ou=users,dc=ldap,dc=company,dc=com |
| Base DN | 查询基点:每次搜索都可以从树根,或者树根下的某根树枝开始查 | dc=ldap,dc=company,dc=com |
| Bind | 登录:用你的 DN 加上密码向目录证明你是谁 | 用 cn=svc-jumpserver,... 加上密码执行 Bind |
| Search | 查询:在指定的 Base DN 范围内按条件捞出想要的条目 | 在 ou=users 这个圈子里查询 (cn=charles.shao) |
| Filter | 搜索条件表达式,必须包裹在括号里 | (cn=charles.shao)、(mail=*@company.com) |
| Attribute | 每个条目身上挂的属性字段 | cn(通用名)、mail(邮箱)、memberOf(所属组) |
2. authentik 里的 LDAP,是一个“幻觉”
传统做法里,你需要维护一个真实的 LDAP 数据库。但在 authentik 这里,LDAP 完全是一个用代码动态生成的“虚拟目录”。
当独立的 LDAP Outpost 组件收到外界的 LDAP 请求时,它会像个翻译官一样,把请求当场转换成对 authentik 后端接口的调用:
- 针对 Bind 请求(登录):Outpost 会拿着请求里的用户名和密码,在 authentik 内部跑一遍你在 LDAP Provider 里配置的那个 Bind Flow。流程跑通了,它就告诉客户端 Bind 成功。正因如此,那些被禁用的账号、还没设密码的账号、或者压根不在当前 LDAP 应用权限绑定(Binding)范围内的账号,在这一步都会被直接无情拒绝。
- 针对 Search 请求(查询):Outpost 会实时从 authentik 数据库里读出当下的用户和组,现场拼装成上面那棵树的样子扔给客户端。
最重要的限制是:这个虚拟目录是绝对只读的。 你不能通过标准 LDAP 工具去修改密码、创建新用户或更新员工信息。员工如果想改密码,只能乖乖登录到 authentik 的个人设置页面去操作。
3. 接上 JumpServer 后,发生了什么
我们以老版本 JumpServer 接入为例。当员工在 JumpServer 的登录框里敲下 charles.shao 和他的密码并按下回车时,幕后发生了这样一场接力赛:
这是 LDAP 圈子的标准铁律:“先用服务账号(Admin)Bind 进去把目标用户的 DN 搜出来,再用目标用户的 DN 加上他自己刚才输入的密码进行第二次 Bind 验证”。
这张图点出了 LDAP 在安全架构上最致命的一块短板:员工的密码是先交给了 JumpServer,再由 JumpServer 拿着明文密码去向 LDAP 验证的。
这带来的后果是:
- 员工没法用飞书扫码,也不能在 authentik 那边弹出一个漂亮的二次 MFA 页面。
- 飞书同步脚本建出来的账号默认是没有独立密码的,员工必须先登录 authentik 去设置一个专用的内部密码。
- JumpServer 会过手员工的明文密码。 这意味着接入 LDAP 的必须是你绝对信任的系统。
正因如此,如果新版 JumpServer 已经支持了 OIDC 接入,请务必果断切换到 OIDC。LDAP 只应留给那些没有选择的老古董系统。
4. 目录里究竟装了哪些属性
在这个虚拟目录里,你可以查到几乎所有的核心身份信息:
| 关键属性 | 里面装了什么 |
|---|---|
cn | 用户名,例如 charles.shao |
uid | 用户的唯一内部标识 |
uidNumber | 自动生成的数字 ID,专门给 Linux 系统的 user id 用 |
name / displayName | 真实姓名 |
mail | 邮箱 |
memberOf | 用户所属所有组的 DN 列表(用于应用侧权限映射) |
objectClass | 标识条目类型的底层元数据,比如 user、organizationalPerson |
homeDirectory | 给 Linux 用的家目录路径,默认 /home/<用户名> |
ak-active | 账号是否被启用 |
ak-superuser | 是否属于拥有 authentik 超级管理员权限的组 |
对于“组”条目,除了 cn(组名)之外,最关键的是 member(组内所有成员的 DN 列表)。如果你在 authentik 的用户或组上挂了自定义属性(Custom Attributes),它们也会被原封不动地暴露到 LDAP 里。
把这些属性对应到 JumpServer 的 LDAP 接入配置里,差不多是这个样子:
| 配置项 | 该填什么 |
|---|---|
| 服务器地址 | ldaps://ldap.company.com:636 |
| 绑定 DN | cn=svc-jumpserver,ou=users,dc=ldap,dc=company,dc=com |
| 用户 OU | ou=users,dc=ldap,dc=company,dc=com |
| 用户过滤器 | (cn=%(user)s) |
| 属性映射 | {"username": "cn", "name": "name", "email": "mail"} |
5. 谁能 Bind?谁能 Search?
这是刚上手 authentik LDAP 时最容易迷糊的地方:
- 谁能 Bind(登录)?:只有在 LDAP 应用绑定(Binding)范围内的人才能登录。最容易踩坑的是服务账号也必须被绑定。比如你的 LDAP 应用只绑定了
飞书/技术中心,而svc-jumpserver这个服务账号并不属于技术中心,那 JumpServer 连第一步的查询验证都做不了。你必须给服务账号单独加一条用户绑定。 - 谁能 Search(查询)?:出于安全考虑,默认情况下每个人只能查到自己的信息,以及自己所在的组。JumpServer 既然要查全公司的员工,你就必须在 authentik 后台建一个角色,在 LDAP Provider 的 Permissions 标签页里赋予它 “Search full LDAP directory” 的对象权限,然后把这个角色分配给
svc-jumpserver。
6. 危险的性能开关:Bind 与 Search 模式
在 LDAP Provider 的配置里,有两组决定安全与性能天平的选项:
| 设置项 | 选项 | 它的行为 | 选哪个? |
|---|---|---|---|
| Bind mode | Direct bind | 每次收到 Bind 请求,都老老实实去 authentik 跑一遍完整的 Bind Flow 验证。 | 必须选这个 |
| Cached bind | 验证成功一次后,就把密码的哈希缓存在 Outpost 内存里。期间就算在 authentik 里把人禁用了,缓存过期前他依然能登录! | 绝对不要用 | |
| Search mode | Direct search | 每次搜索都实时查 authentik 数据库。数据绝对新鲜,但并发极高时可能会慢。 | 千人以内的公司闭眼选这个 |
| Cached search | Outpost 每隔一段时间把所有用户和组全拉到自己内存里,直接用内存回答查询。极快,但数据可能有延迟。 | 除非遇到明确的性能瓶颈,否则先别开 |
总结一下:Cached bind 典型的“为了节省几百毫秒的性能,在离职禁用上留个巨大的后门”。对于 JumpServer 登录这种绝对低频的操作,跑一遍完整的验证流程没有任何问题。
7. 怎么做 MFA?什么是专用密码?
LDAP 下的 MFA 怎么做:
在 LDAP Provider 的设置里打开 Code-based MFA Support,并在 Bind Flow 里加上 Authenticator Validation 步骤后,MFA 就开启了。员工输入密码时,需要硬核地把 6 位动态码拼在密码后面,中间用分号隔开,格式是:密码;123456。
注意,这里只支持 TOTP、Duo 和静态码,不支持短信验证码,因为纯正的 LDAP 协议里根本没有“给你发短信并等你回填”的交互机制。
提示:如果系统自己支持 MFA(比如 JumpServer 自身带有 MFA 功能),强烈建议在系统那边开,就别折腾 LDAP 这种反人类的拼密码方式了。
应用专用密码(App Password): 为了不让脚本或内部工具拿着你的主密码到处乱跑,你可以在个人设置里生成一个“应用专用密码”。在 Bind Flow 的密码验证步骤里,把 Backends 选为 “User database + app passwords”,员工就可以用这段随机生成的字符串代替主密码去执行 LDAP Bind。一旦泄露,在后台单点吊销即可。
8. 加密传输
LDAP Provider 支持原生的 LDAPS(636 端口)和 StartTLS(在 389 端口上握手后升级为加密连接)。你只需要在 Provider 上选好 TLS 证书即可。
强烈建议直接封死 389,只开放 ldaps://(636)。 因为一旦 StartTLS 配置稍有差池,有些脆弱的客户端就会悄悄回退到明文传输密码。
9. 排障指南:那些常见的报错
| 现象 | 最可能的原因 |
|---|---|
| 员工 Bind 失败,永远提示密码错误 | 员工压根没去 authentik 设置过密码;不在应用的绑定范围内;或者你作死在 Bind Flow 里加了不支持的步骤(比如飞书按钮) |
| 服务账号 Bind 失败 | 没给服务账号配置应用绑定(参见第 5 节) |
| 服务账号只能搜到自己 | 没有给服务账号授予 “Search full LDAP directory” 的权限(参见第 5 节) |
| 员工昨天就离职了,今天还能登系统 | Bind Mode 选了坑人的 Cached bind;或者他在 JumpServer 里的老会话还没过期 |
| 弄了多个 LDAP Provider,查询全乱了 | 每个 LDAP Provider 的 Base DN 必须独一无二。如果冲突了,可以在前面再垫一层,比如 ou=jumpserver,dc=ldap,... |
当遇到玄学报错时,永远先用命令行工具绕过应用直接查,这是洗清 authentik 嫌疑的最快方法:
ldapsearch -H ldaps://ldap.company.com:636 -x \
-D 'cn=svc-jumpserver,ou=users,dc=ldap,dc=company,dc=com' -W \
-b 'ou=users,dc=ldap,dc=company,dc=com' '(cn=charles.shao)'
10. 生产环境的取舍与防坑经验
LDAP 下飞书扫码帮不上任何忙。 这意味着每个员工都得被逼着额外去记一个内部密码,忘了就得找 IT 重置,而且这串密码还会被每个接了 LDAP 的下游应用看得一清二楚。所以,只要那个系统能迁到 OIDC,不管花多少精力都值得;LDAP 只应该留给那些别无选择的“遗留系统”。
离职禁用要死死盯住应用本地的会话。 在 Direct bind 模式下,被禁用的员工确实立刻就无法发起新登录了;但由于 LDAP 没有像 OIDC 那样的登出回调机制,员工在 JumpServer 里已经建立的会话会丝毫不受影响。面对紧急离职,禁用账号后必须立刻去 JumpServer 里把人手动踢下线。完整的离职处理见 架构与接入方式选型。
JumpServer 既然依赖 authentik,就必须留应急后门。 万一 authentik 挂了,运维连不上跳板机,也就没法登进机器去修 authentik,这就成了死局。JumpServer 里必须保留一个不依赖 LDAP 的本地管理员账号,凭据封存在保险箱里,定期演练“破窗登录”。
LDAP Outpost 是个独立进程,需要独立呵护。 它并不随着 authentik Server 一起自动扩容。在 Kubernetes 上,它应该被当成和核心 Server 同等重要的组件对待:保证多副本打散部署,并且前面挂一个靠谱的 TCP 负载均衡。