Clickhouse权限与访问控制设计
目录
作者声明:内容由AI辅助创作
本文使用 ChatGpt 辅助进行文章结构规划、配置及示例生成,由 Google gemini 辅助技术细节解释优化
所有配置均经过实际测试验证,但其中某些概念可能存疑,请自行判断。
信息
当前测试环境:
- 主节点:
Ubuntu 24.04 - 从节点:
Debian 13 ClickHouse server:25.11.2.24 (official build)
适用版本:ClickHouse 23+ / 25.x
适用场景:生产集群、多数据库、多团队、长期演进
非目标:OLTP 事务级权限模型
1. ClickHouse 权限设计的工程背景
1.1 ClickHouse 的定位决定了一切
| 数据库 | 设计目标 |
|---|---|
MySQL / PostgreSQL | OLTP(事务系统) |
ClickHouse | OLAP(分析系统) |
这意味着:
ClickHouse不是为频繁 UPDATE / DELETE 设计的ClickHouse的“安全边界”更多在 结构、资源、复制层面
2. 集群、Keeper 与权限的真实关系
2.1 ON CLUSTER 的真实含义
| |
ON CLUSTER 只意味着:
| 能力 | 是否 |
|---|---|
| 当前集群节点执行 DDL | ✅ |
| 新节点加入后自动存在 | ❌ |
| 元数据持续复制 | ❌ |
ON CLUSTER是“广播执行”,不是“持续复制”- 所有已配置的节点必须在线,否则
ON CLUSTER执行时会等待所有节点完成,从而导致执行失败
2.2 Keeper 对权限的影响
Keeper 负责:
- 分布式
DDL协调 Replicated表元数据- 副本状态
因此:
- 没有
Keeper,ON CLUSTER权限 / DDL 不可用 - 部分权限(
SYSTEM/DDL)隐含依赖 Keeper
3. 数据库是权限隔离的最小单元
3.1 为什么禁止使用 default 数据库?
- 所有用户天然可见
- 权限边界模糊
- 容易被误用
📌 规范要求:
| |
3.2 一个 clickhouse-server 应该有多少数据库?
原则:一个业务 / 团队 = 一个数据库
这是后续权限、审计、迁移的基础。
4. 数据库创建规范
4.1 两种数据库模式必须明确区分
模式一:Atomic Database(非持续复制)
| |
特点:
- 结构简单
- ❌ 新节点加入后需手动建库
适合: 👉 集群稳定、扩容极少
模式二:Replicated Database(推荐生产)
| |
特点:
- 数据库元数据存于 Keeper
- 新节点自动可见
- 扩容成本最低(全自动)
📌 这是“长期可演进集群”的推荐选择
5. 表级复制是“自动复制”的真正前提
5.1 标准建表规范
| |
关键结论:
- 是否自动复制 与 ON CLUSTER 无关
- 是否自动复制 完全取决于 ReplicatedMergeTree
5.2 关于 Replicated 路径(重要结论)
在 ClickHouse 23+ / 25.x 中:
| |
5.3 扩容时「自动复制」是如何发生的?
当你:
- 新增一台
ClickHouse节点 - 加入
cluster.xml - 配置相同的
Keeper - 启动
clickhouse-server
- 新增一台
会发生:
Replicated Database:- 自动看到
dbtest数据库
- 自动看到
ReplicatedMergeTree表:- 自动创建
replica - 自动拉取历史数据
- 自动创建
必要时可手动触发:
| |
6. ClickHouse 集群架构设计与元数据管理
6.1 传统模式(Atomic 数据库 + 手动路径管理)
- 数据库创建:使用
Atomic引擎(不带路径参数)。 - 表创建:必须指定路径参数。
1 2 3 4 5 6 7-- 数据库只是个文件夹(Atomic 默认) CREATE DATABASE testdb ON CLUSTER default_cluster; -- 表必须明确告诉 Keeper 它的位置 CREATE TABLE testdb.test_table (...) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/dbtest/test_table', '{replica}') ORDER BY id; - 优缺点
- 元数据存储:散落在每个节点的本地磁盘。
- 同步机制:依赖
ON CLUSTER语句进行即时广播。如果节点在执行时离线,则该节点不会创建表。 - 路径定义:必须手动在 SQL 中指定 ZooKeeper 路径,运维成本随表数量线性增长
此项适用于:小规模集群、表数量不多、扩容频率极低
6.2 元数据托管模式(Replicated 数据库 + 自动元数据托管)
- 数据库创建:使用
Replicated引擎, 携带ZK路径, 表创建不携带ZK路径1 2 3 4 5 6 7 8 9 10 11 12 13-- 1. 创建高可用同步库 (指定库级 ZK 根路径) -- Replicated('/clickhouse/databases/<db_name>', '{shard}', '{replica}'); CREATE DATABASE dbtest ON CLUSTER default_cluster ENGINE = Replicated('/clickhouse/databases/dbtest', '{shard}', '{replica}'); -- 2. 创建表:严禁指定参数,实现全自动托管 CREATE TABLE dbtest.order_items ON CLUSTER default_cluster ( order_id UInt64, price Float64 ) ENGINE = ReplicatedMergeTree ORDER BY order_id; - 优缺点
- 元数据存储:集中化存储在
Keeper/ZooKeeper中。 - 同步机制:新节点启动时自动拉取
Keeper上的库表定义。无需关心ON CLUSTER是否送达,具有自愈能力。 - 路径定义:由数据库引擎根据
UUID自动分配路径,消灭了手动拼接路径导致的碰撞风险。 - 扩容时只需配置新节点的
macros.xml并启动,数秒内所有库、表自动克隆完成,运维实现零介入。
- 元数据存储:集中化存储在
此项适用于:大规模集群、表数量多、扩容频繁
7. 权限模型总览(核心结构)
flowchart LR
User[User
(用户)] -->|赋予| Role[Role
(角色)]
Role -->|赋予| Privilege[Privilege
(权限)]
Privilege -->|作用于| DB[Database/Table
(数据库/表)]
style User fill:#e3f2fd,stroke:#1976d2
style Role fill:#e8f5e9,stroke:#388e3c
style Privilege fill:#fff3e0,stroke:#fbc02d
style DB fill:#ede7f6,stroke:#7b1fa2flowchart LR
User[User
(用户)] -->|赋予| Role[Role
(角色)]
Role -->|赋予| Privilege[Privilege
(权限)]
Privilege -->|作用于| DB[Database/Table
(数据库/表)]
style User fill:#e3f2fd,stroke:#1976d2
style Role fill:#e8f5e9,stroke:#388e3c
style Privilege fill:#fff3e0,stroke:#fbc02d
style DB fill:#ede7f6,stroke:#7b1fa2flowchart LR
User[User
(用户)] -->|赋予| Role[Role
(角色)]
Role -->|赋予| Privilege[Privilege
(权限)]
Privilege -->|作用于| DB[Database/Table
(数据库/表)]
style User fill:#e3f2fd,stroke:#1976d2
style Role fill:#e8f5e9,stroke:#388e3c
style Privilege fill:#fff3e0,stroke:#fbc02d
style DB fill:#ede7f6,stroke:#7b1fa2flowchart LR
User[User
(用户)] -->|赋予| Role[Role
(角色)]
Role -->|赋予| Privilege[Privilege
(权限)]
Privilege -->|作用于| DB[Database/Table
(数据库/表)]
style User fill:#e3f2fd,stroke:#1976d2
style Role fill:#e8f5e9,stroke:#388e3c
style Privilege fill:#fff3e0,stroke:#fbc02d
style DB fill:#ede7f6,stroke:#7b1fa2- 用户只绑定角色
- 角色才拥有权限
- 权限始终以数据库为边界
8. 运维角色设计(全局)
8.1 为什么运维角色是全局的?
- 表结构、复制、副本是全局行为
- 拆分会造成权限碎片
8.2 推荐运维角色(生产)
| |
不直接授予 ALL, 原因:DROP / TRUNCATE 属于事故级操作
8.3 超级管理员角色 (不推荐)
| |
9. 业务角色设计(核心)
命名规范应该遵循 <database>_(read|write|admin) 的格式,例如 dbtest_read、dbtest_write、dbtest_admin。这样命名可以清晰地表示角色的用途和所属的数据库。
9.1 标准业务库角色
| |
9.2 为什么生产程序用户不授予 UPDATE / DELETE?
- 根本原因
数据库 UPDATE / DELETE MySQL / PostgreSQL原生能力 ClickHouse高成本模拟
ClickHouse 的 DELETE / UPDATE:
- 本质是数据重写
高 IO/高 CPU- 容易引发
merge堆积
📌 行业共识:生产程序不直接删改
9.3 推荐替代方式
| 场景 | 推荐 |
|---|---|
| 数据过期 | TTL |
| 大批量删除 | DROP PARTITION |
| 修正数据 | 重算 + INSERT |
| 极少纠错 | 运维 ALTER |
10. 测试环境权限(例外规则)
| |
必须明确:仅限测试环境
11. 用户绑定规范
| |
11.1 禁止使用 default 用户
| |
11.2 限制角色/用户的登陆来源
| |
12. 用户权限同步
12.1 传统模式
- 权限信息存在本地
.sql文件中, 一般位于/var/lib/clickhouse/access中
12.2 同步模式
当你在集群任何一个节点执行 CREATE USER ... ON CLUSTER 时,该操作会被记录到 Keeper。其他节点监听该路径,一旦有变动,会自动将权限信息拉取到本地内存生效。
- 权限信息以元数据形式存放在
Keeper/ZooKeeper的指定路径下。 - 核心配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17<!-- /etc/clickhouse-server/config.d/replicated_access.xml --> <clickhouse> <user_directories replace="replace"> <!-- 主存储:ZooKeeper --> <replicated> <zookeeper_path>/clickhouse/access/</zookeeper_path> </replicated> <!-- 本地缓存 & 容灾 --> <local_directory> <path>/data/_clickhouse/access/</path> </local_directory> <users_xml> <path>users.xml</path> </users_xml> </user_directories> </clickhouse> - 验证
1 2 3 4 5 6-- 主节点创建后,新加入的节点即可查看 SHOW USERS; SHOW ROLES; -- 查看当前节点正在使用的用户目录 SELECT name,type,params FROM system.user_directories
若为发现权限同步,可能是角色创建在同步模式之前
13. Settings Profile(权限设计的重要补充)
13.1 为什么 settings 是权限的一部分?
在 ClickHouse 中:
资源滥用比权限越权更常见
13.2 程序用户推荐限制
| |
14. 高风险操作清单(必须人工控制)
| 操作 | 原因 |
|---|---|
DROP TABLE | 不可逆 |
TRUNCATE | 数据瞬间丢失 |
ALTER UPDATE / DELETE | 高成本 |
SYSTEM STOP MERGES | 影响全局 |
15. 最小可复用初始化模板(汇总)
| |