1. 安全模型概览
ClickHouse 的安全体系从「单一 users.xml 文件」演进到「SQL 驱动的 RBAC」。现代生产环境应该用 SQL 管理权限,users.xml 只做最小启动配置。
1.1 双层模型
| 层 | 载体 | 职责 |
|---|
| 配置层 | users.xml / config.xml | 启动参数、网络监听、SSL 证书 |
| SQL 层 | system.* 目录表 | 用户、角色、配额、行策略、授权 |
启用 SQL 权限管理的开关:
<users>
<default>
<access_management>1</access_management> <!-- 允许 default 管理权限 -->
</default>
</users>
1.2 权限对象
-- 查看现有对象
SELECT * FROM system.users;
SELECT * FROM system.roles;
SELECT * FROM system.grants;
SELECT * FROM system.quotas;
SELECT * FROM system.row_policies;
| 对象 | 作用域 | 说明 |
|---|
| User | 登录主体 | 认证方式 + 默认设置 |
| Role | 权限集合 | 可授予用户或其他角色 |
| Quota | 资源配额 | 查询频率/量级限制 |
| Row Policy | 行过滤 | 同一张表对不同用户可见不同行 |
2. 用户与角色(RBAC)
2.1 创建用户
-- 推荐:SHA-256 口令
CREATE USER analyst IDENTIFIED WITH sha256_password BY 'StrongPassw0rd!';
-- 明文口令(仅测试)
CREATE USER dev IDENTIFIED WITH plaintext_password BY 'dev123';
-- 带默认设置
CREATE USER readonly_user
IDENTIFIED WITH sha256_password BY 'read123'
SETTINGS max_memory_usage = 4_000_000_000, readonly = 1;
| 认证方式 | 说明 | 适用 |
|---|
sha256_password | 服务端存哈希 | 生产默认 |
plaintext_password | 明文传输 | 仅内网测试 |
sha256_hash | 直接指定哈希 | 脚本化分发 |
ldap | 绑定 LDAP 服务器 | 企业统一认证 |
kerberos | Kerberos 域 | 大数据生态 |
2.2 角色与授权
-- 建角色
CREATE ROLE read_only;
CREATE ROLE etl_writer;
-- 授权到角色
GRANT SELECT ON default.* TO read_only;
GRANT SELECT, INSERT ON default.events TO etl_writer;
-- 角色授予用户
GRANT read_only TO analyst;
GRANT read_only, etl_writer TO dev;
-- 查看用户拥有的角色
SELECT user_name, granted_role_name
FROM system.role_grants WHERE user_name = 'analyst';
2.3 修改与删除
ALTER USER analyst SETTINGS max_memory_usage = 8_000_000_000;
ALTER ROLE read_only SETTINGS readonly = 1;
DROP USER analyst;
DROP ROLE read_only;
角色是权限复用的核心:团队变更多个用户,只改角色即可。权限变更即时生效,无需重启。
3. GRANT 与库表级权限
3.1 权限粒度
-- 表级
GRANT SELECT ON default.events TO analyst;
GRANT SELECT, INSERT, ALTER UPDATE ON default.events TO etl_writer;
-- 库级通配
GRANT SELECT ON default.* TO analyst;
GRANT ALL ON *.* TO admin WITH GRANT OPTION;
-- 列级(24.x 起支持)
GRANT SELECT(user_id, event_type) ON default.events TO analyst;
| 权限 | 示例 | 控制内容 |
|---|
SELECT | ON db.table | 查询 |
INSERT | ON db.table | 写入 |
ALTER UPDATE/DELETE | ON db.table | 突变 |
CREATE/DROP | ON db.* | DDL |
BACKUP | ON db.* | 备份操作 |
SYSTEM | SYSTEM RELOAD 等 | 运维命令 |
ALL | ON *.* | 全部权限 |
3.2 REVOKE 与权限校验
-- 回收权限
REVOKE INSERT ON default.events FROM etl_writer;
-- 校验权限
SHOW GRANTS FOR analyst;
SELECT * FROM system.grants WHERE user_name = 'analyst';
4. 配额(Quota)与限流
4.1 配额语法
-- 每小时最多 100 次查询
CREATE QUOTA q_analyst FOR INTERVAL 1 HOUR
MAX QUERIES 100
TO analyst;
-- 每日最多读 1 亿行
CREATE QUOTA q_api FOR INTERVAL 1 DAY
MAX READ ROWS 100_000_000
TO api_user;
-- 可以叠加多个区间
CREATE QUOTA q_strict FOR INTERVAL 1 MINUTE MAX QUERIES 30,
INTERVAL 1 HOUR MAX QUERIES 300,
INTERVAL 1 DAY MAX EXECUTION TIME 3600
TO dev;
| 配额维度 | 指标 | 含义 |
|---|
QUERIES | 查询次数 | 防滥用 |
ERRORS | 错误次数 | 防故障风暴 |
RESULT ROWS / RESULT BYTES | 结果量 | 防大结果拖垮网络 |
READ ROWS / READ BYTES | 扫描量 | 防全表扫描 |
EXECUTION TIME | 累计执行时间 | 防长期占用 |
4.2 配额分配与追踪
-- 按用户/IP 分组独立计数
CREATE QUOTA q_by_ip FOR INTERVAL 1 HOUR
KEYED BY ip_address
MAX QUERIES 100
TO analyst;
-- 查看当前配额用量
SELECT * FROM system.quotas_usage;
SELECT * FROM system.query_log WHERE quota_key != '' LIMIT 5;
配额超出后查询会被拒绝并记录 QUOTA_EXCEEDED 异常。限流比事后清理更可靠,多租户场景必须按租户建独立配额。
5. 行级安全(Row Policy)
5.1 按租户隔离
-- 建表:带租户字段
CREATE TABLE tenant_orders (
tenant_id UInt64,
order_id UInt64,
amount Float64,
order_time DateTime
) ENGINE = MergeTree() ORDER BY order_time;
-- 行策略:每个用户只能看自己租户的数据
CREATE ROW POLICY rp_tenant
ON tenant_orders
FOR SELECT
USING tenant_id = toUInt64(currentUser())
TO analyst;
| 行策略要素 | 说明 |
|---|
ON 表名 | 作用目标表 |
FOR SELECT | 只作用于 SELECT |
USING 条件 | 过滤表达式,可用函数 |
TO 用户/角色 | 应用于哪些主体 |
5.2 管理与覆盖
-- 允许某角色看全部(豁免策略)
CREATE ROW POLICY rp_all ON tenant_orders
FOR SELECT USING 1
TO admin;
-- 查看与删除
SELECT * FROM system.row_policies;
DROP ROW POLICY rp_tenant ON tenant_orders;
行策略是叠加的:一个用户命中多条策略时会取并集。常用模式是「默认拒绝 + 租户策略」或「全员 + 豁免策略」。
6. SSL/TLS 与网络加固
6.1 开启 TLS
<openSSL>
<server>
<certificateFile>/etc/clickhouse-server/server.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-server/server.key</privateKeyFile>
<verificationMode>none</verificationMode>
</server>
</openSSL>
# 原生协议安全端口 9440
clickhouse-client --secure --port 9440
# HTTP 安全端口 8443
curl -s https://ch.example.com:8443/?query=SELECT%201
| 协议 | 明文端口 | 安全端口 |
|---|
| Native(TCP) | 9000 | 9440(TLS) |
| HTTP | 8123 | 8443(HTTPS) |
| Interserver | 9009 | 同证书加密 |
6.2 网络加固
<listen_host>127.0.0.1</listen_host> <!-- 只监听本机,配合反代 -->
<listen_host>::</listen_host> <!-- 按需放开 -->
| 措施 | 配置/命令 | 作用 |
|---|
| 绑定内网 IP | <listen_host> | 不暴露公网 |
| 防火墙 | iptables/firewalld | 只放行 9000/8123/9440 来源 |
| 反代加密 | Nginx + TLS | 统一入口与鉴权 |
| 用户网络白名单 | users.xml <networks> | 用户级来源 IP 限制 |
| 限制连接数 | <max_connections> | 防连接风暴 |
<!-- 用户级网络限制(users.xml) -->
<users><analyst>
<networks><ip>10.0.0.0/8</ip><ip>172.16.3.10</ip></networks>
</analyst></users>
7. 审计日志与危险操作禁用
7.1 开启查询审计
-- 会话级强制记录
SET log_queries = 1;
-- 用户默认开启
CREATE USER audited_user IDENTIFIED WITH sha256_password BY '***'
SETTINGS log_queries = 1;
-- 审计查询:谁在何时执行了什么
SELECT
user, query_kind, query, query_start_time,
query_duration_ms, read_rows, exception_code
FROM system.query_log
WHERE query_start_time >= now() - INTERVAL 1 DAY
AND query NOT ILIKE '%system.query_log%'
ORDER BY query_start_time DESC
LIMIT 50;
7.2 会话与登录审计
-- 会话日志
SELECT user, client_name, client_version, session_start_time
FROM system.session_log
ORDER BY session_start_time DESC LIMIT 20;
| 审计表 | 记录内容 |
|---|
system.query_log | 每条查询的完整执行信息 |
system.query_thread_log | 查询的线程级指标 |
system.session_log | 登录/登出会话 |
system.processes | 正在执行的查询 |
7.3 禁用危险操作
| 危险操作 | 禁用方式 |
|---|
SYSTEM SHUTDOWN / KILL | 不授予 SYSTEM 权限 |
ALTER DELETE / UPDATE | 收回 ALTER UPDATE / ALTER DELETE |
DROP TABLE | 收回 DROP TABLE |
| 无限全表扫描 | SETTINGS max_rows_to_read / 配额 |
| 大结果集 | max_result_rows / 配额 RESULT BYTES |
| DDL 直连 | 通过 readonly = 1 用户暴露只读入口 |
-- 只读账号:禁止一切写与 DDL
CREATE USER query_only
IDENTIFIED WITH sha256_password BY '***'
SETTINGS readonly = 1;
8. 与 LDAP/SSO 集成与总结
8.1 LDAP 集成
<!-- config.xml 中配置 LDAP 服务器 -->
<ldap_servers>
<ldap1>
<host>ldap.company.com</host>
<port>389</port>
<bind_dn>cn=admin,dc=company,dc=com</bind_dn>
<verification_cooldown_period>30</verification_cooldown_period>
</ldap1>
</ldap_servers>
-- 用户绑定 LDAP 认证
CREATE USER analyst IDENTIFIED WITH ldap SERVER 'ldap1';
LDAP 认证后,用户的权限仍需在 ClickHouse 内用 GRANT 授予——LDAP 只负责「你是谁」,不负责「你能干什么」。
8.2 Kerberos 与 SSO
-- Kerberos 域认证
CREATE USER analyst IDENTIFIED WITH kerberos REALM 'COMPANY.COM';
| 方案 | 适用 |
|---|
LDAP(IDENTIFIED WITH ldap) | 企业统一账号密码 |
| Kerberos | Hadoop 大数据生态 |
| 反向代理 SSO | Nginx + OIDC/SAML,X-ClickHouse-User 头传递身份 |
8.3 安全加固清单
| 主题 | 核心结论 |
|---|
| 模型 | SQL RBAC 为主,users.xml 最小化 |
| 用户/角色 | sha256 口令,角色复用,最小权限 |
| GRANT | 表级/库级/列级按需授权 |
| 配额 | 多区间限流,多租户隔离 |
| 行策略 | USING 条件过滤,租户数据隔离 |
| 网络 | 内网监听 + TLS 9440/8443 + 白名单 |
| 审计 | log_queries + query_log/session_log |
| 集成 | LDAP/Kerberos/SSO 只做认证,授权留在 SQL |
安全不是单个开关,而是一组叠加的纵深防御:认证确认「是谁」,授权决定「能干什么」,配额限住「能干多大」,行策略隔离「能看哪些」,审计记录「干了什么」。把这五层配齐,ClickHouse 就能安全地暴露给更多团队。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。