Skip to content

필사 모드: Keycloak 26.7 — SCIM 升级为预览版,无需外部 Infinispan 的多集群 v2,以及升级中容易踩的坑

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

引言 — 每季度一个小版本,这次轮到 26.7

Keycloak 最近大约每三个月发布一个小版本(minor)。按 GitHub 发布日期算,26.5.0 是 2026 年 1 月 6 日,26.6.0 是 4 月 8 日,26.7.0 则是 7 月 9 日发布的。多数小版本翻一遍发布说明就能了事,但这次对运维来说值得多留意 —— 两个等了很久的功能(SCIM、无需外部缓存的多集群)都进入了预览阶段,升级指南里 breaking/notable 的清单也格外长。

本文是对照官方发布说明与仓库里的原始 adoc 文档(发布说明升级指南),再加上功能开关的真正定义所在地 Profile.java,整理出的运维视角解读。如果你还不熟悉 Keycloak 26 的架构本身,建议先看Keycloak 26 架构深度解析

SCIM API — 悬而未决四年的议题进入核心(预览版)

SCIM(System for Cross-domain Identity Management)是一种通过标准 REST API 在系统之间读写用户、群组等身份资源的协议(模式定义在 RFC 7643,协议定义在 RFC 7644)。在 Okta 或 Entra ID 这类商用 IdP 里这被视为理所当然的功能,但 Keycloak 核心一直没有。2022 年 8 月开的那个请求支持 SCIM 的 issue已经攒了 300 个反应且至今仍是打开状态,这段时间这个空白一直靠 scim-for-keycloak 这类第三方扩展来填补。

这一次,这个空白开始在核心中被填上。用代码追一下时间线是这样的 —— scim-api 功能开关在 26.6.0 的 Profile.java 中作为 experimental 悄悄加入(26.6.0 的发布说明里完全没有提到),随后在 26.7.0 中被升级为预览版。它默认关闭,需要用 --features=scim-api 打开,打开之后还得在 realm 设置里逐 realm 再次开关。

根据管理指南中的 SCIM 章节,实现范围如下。

  • 用户、群组的创建/查询/更新/PATCH/删除全套操作,以及群组成员管理
  • 完整的 SCIM 过滤语法与分页
  • 通过 Enterprise User 扩展(RFC 7643 第 4.3 节)和 User Profile 属性映射实现的自定义 schema 扩展
  • schema 发现端点

端点按 realm 开放。

/realms/<realm-name>/scim/v2/ServiceProviderConfig
/realms/<realm-name>/scim/v2/ResourceTypes
/realms/<realm-name>/scim/v2/Schemas
/realms/<realm-name>/scim/v2/Users
/realms/<realm-name>/scim/v2/Groups

权限模型没有新建,而是复用了和 Admin REST API 相同的 realm-management 角色。写用户需要 manage-users,读取需要 view-users,搜索需要 query-users/query-groups —— 如果已经为 Admin API 配置了服务账号,无需额外设置 SCIM 就能用。调用只允许 confidential 客户端,public 客户端会被拒绝。

设计上值得一提的是对管理员资源的保护。SCIM 客户端通常带着广泛的管理权限运行,因此文档明确防范了这样的场景:一个被攻破的配置客户端删除管理员账户,或把用户塞进管理员组 —— 通过 SCIM 查询带有管理角色的用户、群组时,只会返回最小化的表示(大致是 id、schemas、userName),写操作则会被 403 拒绝。管理员账户仍然只能通过 Admin 控制台和 Admin REST API 操作。

诚实地说清楚边界 —— 这次落地的只是 Keycloak 成为 SCIM 服务器这一个方向。 HR 系统或身份治理平台向 Keycloak 增删用户的入站配置(inbound provisioning)靠这个就够了。反过来,Keycloak 作为 SCIM 客户端从外部 SCIM 提供方联合用户过来,这件事还在另一个尚未关闭的 issue 里,文档也只是把来自外部 SCIM 服务提供方的用户联合、以及基于推送的实时事件列为未来版本的计划。从 Keycloak 向下游应用推送的出站配置(outbound provisioning)同样不在这次范围内 —— 那仍然是扩展的地盘。而且预览版就是预览版:不受支持,最终形态也可能变化。

多集群 v2 — 不再需要外部 Infinispan(预览版)

到目前为止,Keycloak 的多站点高可用(v1)需要为跨站点会话复制单独部署和运维一套外部 Infinispan(Data Grid)集群,还需要面向自动故障转移的、与厂商绑定的 fencing 基础设施 —— 这正是Keycloak HA 集群指南里讲过的那套结构。运维过的人都知道,为了让认证服务器高可用而去照看缓存集群这另一套分布式系统,成本并不小。

26.7 的多集群 v2 把这个外部依赖整个拿掉了。架构变成了这样。

  • Keycloak 实例之间通过内置的 Infinispan 缓存直接跨集群连接。
  • 同步复制的数据库成为唯一的事实来源(single source of truth)。功能开关取名为 stateless 正是因为这个 —— 按 Profile.java 里的定义,认证会话、动作令牌、登录失败数据都存进数据库,让多个集群仅靠数据库就能连接在一起。
  • 跨站点的缓存失效通过基于数据库的 outbox 模式处理。
  • 负载均衡器无需外部 fencing 就能检测站点宕机。

光听到这里,可能会觉得连地理级 DR 都能做到,但官方指南把约束钉得很死,原样照搬如下。

  • 它只面向单一区域,或延迟同等低的环境。 同步复制的高可用数据库是必须的,集群到数据库之间的读写/提交延迟建议低于 5ms、必须低于 10ms。不要期待跨大洲的主动-主动式 DR。
  • 团队定期测试的配置(厂商自测)是:同一 AWS 区域内两个单可用区的 OpenShift(ROSA HCP)集群,加上一个带跨可用区同步复制 leader 的 Aurora PostgreSQL 17.5,再加上 AWS Global Accelerator,测试负载是 100 万用户、每秒 300 个请求。超出这个范围的规模,文档明确要求自行验证。
  • 根据故障场景不同,可能出现数分钟的停机时间,视数据库厂商而定也可能需要人工介入。节点故障检测在默认设置下不到一分钟。

从运维角度再补一句 —— 在 Profile.java 中,这个功能被声明为 FeatureUpdatePolicy.SHUTDOWN。也就是说,开关这个功能标志时无法滚动更新,需要整个集群关停。这不是那种能无停机地塞进已经在跑的生产环境里的功能。

总结一下,v2 是"去掉了外部 Infinispan 运维的区域内多集群可用性",而不是"相距遥远的两个数据中心"。作为交换得到的东西很明确 —— 需要管理的分布式系统少了一套,对 Kubernetes 或 AWS 这类特定环境的依赖也消失了。如果负载落在测试范围内,且组织有能力以同步复制方式运维数据库,这是一笔值得用来换掉 v1 运维复杂度的交易。

顺带一提。打标签那一刻的发布说明原文有一处不一致 —— 在亮点里把这个功能标为预览版,而在正文标题里写成了 experimental(main 分支上已经统一整理为预览版),而代码里的 Profile.java 从一开始就是 PREVIEW。发布说明和代码对不上的时候,以代码为准。

Organizations — 多租户委托变得可行

正如多租户 SaaS SSO 架构一文所讲,Keycloak 的 Organizations 功能是在单个 realm 内管理多个租户(组织)。但到目前为止,管理组织需要 manage-realm 这个高权限角色 —— 相当于把整个 realm 的管理权限交给了租户管理员,说是"委托"都有点名不副实。

26.7 修正了这一点。

  • 新增了三个专属的 realm 管理角色: manage-organizations(组织的完整读写)、view-organizations(只读)、query-organizations(仅列表/搜索)。和现有的 query-users/query-clients 是同一路数。manage-realm 出于向后兼容,仍然隐含组织管理权限。
  • 组织成为 Fine-Grained Admin Permissions 下的一级资源类型。可以创建只管理单个组织的委托管理员,而且当 FGAP 启用时,组织成员查询也会遵循用户级权限,只返回调用者有权查看的成员。
  • 组织群组现在可以映射 realm/client 角色。给组织群组挂一次角色,就会自动反映到全体成员的 realm_access/resource_access 声明中;打开 Organization Group Membership 协议映射器的相关选项,还能按组织把这些整理进 organization 声明里。也就是说,对于成百上千人规模的租户,应该按群组管理角色,而不是给每个成员单独挂。

还带来了一处 breaking 变更。组织成员列表 API 现在默认返回 brief 表示。需要完整用户表示时必须通过查询参数明确指定。

GET /admin/realms/{realm}/organizations/{id}/members?briefRepresentation=false

组织邀请列表里 email/firstName/lastName 的过滤方式也从部分匹配改成了忽略大小写的精确匹配 —— 如果需要部分匹配,指南建议改用 search 参数。如果有自动化依赖这些 API,先确认响应格式和过滤行为是否变了。

升级中容易踩的坑

以下是从这次升级指南里挑出的、运维人员实际可能踩到的坑。完整清单参见升级指南原文

PostgreSQL 异步提交默认开启。 只更新 persisted user sessions、client sessions、login failures、events 这类易失表的事务,现在会用 PostgreSQL 的异步提交(async commit)处理(登出仍然强制同步提交)。这是出于性能考虑的选择,但必须准确理解它的含义 —— 根据 PostgreSQL 文档,异步提交会在 WAL 刷盘之前就返回提交成功,一旦服务器崩溃,这段时间内的提交就会丢失。丢失窗口最多是 wal_writer_delay(默认 200ms)的三倍。数据不会损坏,丢的只是崩溃前不到一秒钟的会话、事件写入,对用户来说无非是重新登录一次。不过值得一提的是 events 表也包含在内 —— 意味着崩溃前那一刻的登录事件可能从审计日志里消失,如果所在环境对审计要求严格,就要判断是否用 --spi-connections-jpa--quarkus--async-commit=false 选择退出。

X.509 客户端认证新增了 CA Subject DN 选项,而且事实上成了必需项。 如果用 mTLS 认证客户端,管理控制台现在会强制要求指定信任锚 CA 的 subject DN。现有配置暂时还能正常工作,但从下一个大版本开始会加入服务端校验,没有这个选项的创建/更新/导入都会被拒绝。用正则表达式匹配证书、而不是精确 DN 的那个选项,也同时被标记为弃用。如果是在 TLS 终止代理后面通过请求头传递证书的架构,也需要重新确认 truststore 是否配置好了对客户端证书链的校验。

自助注册流程发生了变化。 如果 realm 同时启用了自助注册和 Verify Email,注册表单里的密码字段默认会消失。用户只注册资料,验证邮箱之后才设置密码(或 OTP、passkey)。这把"用未验证的邮箱先创建凭证"的顺序整个反过来了,是一处会牵动注册 UX 以及全部文档、截图的变更。有开关可以恢复旧行为,但已被标记为 deprecated。

其余的压缩罗列如下。

  • 关闭超时从 1 秒延长到 10 秒,而且会等分布式缓存完成再平衡之后才真正关闭。请与编排器的终止宽限期(如 terminationGracePeriodSeconds)对齐。可通过 shutdown-timeout 选项调整。
  • 新生成的客户端密钥现在固定为 86 个字符(为了保证 HS512 所需的熵)。现有密钥不受影响,但如果存储密钥的地方有最大长度限制,需要放宽。
  • 会话 cookie 的哈希从 SHA-256 改为 SHA-384,新生成的 aes-generated 密钥默认长度从 128 位提高到 256 位(都是为了对齐 CNSA 2.0,既有会话、既有 realm 不受影响)。
  • 在 26.5.4 中一引入就被标记为 deprecated 的 view-system 管理角色,出于安全原因被移除了。服务器级别的信息查询现在仅限 master realm 中拥有 manage-realm 的用户。
  • FreeMarker 默认版本升级到 2.3.32。依赖旧式指令或 ?api 这类内部访问方式的自定义登录主题,升级后必须测试。登录主题的按钮布局也变了。
  • DPoP 在 implicit/hybrid 流程中会被拒绝。因为在访问令牌经由前端通道下发的流程里,sender-constrained 模型本身就不成立,所以这种组合现在会直接报错。
  • Admin REST API 按 ID 查询用户时,服务账号不再包含在结果里;Identity Provider 的 alias 在创建后不可再修改。
  • Authorization Services 的资源 URI 模板校验变严格了。像路径中间使用通配符这种原本就不生效的写法,现在在创建/更新时会被拒绝,因此指南甚至提供了一条升级前的预检查询,用来审查资源的 uris 字段。

弃用雷达 — 现在就该关掉或迁移的东西

  • Identity Brokering API V1 已被标记为 deprecated。 替代方案 V2 不再给用户挂 broker 角色,而是改为按客户端授权(一个允许获取外部令牌的开关 + IdP 白名单),只允许 confidential 客户端,并使用 POST 加标准 JSON 响应。V2 在这个版本里已受支持,但默认关闭;V1 目前仍然默认开启 —— 未来版本会移除 V1、把 V2 变成默认,如果有应用在读取外部 IdP 令牌,现在就该开始迁移到 V2。
  • Twitter Identity Broker 已预告将被移除,原因是它依赖遗留的 OAuth 1.0a 端点。迁移方式是针对 X 的 OAuth 2.0 端点配置通用的 OAuth v2 IdP;如果没在用,现在就可以用 --features-disabled=twitter-broker 关掉。
  • OIDC 客户端的 Bearer-only 开关已被标记为 deprecated。 它已经从控制台里消失,只能通过 REST 配置,而这条路径也将被封堵。用无授权类型(grantless)的 OIDC 客户端可以达到同样的目的。
  • WebAuthn 策略中的 Require Discoverable Credential 选项已被标记为 deprecated。 新的 Discoverable Credential 选项直接支持 WebAuthn 规范里的 residentKey 值(required/preferred/discouraged)—— 用 Yes/No 硬性开关表达不出来的 preferred,对于 iCloud 钥匙串、Google 密码管理器、1Password 这类 passkey 提供方的兼容性很重要。passkey 生态目前走到哪一步,Passkey 凭证交换整理一文讨论过。
  • SHA-1 将在 Keycloak 27 中被全面移除。 依据是 NIST 的 SHA-1 退役计划(2030 年完全退役),升级指南明确要求把 Keycloak 内部的 SHA-1 视为已经退役,现在就迁移到 SHA-2/SHA-3 系列。如果 SAML 签名算法或某些老旧对接还在用 SHA-1,得在 27 发布前处理掉。

其余的标准实验 —— 各写一段

这次发布里带 experimental 标签的标准实现异常多。全部默认关闭,阅读时请记住 experimental 比预览版还要早一个阶段。

  • Shared Signals Framework 发送方(ssf):把登出、凭证变更、账户禁用这类安全事件,以带签名的 SET(RFC 8417)形式近实时推送给下游。支持 CAEP 1.0 和 RISC 1.0 规范,支持 push(RFC 8935)和 poll(RFC 8936)两种投递方式,并用持久化的 outbox 设计确保重启也不丢事件。它瞄准的是"要等到令牌刷新才知道会话已失效"这个老问题。
  • AuthZEN Evaluation API(authzen):实现了 OpenID AuthZEN 1.0 中的 PDP 角色。发送 subject/resource/action,就能用已有的 Authorization Services 策略返回 permit/deny。单次评估和批量评估都支持。
  • Identity Assertion JWT Grant(identity-assertion-jwt):ID-JAG 草案的部分实现,让跨组织的认证服务器之间无需重新认证就能拿到令牌。目前只实现了接收方这一侧,完整流程还跑不通。
  • 令牌交换委托(token-exchange-delegation):面向网关代表用户在下游行事的委托场景,带 delegation 参数化的 scope 需要用户同意,并且每次刷新都会重新评估。令牌交换的背景可参考RFC 8693 令牌交换与委托
  • Admin API v2(client-admin-api:v2):作为带严格校验和准确 OpenAPI 规范的新管理 API 的第一个资源,客户端管理进来了。Operator 用它通过 KeycloakOIDCClient/KeycloakSAMLClient 自定义资源声明式地管理客户端。这算是对现有 Admin REST API 校验松散、规范不准确这个老问题给出的第一步回应。

从预览版升级为正式支持的只有一项:SAML 客户端的 step-up 认证。原本只有 OIDC 才有的认证上下文要求,现在也向 SAML SP 开放了。

那么,什么时候升级,该开什么

综合起来,我会这样判断。

  • 升级本身是个小版本,上面列的东西都在可控范围内,没有理由拖延。但升级前建议列一份清单,把这四五件事过一遍:补上 X.509 CA Subject DN、客户端密钥长度限制、测试自定义主题、判断是否要为异步提交选择退出、以及自助注册流程的变化。
  • SCIM 预览版很值得在预发环境里打开试试。特别是那些一直用 Admin REST API 写配置脚本的组织,标准协议加上既有权限模型再加管理员保护,这个方向从长期看是对的。但生产环境依赖应该等到 preview 升级为 supported 之后,而且设计时要假定 Keycloak 作为客户端(外部 SCIM 联合、向下游推送)这条路目前还不存在。
  • 多集群 v2 对于已经厌倦了运维 v1(外部 Infinispan)、又能满足单一区域加同步复制数据库这个条件的组织来说,是一次实实在在的简化。反过来,如果地理级 DR 是硬性需求,这个功能就不是答案 —— 低于 10ms 的数据库延迟要求划出了这条界线。开关时需要整体关停这一点,也要提前纳入计划。
  • 三个组织管理角色不是预览版,而是这次发布里安静但扎实的收获。如果之前一直把 manage-realm 交给租户管理员,现在就该收回来,收窄到 manage-organizations 及以下 —— 这是这次升级里能拿到的、最确定的一项安全改进。

结语

只看头条(SCIM、多集群 v2)的话,Keycloak 26.7 像是一场预览版的展会,但背后的方向是一致的 —— 把第三方扩展和外部基础设施一直在填补的空白,吸收进核心的标准实现(SCIM、SSF、AuthZEN);拆分高权限角色(组织管理角色、移除 view-system);收紧过去的松散之处(X.509 CA DN、URI 模板校验、SHA-1 退役预告)。对于自托管 IdP 的运维者来说,这是个值得欢迎的方向,代价只是升级指南变长了而已。不要只读发布说明就了事,建议把升级指南当作清单认真过一遍。

参考资料

현재 단락 (1/81)

Keycloak 最近大约每三个月发布一个小版本(minor)。按 GitHub 发布日期算,26.5.0 是 2026 年 1 月 6 日,26.6.0 是 4 月 8 日,[26.7.0 则是 7...

작성 글자: 0원문 글자: 10,647작성 단락: 0/81