Skip to content
Charles Shao
Go back

authentik 统一身份认证 · LDAP:虚拟目录、bind 流程与 JumpServer 接入

创建于:
v1.0.0
–views

即便 OIDC 已经是现代系统的主流,但在内网里总有那么几个“钉子户”只认 LDAP:老版本的 JumpServer、沉淀多年的内部工具、或者需要统一管控登录账号的 Linux 主机。在 authentik 统一身份认证 的四种接入方式里,LDAP 就是给这些系统准备的终极兜底方案。

authentik 会对外伪装成一个标准的 LDAP 目录服务器。有了它,你不需要再单独去搭一套 OpenLDAP;这套虚拟目录里的账号、组结构和禁用状态,会与 OIDC 完美共用底层数据。

本篇我们将带你快速补齐 LDAP 的核心概念,拆解 authentik 这个“虚拟目录”与传统 LDAP 究竟有何不同。我们还会以 JumpServer 为例走一遍接入流程,并重点盘点那些一旦选错就会留下安全漏洞的危险配置。内容基于 authentik 2026.8 的官方文档。

TL;DR

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 后端接口的调用:

最重要的限制是:这个虚拟目录是绝对只读的。 你不能通过标准 LDAP 工具去修改密码、创建新用户或更新员工信息。员工如果想改密码,只能乖乖登录到 authentik 的个人设置页面去操作。

3. 接上 JumpServer 后,发生了什么

我们以老版本 JumpServer 接入为例。当员工在 JumpServer 的登录框里敲下 charles.shao 和他的密码并按下回车时,幕后发生了这样一场接力赛:

LDAP 登录时序:JumpServer 先以服务账号 bind 并搜索用户 DN,再以员工 DN 和密码 bind,outpost 每次都在 authentik 执行 bind flow

这是 LDAP 圈子的标准铁律:“先用服务账号(Admin)Bind 进去把目标用户的 DN 搜出来,再用目标用户的 DN 加上他自己刚才输入的密码进行第二次 Bind 验证”。

这张图点出了 LDAP 在安全架构上最致命的一块短板:员工的密码是先交给了 JumpServer,再由 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
绑定 DNcn=svc-jumpserver,ou=users,dc=ldap,dc=company,dc=com
用户 OUou=users,dc=ldap,dc=company,dc=com
用户过滤器(cn=%(user)s)
属性映射{"username": "cn", "name": "name", "email": "mail"}

这是刚上手 authentik LDAP 时最容易迷糊的地方:

6. 危险的性能开关:Bind 与 Search 模式

在 LDAP Provider 的配置里,有两组决定安全与性能天平的选项:

设置项选项它的行为选哪个?
Bind modeDirect bind每次收到 Bind 请求,都老老实实去 authentik 跑一遍完整的 Bind Flow 验证。必须选这个
Cached bind验证成功一次后,就把密码的哈希缓存在 Outpost 内存里。期间就算在 authentik 里把人禁用了,缓存过期前他依然能登录!绝对不要用
Search modeDirect search每次搜索都实时查 authentik 数据库。数据绝对新鲜,但并发极高时可能会慢。千人以内的公司闭眼选这个
Cached searchOutpost 每隔一段时间把所有用户和组全拉到自己内存里,直接用内存回答查询。极快,但数据可能有延迟。除非遇到明确的性能瓶颈,否则先别开

总结一下: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 负载均衡。

11. 参考资料


–views
Share this post on:

Previous Post
authentik 统一身份认证 · RADIUS:VPN 与网络设备接入
Next Post
authentik 统一身份认证 · 代理认证:用 Forward auth 给 Prometheus 加一道门