sso.example.com、ldap.example.internal、dc=example,dc=internal、registry.example.internal 作为示例值。截图只用于说明配置入口和字段位置,落地时以自己的域名、DN、账号和凭据为准。0. 结论和边界#
这份 runbook 适合把 Keycloak 作为内部统一登录入口,用 Docker Compose 跑单实例,并接入已有 LDAP 目录。
主要覆盖这些内容:
- 用 PostgreSQL 持久化 Keycloak 数据。
- 通过 Compose 管理 Keycloak、数据库和运行参数。
- 管理员账号丢失时,用
bootstrap-admin进入恢复流程。 - 进入管理台后配置中文、邮件、LDAP、密码策略和自助改密。
- 给出验证矩阵和回滚边界,避免只做“能登录”的浅验证。
边界也要明确:
- 这里不是 Keycloak 高可用方案。生产高可用还要考虑多实例、缓存栈、会话、反向代理和数据库高可用。
- 示例没有展开具体业务系统的 OIDC/SAML Client 接入。
- LDAP 写回能力取决于目录服务权限和组织策略;不建议默认开启可写。
- 邮件、数据库、LDAP Bind 密码不要写进 Git、工单或聊天记录,使用
.env、Secret Manager 或 CI/CD 变量托管。
整体关系如下:
flowchart LR U[Browser] --> RP[Reverse Proxy] RP --> KC[Keycloak] KC --> PG[(PostgreSQL)] KC --> LDAP[(LDAP Directory)] KC --> SMTP[SMTP Server] KC --> APP[OIDC / SAML Clients]
1. 部署前先收住几个事实#
Keycloak 的配置入口很多:命令行参数、环境变量、管理台、Realm 配置、Client 配置、LDAP Provider 配置。先把边界分清,后面排查会轻很多。
| 层次 | 典型配置 | 是否建议写入 Compose |
|---|---|---|
| Server | 数据库、主机名、代理头、健康检查、指标 | 是 |
| Realm | 语言、邮件、密码策略、Required Actions | 不一定,管理台或导出文件维护 |
| User Federation | LDAP 连接、搜索 DN、映射和同步策略 | 可先管理台配置,稳定后再导出 |
| Client | OIDC/SAML 应用、回调地址、Client Secret | 建议单独变更和审计 |
官方文档里,Keycloak 容器使用 KC_DB、KC_DB_URL、KC_DB_USERNAME、KC_DB_PASSWORD 等环境变量配置数据库;初始管理员可用 KC_BOOTSTRAP_ADMIN_USERNAME 和 KC_BOOTSTRAP_ADMIN_PASSWORD 提供。生产模式不要长期使用 start-dev。
2. Compose 部署骨架#
下面是一个单实例 Compose 骨架。它把 PostgreSQL 和 Keycloak 放在同一个 Compose 项目里,适合小规模内部服务或验证环境;生产环境可以把 PostgreSQL 换成已有数据库服务。
services:
postgres:
image: postgres:16-alpine
container_name: keycloak-postgres
restart: unless-stopped
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: ${KC_DB_PASSWORD:?set KC_DB_PASSWORD in .env}
volumes:
- ./postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"]
interval: 10s
timeout: 5s
retries: 10
keycloak:
image: quay.io/keycloak/keycloak:26.3.2
container_name: keycloak
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${KC_DB_PASSWORD:?set KC_DB_PASSWORD in .env}
KC_HOSTNAME: https://sso.example.com
KC_PROXY_HEADERS: xforwarded
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME:?set admin user}
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD:?set admin password}
command:
- start
- --http-enabled=true
ports:
- "8080:8080"
- "9000:9000"
.env 只放在部署机或 Secret Manager 中,不提交到仓库:
KC_DB_PASSWORD=replace-with-generated-password
KC_BOOTSTRAP_ADMIN_USERNAME=bootstrap-admin
KC_BOOTSTRAP_ADMIN_PASSWORD=replace-with-a-strong-password
启动前先渲染配置:
docker compose config
启动服务:
docker compose up -d
基础验证:
docker compose ps
curl -fsS "http://127.0.0.1:9000/health/ready"
docker compose logs --tail=100 keycloak
如果前面有反向代理,先确认代理写入 X-Forwarded-* 头,并让 KC_HOSTNAME 与外部访问地址一致。主机名和代理头不一致时,最常见的现象是后台跳转地址、回调地址或登录地址不对。
3. 数据库初始化和权限#
如果不用 Compose 内置 PostgreSQL,而是接已有 PostgreSQL,可以手工创建数据库和专用用户。不要复用超级用户,也不要把明文密码写到脚本仓库里。
CREATE DATABASE keycloak;
CREATE USER keycloak WITH PASSWORD :'kc_db_password';
GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;
执行时从当前 shell 注入变量,不把真实密码写进 SQL 文件:
psql -v kc_db_password="${KC_DB_PASSWORD:?set KC_DB_PASSWORD}" -f init-keycloak-db.sql
PostgreSQL 15 以后,很多环境还需要在目标库里授予 schema 权限:
\c keycloak
GRANT ALL ON SCHEMA public TO keycloak;
对应的 Keycloak 环境变量:
KC_DB=postgres
KC_DB_URL=jdbc:postgresql://postgres.example.internal:5432/keycloak
KC_DB_USERNAME=keycloak
KC_DB_PASSWORD=replace-with-generated-password
上线前检查:
| 检查项 | 命令 | 继续条件 |
|---|---|---|
| 数据库连通 | psql "$DATABASE_URL" -c "select 1" | 返回 1 |
| Keycloak 表 | \dt | 首次启动后能看到 Keycloak 表 |
| 容器日志 | docker compose logs keycloak | 没有认证失败和迁移失败 |
| 备份 | pg_dump -Fc keycloak > keycloak-before-change.dump | 备份文件生成成功 |
4. 管理员恢复:bootstrap-admin 只做临时入口#
如果后台管理员账号丢失,Keycloak 提供 bootstrap-admin 恢复入口。这个命令有两个常见形态:
/opt/keycloak/bin/kc.sh bootstrap-admin user
/opt/keycloak/bin/kc.sh bootstrap-admin service
在容器里执行时,先进入容器:
docker exec -it keycloak bash
再执行恢复命令:
/opt/keycloak/bin/kc.sh bootstrap-admin service
这里要注意三点:
- 恢复命令需要使用和服务启动一致的运行配置,尤其是数据库、主机名和扩展 Provider。
- 恢复入口只用于重新拿回后台控制权,bootstrap 账号和凭据不能当长期管理员保留。
- 拿回后台后,创建新的管理员账号,确认角色无误,再删除 bootstrap 阶段留下的临时账号或凭据。
下面这几张图对应管理员收口动作。顺序不要反过来:先创建新的后台管理员,再确认角色,最后处理 bootstrap 阶段留下的临时账号。
先在目标 Realm 里创建新的后台管理员。这里重点不是用户名,而是确认账号来自可维护的长期身份源,不依赖临时恢复入口。

然后进入用户的角色映射页面,把管理控制台需要的角色授给新管理员。授予后建议用新账号单独登录一次,确认能进入目标 Realm。

新管理员验证通过后,再删除临时 admin 或回收临时凭据。这样能避免恢复账号长期留在系统里。

5. 基础界面:中文和主题#
Keycloak 的中文界面通常在 Realm 级别配置。路径是:
Realm settings -> Localization / Themes
建议至少确认两类配置:
| 配置 | 建议 |
|---|---|
| Internationalization | 开启后选择需要支持的语言 |
| Default Locale | 内部用户为主时可设为 zh-CN 或 Simplified Chinese |
| Login theme | 没有定制主题时先保持默认 |
| Account theme | 自助改密依赖 Account Console,先不要关闭 |
先从 Realm 设置页进入主题和国际化配置,确认登录页、账号页和管理台使用的是预期主题。

再设置默认语言。内部用户以中文为主时,可以把默认语言设为中文,同时保留登录页语言切换能力。

如果团队里同时有中文和英文用户,不要强行只保留一个语言;保持语言切换入口可见,减少登录页支持成本。
6. 邮件配置:把 GitLab 示例改成 Keycloak 字段#
很多系统都有自己的 SMTP 配置写法,不能把 GitLab Omnibus 的 gitlab_rails['smtp_*'] 片段直接搬到 Keycloak。Keycloak 的邮件配置在 Realm 里维护:
Realm settings -> Email
建议按字段理解:
| Keycloak 字段 | 示例值 | 说明 |
|---|---|---|
| Host | smtp.example.com | SMTP 服务器 |
| Port | 465 或 587 | 取决于 TLS/STARTTLS 策略 |
| From | sso@example.com | 用户收到邮件时看到的发件人 |
| From display name | Example SSO | 可读名称 |
| Authentication | Enabled | 大多数 SMTP 都需要 |
| Username | sso@example.com | SMTP 账号 |
| Password | 不写入文档 | 使用邮件服务授权码或专用密码 |
| Enable SSL | 端口 465 常见为开启 | 按邮件服务要求 |
| Enable StartTLS | 端口 587 常见为开启 | 不要和 SSL 混用错 |
先进入 Realm 的 Email 配置页,确认当前配置属于目标 Realm,而不是误改到 master 或其他测试 Realm。

再填写发件人、SMTP 地址、端口和认证方式。密码或授权码只进入运行环境,不写入文档、仓库或工单。

配置完成后,先用管理台的测试邮件按钮验证。测试通过只代表 SMTP 通道可用,还需要继续验证真实用户动作,比如重置密码、更新邮箱、Required Action 邮件。

7. LDAP User Federation#
LDAP 接入建议从只读或受控写入开始,不要一上来就让 Keycloak 全量写回目录服务。路径是:
User federation -> Add LDAP provider
从 User Federation 入口查看现有用户源。这里能看到当前 Realm 是否已经接入 LDAP,以及后续同步是否走同一个 Provider。

新增 Provider 时选择 LDAP。Provider 名称建议体现目录来源,避免后续多个目录源混在一起。

关键配置可以拆成三组。
连接和认证:
| 字段 | 示例值 | 说明 |
|---|---|---|
| Vendor | Other、Active Directory 等 | 按目录类型选择 |
| Connection URL | ldap://ldap.example.internal:389 | 能用 LDAPS 时优先 ldaps://...:636 |
| Bind type | simple | 常见内部 LDAP 绑定方式 |
| Bind DN | cn=keycloak,ou=svc,dc=example,dc=internal | 使用专用服务账号 |
| Bind credential | 不写入文档 | 只放 Secret |
| Use Truststore SPI | 按证书链策略设置 | LDAPS 时重点验证 |
连接和认证页决定 Keycloak 能否访问目录服务。先用只读服务账号完成连接测试,再评估是否需要写回能力。

搜索和属性:
| 字段 | 示例值 | 说明 |
|---|---|---|
| Edit mode | READ_ONLY 或 WRITABLE | 先从只读开始更稳 |
| Users DN | ou=users,dc=example,dc=internal | 用户搜索根 DN |
| Username LDAP attribute | uid | 登录名字段 |
| RDN LDAP attribute | uid | 新建用户时的 RDN 字段 |
| UUID LDAP attribute | entryUUID | 唯一标识字段,AD 通常不同 |
| User object classes | inetOrgPerson, organizationalPerson | 按目录结构设置 |
| Search scope | One Level 或 Subtree | 目录层级深时用 Subtree |
| Pagination | 开启 | 大目录同步时避免一次拉取过多 |
搜索配置决定 Keycloak 能看到哪些用户。Users DN、对象类和唯一标识字段要与目录实际结构一致,不能只照抄示例。

同步策略:
| 配置 | 建议 |
|---|---|
| Import users | 开启,便于 Keycloak 缓存和映射 |
| Sync Registrations | 一般关闭,避免 Keycloak 反向创建 LDAP 用户 |
| Full sync period | 按用户规模设置,不要过短 |
| Changed users sync period | 变更频繁时开启增量同步 |
| Batch size | 按 LDAP 性能和目录规模设置 |
同步配置影响目录压力和用户可见性。用户量不明时,先小范围手动同步,再决定全量和增量同步周期。

厂商和通用选项要和目录类型匹配。Active Directory、OpenLDAP、FreeIPA 在 UUID 字段、对象类和分页行为上都可能不同。

配置后不要急着点全量同步,先做连接测试和认证测试:
Test connection
Test authentication
再做小范围验证:
- 选择一个测试用户,确认能在 Keycloak 用户列表中看到。
- 用该用户登录 Keycloak Account Console。
- 修改 LDAP 侧字段,观察 Keycloak 是否按预期同步。
- 如果启用了写回,再用专门测试用户验证改密或属性更新。
8. 密码策略和自助改密#
Keycloak 的密码策略在 Realm 级别配置。建议别把策略一次拉满,先匹配现有组织要求,再用真实登录流程验证用户体验。
常见策略:
| 策略 | 建议 |
|---|---|
| Length | 先设置最低长度 |
| Digits / Lowercase / Uppercase | 按组织密码规范启用 |
| Special chars | 启用前确认移动端和输入法体验 |
| Not username | 建议开启 |
| Password history | 有合规要求时开启 |
| Hashing iterations | 按 Keycloak 当前默认和性能压测决定 |
密码策略页用于声明 Realm 级规则。每新增一条规则,都要用测试用户完整走一次登录和改密流程。

自助改密依赖两个部分:
- Account Console 可访问。
- Required Actions 或用户动作允许
Update Password。
Required Actions 决定用户何时被要求更新密码、邮箱或资料。自助改密要和 Account Console、LDAP 写回模式一起验证。

如果用户来自 LDAP,还要额外确认 LDAP Provider 的 Edit mode。只读模式下,Keycloak 不能把密码写回 LDAP;可写模式下,也要确认 Bind 账号有修改密码权限。
这类能力建议用测试用户做完整闭环:
登录 -> 进入 Account Console -> 修改密码 -> 退出 -> 用新密码重新登录
9. 身份验证和客户端入口#
Keycloak 后台里还有身份提供者、认证流程和 Client 入口。它们和 LDAP 不是同一层:
- LDAP User Federation 负责“用户从哪里来”。
- Identity Provider 负责“是否信任外部 IdP 登录”。
- Authentication Flow 负责“登录过程怎么走”。
- Client 负责“业务系统怎么接入 Keycloak”。
这些入口后续会承载业务系统接入。不要在 LDAP 首次接入时同时大改认证流程和 Client 配置,排障成本会明显上升。

上线前不要把这些配置混在一次变更里。先把用户目录和基础登录跑通,再逐个接入业务 Client,更容易定位问题。
10. 验证矩阵#
Keycloak 这类身份服务,不能只看容器 running。至少做下面这些验证:
| 场景 | 验证动作 | 通过标准 |
|---|---|---|
| 服务健康 | curl http://127.0.0.1:9000/health/ready | 返回 ready |
| 管理台登录 | 使用自建管理员登录 | 能进入目标 Realm |
| 临时账号收口 | 删除 bootstrap 临时账号 | 临时账号无法登录 |
| SMTP | 发送测试邮件 | 收件箱收到邮件 |
| LDAP 连接 | Test connection | 管理台提示成功 |
| LDAP 认证 | Test authentication | Bind 账号认证成功 |
| LDAP 用户同步 | 导入或同步测试用户 | 用户出现在 Keycloak |
| 普通用户登录 | LDAP 测试用户登录 | 能进入 Account Console |
| 自助改密 | 测试用户修改密码 | 新密码生效,旧密码失效 |
| 业务接入 | 测试 OIDC Client 回调 | 登录后回到业务系统 |
日志侧同步看三处:
docker compose logs --tail=200 keycloak
docker compose logs --tail=100 postgres
curl -fsS "http://127.0.0.1:9000/metrics" | head
11. 备份、升级和回滚#
Keycloak 的关键状态主要在数据库。Realm 配置可以导出,但不要把导出文件当作唯一备份。
变更前:
pg_dump -Fc -h postgres.example.internal -U keycloak keycloak > keycloak-before-change.dump
docker compose config > compose.rendered.before.yaml
导出 Realm 作为配置参考:
docker exec -it keycloak \
/opt/keycloak/bin/kc.sh export \
--dir /tmp/keycloak-export \
--realm master
回滚优先级:
- 如果只是 Realm 配置改错,优先在管理台回退具体配置。
- 如果 LDAP/SMTP 改错,回滚 Provider 或 Realm Email 配置,不动数据库。
- 如果升级后启动失败,先回退镜像版本和 Compose 配置。
- 如果数据库迁移已经发生,按备份恢复数据库;这一步要停服务并评估数据损失窗口。
12. 常见问题#
后台登录后一直跳转或回调地址不对
先查 KC_HOSTNAME、反向代理外部地址、KC_PROXY_HEADERS 和 X-Forwarded-* 头。Keycloak 对外地址应和用户浏览器看到的地址一致。
LDAP Test connection 成功,但用户登录失败
连接成功只说明网络和 Bind DN 可用。继续查 Users DN、Username LDAP attribute、搜索范围、用户 objectClass,以及是否启用了错误的认证流程。
用户能登录,但不能自助改密
确认用户是否来自 LDAP。如果 LDAP Provider 是只读,Keycloak 无法写回密码。即使是可写,也要确认 Bind 账号有改密权限。
邮件测试成功,但重置密码邮件收不到
检查 Realm Email 配置、用户邮箱字段、Required Action、垃圾邮件策略,以及 SMTP 服务是否限制发件人地址。
是否要把 LDAP Provider 配置写成脚本
初期可以用管理台配置,稳定后再导出 Realm 或用 Admin CLI/Terraform 管理。不要在还没跑通语义时先写自动化,否则只是把错误固化。
13. 可复用原则#
这次整理下来,Keycloak 部署最重要的不是 Compose 文件,而是配置收口顺序:
- 先让服务以正确主机名和数据库启动。
- 再替换临时管理员,收紧后台入口。
- 再配置 SMTP 和 LDAP,分别验证通道。
- 然后再打开密码策略、自助改密和业务 Client。
- 每一步都保留回滚点,避免身份系统变成“一改全炸”的大变更。
这个顺序不花哨,但很适合内部身份服务。身份系统一旦接入多个业务,后续每个配置项都应当能解释来源、影响范围和验证方式。
