跳过正文
  1. 博客文章/

Docker Compose 部署 Keycloak 并接入 LDAP

·1010 字·5 分钟·
DevOps Identity Keycloak Docker-Compose LDAP PostgreSQL SSO DevOps
Zayn
作者
Zayn
专注 Kubernetes、CI/CD、可观测性等云原生技术栈,记录生产环境中的实战经验与踩坑复盘。
目录
生产变更复盘 - 这篇文章属于一个选集。
5: 本文
Keycloak 部署本身不复杂,真正容易出问题的是“第一次进后台以后怎么收口”:临时 admin 要替换,SMTP 要能发验证邮件,LDAP 要同步得可控,密码策略和自助改密也要提前验证。
文中命令和配置使用 sso.example.comldap.example.internaldc=example,dc=internalregistry.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 FederationLDAP 连接、搜索 DN、映射和同步策略可先管理台配置,稳定后再导出
ClientOIDC/SAML 应用、回调地址、Client Secret建议单独变更和审计

官方文档里,Keycloak 容器使用 KC_DBKC_DB_URLKC_DB_USERNAMEKC_DB_PASSWORD 等环境变量配置数据库;初始管理员可用 KC_BOOTSTRAP_ADMIN_USERNAMEKC_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 或回收临时凭据。这样能避免恢复账号长期留在系统里。

删除 bootstrap 阶段使用的临时账号

5. 基础界面:中文和主题
#

Keycloak 的中文界面通常在 Realm 级别配置。路径是:

Realm settings -> Localization / Themes

建议至少确认两类配置:

配置建议
Internationalization开启后选择需要支持的语言
Default Locale内部用户为主时可设为 zh-CN 或 Simplified Chinese
Login theme没有定制主题时先保持默认
Account theme自助改密依赖 Account Console,先不要关闭

先从 Realm 设置页进入主题和国际化配置,确认登录页、账号页和管理台使用的是预期主题。

主题和语言入口

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

Realm 语言配置

如果团队里同时有中文和英文用户,不要强行只保留一个语言;保持语言切换入口可见,减少登录页支持成本。

6. 邮件配置:把 GitLab 示例改成 Keycloak 字段
#

很多系统都有自己的 SMTP 配置写法,不能把 GitLab Omnibus 的 gitlab_rails['smtp_*'] 片段直接搬到 Keycloak。Keycloak 的邮件配置在 Realm 里维护:

Realm settings -> Email

建议按字段理解:

Keycloak 字段示例值说明
Hostsmtp.example.comSMTP 服务器
Port465587取决于 TLS/STARTTLS 策略
Fromsso@example.com用户收到邮件时看到的发件人
From display nameExample SSO可读名称
AuthenticationEnabled大多数 SMTP 都需要
Usernamesso@example.comSMTP 账号
Password不写入文档使用邮件服务授权码或专用密码
Enable SSL端口 465 常见为开启按邮件服务要求
Enable StartTLS端口 587 常见为开启不要和 SSL 混用错

先进入 Realm 的 Email 配置页,确认当前配置属于目标 Realm,而不是误改到 master 或其他测试 Realm。

邮件配置入口

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

发件人和 SMTP 字段

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

测试邮件结果

7. LDAP User Federation
#

LDAP 接入建议从只读或受控写入开始,不要一上来就让 Keycloak 全量写回目录服务。路径是:

User federation -> Add LDAP provider

从 User Federation 入口查看现有用户源。这里能看到当前 Realm 是否已经接入 LDAP,以及后续同步是否走同一个 Provider。

User Federation 入口

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

新增 LDAP Provider

关键配置可以拆成三组。

连接和认证:

字段示例值说明
VendorOtherActive Directory按目录类型选择
Connection URLldap://ldap.example.internal:389能用 LDAPS 时优先 ldaps://...:636
Bind typesimple常见内部 LDAP 绑定方式
Bind DNcn=keycloak,ou=svc,dc=example,dc=internal使用专用服务账号
Bind credential不写入文档只放 Secret
Use Truststore SPI按证书链策略设置LDAPS 时重点验证

连接和认证页决定 Keycloak 能否访问目录服务。先用只读服务账号完成连接测试,再评估是否需要写回能力。

LDAP 连接和身份验证

搜索和属性:

字段示例值说明
Edit modeREAD_ONLYWRITABLE先从只读开始更稳
Users DNou=users,dc=example,dc=internal用户搜索根 DN
Username LDAP attributeuid登录名字段
RDN LDAP attributeuid新建用户时的 RDN 字段
UUID LDAP attributeentryUUID唯一标识字段,AD 通常不同
User object classesinetOrgPerson, organizationalPerson按目录结构设置
Search scopeOne LevelSubtree目录层级深时用 Subtree
Pagination开启大目录同步时避免一次拉取过多

搜索配置决定 Keycloak 能看到哪些用户。Users DN、对象类和唯一标识字段要与目录实际结构一致,不能只照抄示例。

LDAP 搜索和属性字段

同步策略:

配置建议
Import users开启,便于 Keycloak 缓存和映射
Sync Registrations一般关闭,避免 Keycloak 反向创建 LDAP 用户
Full sync period按用户规模设置,不要过短
Changed users sync period变更频繁时开启增量同步
Batch size按 LDAP 性能和目录规模设置

同步配置影响目录压力和用户可见性。用户量不明时,先小范围手动同步,再决定全量和增量同步周期。

LDAP 同步设置

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

LDAP 厂商和基础选项

配置后不要急着点全量同步,先做连接测试和认证测试:

Test connection
Test authentication

再做小范围验证:

  1. 选择一个测试用户,确认能在 Keycloak 用户列表中看到。
  2. 用该用户登录 Keycloak Account Console。
  3. 修改 LDAP 侧字段,观察 Keycloak 是否按预期同步。
  4. 如果启用了写回,再用专门测试用户验证改密或属性更新。

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 写回模式一起验证。

Required Actions 和自助改密

如果用户来自 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 authenticationBind 账号认证成功
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

回滚优先级:

  1. 如果只是 Realm 配置改错,优先在管理台回退具体配置。
  2. 如果 LDAP/SMTP 改错,回滚 Provider 或 Realm Email 配置,不动数据库。
  3. 如果升级后启动失败,先回退镜像版本和 Compose 配置。
  4. 如果数据库迁移已经发生,按备份恢复数据库;这一步要停服务并评估数据损失窗口。

12. 常见问题
#

后台登录后一直跳转或回调地址不对

先查 KC_HOSTNAME、反向代理外部地址、KC_PROXY_HEADERSX-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。
  • 每一步都保留回滚点,避免身份系统变成“一改全炸”的大变更。

这个顺序不花哨,但很适合内部身份服务。身份系统一旦接入多个业务,后续每个配置项都应当能解释来源、影响范围和验证方式。

14. 参考
#

生产变更复盘 - 这篇文章属于一个选集。
5: 本文

相关文章

用 Docker Compose 部署 Scrutiny:NVMe 健康监控的最小可用方案
·772 字·4 分钟
SRE NVMe SMART SRE DevOps +3
华为 UPS2000 接入 NUT Server:编译 huawei-ups2000 驱动并完成联动
··2156 字·11 分钟
SRE NUT UPS Linux SRE +4
生产 DNS 集群平滑升级复盘:dnsdist 与 Technitium 的滚动变更
·989 字·5 分钟
SRE DNS SRE DevOps Dnsdist +3