跳转到主内容
跳转到主内容

JWT 身份验证

ClickHouse Cloud only

ClickHouse 可以使用 JSON Web Token (JWT) 对用户进行身份验证。与 LDAPKerberos 等其他外部身份验证器不同,JWT 身份验证不会校验预先存在用户的身份。相反,它会根据嵌入在每个令牌中的声明动态创建临时用户。这些用户仅存在于内存中,其访问权限由令牌声明派生,并会在令牌过期后自动移除。

因此,JWT 身份验证与基于密码或证书的方法有本质区别:不存在 CREATE USER ... IDENTIFIED WITH jwt 语句,尝试这样做会引发异常。JWT 用户完全由令牌生命周期管理。

概述

身份验证流程如下:

  1. 客户端通过一种受支持的传输机制提供已签名的 JWT (HTTP Authorization: Bearer 请求头、TCP 原生协议或 gRPC jwt 字段) 。
  2. ClickHouse 验证令牌签名。
  3. 验证必需的声明 (expiatisssubaud) 。
  4. 在内存中创建一个临时用户,其访问权限来自令牌声明中的 clickhouse:grantsclickhouse:roles,并与权限限制求交集。
  5. 当令牌过期时,后台垃圾回收任务会移除该用户。

令牌声明

必需的声明

提交给 ClickHouse 的每个 JWT 都必须包含以下声明:

ClaimDescription
alg签名算法 (请求头声明) 。支持的值:HS256RS256ES256
exp过期时间。用于设置临时用户的 valid_until
iat签发时间。用于防止同一身份重放较早签发的标记。
iss签发者。需与提供商预期的签发者匹配。
sub主体。会成为生成用户名的一部分。
aud受众。需与提供商预期的受众匹配。

使用基于 JWKS 的密钥解析时,还必须提供 kid (密钥 ID) 请求头声明。

JWKS 模式仅支持 RSA 密钥

虽然静态密钥提供商接受 HS256RS256ES256 中的任意一种,但基于 JWKS 的提供商只接受 ktyRSA 的 JWK (即使用 RS256 签名的标记) 。使用 HMAC (HS256) 或 EC (ES256) 密钥签名的标记无法通过 JWKS 端点验证,因此会被拒绝。

其他可识别的声明

声明说明
nbf生效时间下限。此声明不是必需的,但如果存在,则在该时间之前,标记会被拒绝。
jti保留。可出现在标记中,但当前不会被验证或使用。

可选声明

声明默认名称说明
授权clickhouse:grantsSQL GRANT 片段构成的 JSON 数组,例如 ["SELECT ON db.*", "INSERT ON db.table1"]。每个元素都会作为 GRANT 语句的主体进行解析。
角色clickhouse:roles要分配的角色名称的 JSON 数组,例如 ["analyst", "reader"]
如果您的身份提供商采用不同的命名约定,可以将默认声明名称重映射为自定义声明名称。

示例令牌的头部和载荷

{
  "alg": "RS256",
  "kid": "my-key-id"
}
{
  "iss": "https://idp.example.com",
  "sub": "jane.doe",
  "aud": "my-clickhouse-cluster",
  "exp": 1719504000,
  "iat": 1719500400,
  "clickhouse:grants": ["SELECT ON analytics.*", "INSERT ON analytics.events"],
  "clickhouse:roles": ["analyst"]
}

临时用户的行为

JWT 用户与普通 ClickHouse 用户在几个重要方面存在差异。

身份与命名

每个 JWT 用户都会获得一个基于 isssubaud 声明计算出的确定性 UUID。该 UUID 在多次登录之间是稳定的。用户即使用不同的令牌多次登录 (只要签发方、主体和受众相同) ,也始终会得到相同的 UUID。

不过,用户名是可变的。它的构造方式如下:

JWT::<issuer>::<audience>::<subject>::<claims_hash>

<claims_hash> 部分会在 clickhouse:rolesclickhouse:grants 声明发生变化时改变。这意味着,即使是同一身份,角色或授权组合不同的令牌也会生成不同的用户名。

访问权限

有效访问权限按如下方式计算:

effective_rights = permission_limit ∩ (token_grants ∪ token_roles)

其中,permission_limit 是作为上限配置的参考角色或用户所拥有的一组访问权限。令牌请求的任何超出该上限的权限都会被静默丢弃。

令牌时效

ClickHouse 会跟踪每个稳定身份最近一次成功通过身份验证的令牌的 iat (签发时间) 声明。如果提供的令牌其 iat 等于或早于已存储的值,服务器会复用现有的临时用户,而不会重新评估这些声明。这样可以防止较旧的令牌导致用户权限被降级。

生命周期与垃圾回收

临时用户会在令牌首次通过身份验证时创建,并在 valid_until (由 exp 推导而来) 到期后,由后台垃圾回收任务删除。GC 时间间隔由 gc_interval 参数控制 (默认值:5 分钟) 。

在两次 GC 运行之间,已过期的用户在 system.users 中可能仍然可见,但已无法再通过身份验证。

持久化访问分配

由于 UUID 是稳定的,因此你可以使用 SQL 语句将 settings profile、配额、行策略和列脱敏策略分配给 JWT 用户。这些分配会持久保存在访问控制存储中 (磁盘或 ZooKeeper) ,并且在令牌过期和重新进行身份验证后仍然有效。

通过用户当前的用户名来引用该用户:

ALTER SETTINGS PROFILE my_profile ADD TO 'JWT::ClickHouse::my-service-id::jane.doe::<claims-hash>';
注意

某个身份的用户名和 UUID 可在该用户处于活动状态时,从 system.usersnameid 列中查到。

请注意,ALTER USER 不能直接用于 JWT 用户,因为它们是只读的。要分配 settings profile、配额或策略,请使用上文所示的 ALTER SETTINGS PROFILEALTER QUOTAALTER ROW POLICY 语句。

与常规用户的差异

功能JWT 用户常规用户
创建根据令牌声明自动创建CREATE USER 语句
存储仅存于内存中 (临时)磁盘、ZooKeeper 或配置文件
CREATE USER ... IDENTIFIED WITH jwt不支持 (会引发异常)支持所有其他认证类型
ALTER USER / DROP USER不支持支持
备份与恢复不包含包含
用户名自动生成,会变化由管理员指定,固定不变
UUIDiss+sub+aud 确定性生成创建时随机生成
生命周期受令牌 exp 限制直到被显式删除
访问权限从令牌声明派生,并受权限上限限制通过 GRANT 显式授予
主机限制按提供商网络配置按用户的 HOST 子句
设置 profile可按 UUID 分配 (持久)可直接配置
配额和行策略可按 UUID 分配 (持久)可直接配置
默认角色不可配置可配置

SQL SECURITY DEFINER 视图

当临时 JWT 用户使用 SQL SECURITY DEFINER 创建视图时,服务器会自动为该用户创建一个持久化的影子副本,作为该视图的定义者。此影子用户具有以下特点:

  • 名称为 <original_jwt_username>:definer
  • 具有 NO_AUTHENTICATION (无法用于登录)
  • 保留视图创建时原始 JWT 用户所拥有的相同访问权限

这样可确保在临时用户的令牌过期且原始用户被垃圾回收后,视图仍可继续正常工作。

客户端用法

直接传递令牌

使用 clickhouse-client--jwt 标志,通过预先获取的令牌进行身份验证:

clickhouse-client --host your-instance.clickhouse.cloud --secure --jwt '<your_jwt_token>'
注意

--jwt 标志与 --user 互斥。指定 --jwt 时,用户名将从令牌中获取。

HTTP 接口

将该令牌作为 Bearer 令牌通过 Authorization 请求头发送:

curl -H 'Authorization: Bearer <your_jwt_token>' \
    'https://your-instance.clickhouse.cloud:8443/?query=SELECT+currentUser()'
注意

始终通过 HTTPS 传输 JWT。通过明文 HTTP 发送 Bearer 令牌会暴露给传输路径上的任何人,这无异于泄露凭证。

OAuth2 设备代码登录

clickhouse-client 支持通过 --login 标志发起交互式 OAuth2 设备代码流程。对于 ClickHouse Cloud 端点,客户端会自动执行令牌交换,以获取 ClickHouse 专用 JWT。令牌会在会话期间自动刷新且对用户无感知。获取新令牌后,客户端会自动重新连接。

clickhouse-client --host your-instance.clickhouse.cloud --login

ClickHouse Cloud 内置 JWT 身份验证器

每个 ClickHouse Cloud 服务都自带一个预定义的 JWT 身份验证器,SQL 控制台和 clickhouse-client--login 流程都会使用它。此身份验证器配置如下:

参数
iss (签发方)ClickHouse
aud (受众)服务 UUID (可在 Cloud 控制台 URL 中看到)
sub (主体)你的 ClickHouse Cloud 账户邮箱地址

该内置身份验证器的权限上限设置为 default_role 角色和 default 用户。这意味着,任何 JWT 用户的有效权限都会与这两个实体所拥有的授权取交集,因此令牌的权限绝不会提升到超出 default_roledefault 所允许范围之外。

你无需进行任何配置即可使用此身份验证器。创建服务时会自动为其预配。

服务器间通信

当查询被转发到另一个分片或副本时,JWT 令牌会包含在服务器间通信协议中。远程节点会独立对该令牌重新进行身份验证,并创建自己的临时用户。

故障排查

  • 未授予访问权限: 引用的角色或用户可能缺少所需的授权。请确保 clickhouse:roles 中引用的角色存在,并且包含相应的授权。
  • 令牌被拒绝: 请验证令牌中的 issaud 和签名算法是否符合 JWT 提供商的预期。如果使用 JWKS,请确保令牌的 kid 与提供商密钥集中的某个密钥匹配。
  • 用户在查询之间消失: 临时用户会在令牌过期后被移除。对于长时间运行的会话,请使用支持令牌刷新 (例如 --login 模式) 的客户端。
  • CREATE USER ... IDENTIFIED WITH jwt 失败: 这是预期行为。JWT 用户不能通过 DDL 创建,而是完全由令牌生命周期管理。