数据库服务账号可以很简单,比如只是一个使用单独密码或证书进行身份验证的用户。较高级的用户可能希望设置此类账号,使其权限范围可通过 SET ROLE 动态调整,从而无需注销或重新加载内容,即可在不同 profile 之间快速切换。
概述
SET ROLE 可用于在会话期间动态限定服务账号的权限范围。其原理是将用户的有效权限限制为仅限于已激活角色所授予的权限。这种方法有几个优点:
- 服务账号可以被分配多个角色,但只需激活特定查询所需的那个角色。
- 如果服务账号被攻破,攻击者也只能使用当前激活角色的权限。
- 单个账号可以通过切换角色来执行不同任务,而不必为每项任务分别使用单独的凭据。
- 只需修改一个角色,而无需逐个更新用户,即可为整类服务账号更新权限。
- 日志可以记录查询期间具体激活的是哪个角色,从而为安全审计提供更清晰的上下文。
在实践中,你需要:
- 设计用于定义允许范围边界的角色 (如 read_only、maintenance 等)
- 将这些角色授予服务账号
- 在建立连接时,通过
SET ROLE(或 role 参数) 选择激活的角色,从而限制该会话可执行的操作
设置服务角色
将角色授予服务账号
首先,创建具有所需特权/设置的角色,然后将其授予服务账号。
CREATE ROLE read_only_role;
GRANT SELECT ON db1.* TO read_only_role;
CREATE ROLE maint_role;
GRANT SELECT, INSERT, ALTER on db1.* TO maint_role;
GRANT read_only_role, maint_role TO service_user;使用 SET ROLE 定义权限边界
在会话开始时,服务账号可以选择激活哪些角色:
-- 此会话仅启用只读权限
SET ROLE read_only_role;或:
-- 启用所有已授予角色(完整权限)
SET ROLE ALL;SET ROLE 会为当前用户启用角色;生效的特权是所有激活角色特权的并集,再加上直接授予该用户的任何特权。
你也可以禁用所有角色:
SET ROLE NONE;或启用多个角色:
SET ROLE read_only_role, maint_role;当前激活角色可通过 system.current_roles 查看。
为服务账号设置默认角色
为确保服务账号始终以受限模式启动,请配置默认角色:
SET DEFAULT ROLE read_only_role TO service_user;或
SET DEFAULT ROLE ALL EXCEPT maint_role TO service_user;通过 HTTP / 以编程方式使用 SET ROLE
如果服务账号通过 HTTP 连接,则不能将 SET ROLE; SELECT … 作为多条语句发送。应改为将角色作为查询参数传递:
curl "https://host:8123?user=service_user&password=...&role=read_only_role" \
--data-binary "SELECT * FROM db1.table1"?role=… 等同于在该语句之前执行 SET ROLE read_only_role。多个角色参数的行为类似于 SET ROLE role 1, role 2。
一些驱动程序 (例如用于 Python 的 ClickHouse Connect) 也提供角色设置,并会随每个请求一并发送,服务器会将其用作会话角色。