Not supported in ClickHouse Cloud
本指南提供了一些简单且最基本的设置,用于配置 ClickHouse 使用 OpenSSL 证书来验证连接。出于演示目的,我们将创建自签名的证书颁发机构(CA)证书和密钥,并为各节点生成证书,以便在适当的配置下建立连接。
注意
TLS 的实现较为复杂,要确保部署的安全性和健壮性,需要综合权衡多种选项。本文仅为基础教程,展示基本的 TLS 配置示例。请咨询您的 PKI/安全团队,为贵组织生成合适的证书。
如需入门概览,可先阅读这篇关于证书使用的基础教程 。
创建 ClickHouse 部署
创建 ClickHouse 部署 本指南基于 Ubuntu 20.04 编写,ClickHouse 通过 DEB 软件包(使用 apt)安装在以下主机上。域名为 marsnet.local:
Host IP Address chnode1192.168.1.221 chnode2192.168.1.222 chnode3192.168.1.223
创建 TLS 证书
创建 TLS 证书 注意
使用自签名证书仅用于演示目的,不应在生产环境中使用。应创建证书请求,并由组织签名,同时使用将在设置中配置的 CA 链进行验证。不过,这些步骤可用于配置和测试设置,之后再替换为实际要使用的证书。
生成一个将用于新 CA 的密钥:
openssl genrsa -out marsnet_ca.key 2048
生成一个新的自签名 CA 证书。以下命令将创建一个新证书,该证书将使用 CA 密钥对其他证书进行签名:
openssl req -x509 -subj "/CN=marsnet.local CA" -nodes -key marsnet_ca.key -days 1095 -out marsnet_ca.crt
注意
将密钥和 CA 证书备份到集群外的安全位置。生成节点证书后,应从集群节点中删除该密钥。
验证新 CA 证书的内容:
openssl x509 -in marsnet_ca.crt -text
为每个节点创建证书请求(CSR)并生成密钥:
openssl req -newkey rsa:2048 -nodes -subj "/CN=chnode1" -addext "subjectAltName = DNS:chnode1.marsnet.local,IP:192.168.1.221" -keyout chnode1.key -out chnode1.csr
openssl req -newkey rsa:2048 -nodes -subj "/CN=chnode2" -addext "subjectAltName = DNS:chnode2.marsnet.local,IP:192.168.1.222" -keyout chnode2.key -out chnode2.csr
openssl req -newkey rsa:2048 -nodes -subj "/CN=chnode3" -addext "subjectAltName = DNS:chnode3.marsnet.local,IP:192.168.1.223" -keyout chnode3.key -out chnode3.csr
使用 CSR 和 CA 创建新的证书和密钥对:
openssl x509 -req -in chnode1.csr -out chnode1.crt -CA marsnet_ca.crt -CAkey marsnet_ca.key -days 365 -copy_extensions copy
openssl x509 -req -in chnode2.csr -out chnode2.crt -CA marsnet_ca.crt -CAkey marsnet_ca.key -days 365 -copy_extensions copy
openssl x509 -req -in chnode3.csr -out chnode3.crt -CA marsnet_ca.crt -CAkey marsnet_ca.key -days 365 -copy_extensions copy
验证证书的 subject 和 issuer:
openssl x509 -in chnode1.crt -text -noout
检查新证书是否可通过 CA 证书验证:
openssl verify -CAfile marsnet_ca.crt chnode1.crt
chnode1.crt: OK
创建并配置用于存储证书和密钥的目录。
注意
这必须在每个节点上完成。请在每台主机上使用相应的证书和密钥。
在每个节点上,于 ClickHouse 可访问的目录中创建一个文件夹。我们建议使用默认配置目录(例如 /etc/clickhouse-server):
mkdir /etc/clickhouse-server/certs
将 CA 证书、节点证书以及与每个节点对应的密钥复制到新的 certs 目录中。
更新所有者和权限,以允许 ClickHouse 读取证书:
chown clickhouse:clickhouse -R /etc/clickhouse-server/certs
chmod 600 /etc/clickhouse-server/certs/*
chmod 755 /etc/clickhouse-server/certs
ll /etc/clickhouse-server/certs
total 20
drw-r--r-- 2 clickhouse clickhouse 4096 Apr 12 20:23 ./
drwx------ 5 clickhouse clickhouse 4096 Apr 12 20:23 ../
-rw------- 1 clickhouse clickhouse 997 Apr 12 20:22 chnode1.crt
-rw------- 1 clickhouse clickhouse 1708 Apr 12 20:22 chnode1.key
-rw------- 1 clickhouse clickhouse 1131 Apr 12 20:23 marsnet_ca.crt
使用 ClickHouse Keeper 配置包含基础集群的环境
对于此部署环境,每个节点都使用以下 ClickHouse Keeper 设置。每台服务器都会有自己的 <server_id>。(例如,节点 chnode1 使用 <server_id>1</server_id>,依此类推。)
在 ClickHouse 服务器 config.xml 的 <clickhouse> 标签内添加以下内容
<keeper_server>
<tcp_port_secure>9281</tcp_port_secure>
<server_id>1</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<session_timeout_ms>30000</session_timeout_ms>
<raft_logs_level>trace</raft_logs_level>
</coordination_settings>
<raft_configuration>
<secure>true</secure>
<server>
<id>1</id>
<hostname>chnode1.marsnet.local</hostname>
<port>9444</port>
</server>
<server>
<id>2</id>
<hostname>chnode2.marsnet.local</hostname>
<port>9444</port>
</server>
<server>
<id>3</id>
<hostname>chnode3.marsnet.local</hostname>
<port>9444</port>
</server>
</raft_configuration>
</keeper_server>
取消所有节点上的 keeper 设置注释并进行更新,然后将 <secure> 标志设置为 1:
<zookeeper>
<node>
<host>chnode1.marsnet.local</host>
<port>9281</port>
<secure>1</secure>
</node>
<node>
<host>chnode2.marsnet.local</host>
<port>9281</port>
<secure>1</secure>
</node>
<node>
<host>chnode3.marsnet.local</host>
<port>9281</port>
<secure>1</secure>
</node>
</zookeeper>
在 chnode1 和 chnode2 上更新并添加以下集群设置。chnode3 将用于 ClickHouse Keeper 法定人数。
注意
对于此配置,只配置了一个示例集群。测试示例集群必须删除或注释掉;或者如果存在一个正在测试的现有集群,则必须更新端口并添加 <secure> 选项。如果在安装期间或在 users.xml 文件中,最初已将 default 用户配置为带有密码,则必须设置 <user 和 <password>。
以下将创建一个包含一个分片、两个服务器副本的集群(每个节点上一个)。
<remote_servers>
<cluster_1S_2R>
<shard>
<replica>
<host>chnode1.marsnet.local</host>
<port>9440</port>
<user>default</user>
<password>ClickHouse123!</password>
<secure>1</secure>
</replica>
<replica>
<host>chnode2.marsnet.local</host>
<port>9440</port>
<user>default</user>
<password>ClickHouse123!</password>
<secure>1</secure>
</replica>
</shard>
</cluster_1S_2R>
</remote_servers>
定义宏值,以便创建一个 ReplicatedMergeTree 表用于测试。在 chnode1 上:
<macros>
<shard>1</shard>
<replica>replica_1</replica>
</macros>
在 chnode2 上:
<macros>
<shard>1</shard>
<replica>replica_2</replica>
</macros>
在 ClickHouse 节点上配置 TLS 接口
以下设置在 ClickHouse 服务器的 config.xml 中配置
为部署设置显示名称(可选):
<display_name>clickhouse</display_name>
将 ClickHouse 设置为监听外部端口:
<listen_host>0.0.0.0</listen_host>
在每个节点上配置 https 端口并禁用 http 端口:
<https_port>8443</https_port>
<!--<http_port>8123</http_port>-->
在每个节点上配置 ClickHouse Native 安全 TCP 端口,并禁用默认的非安全端口:
<tcp_port_secure>9440</tcp_port_secure>
<!--<tcp_port>9000</tcp_port>-->
在每个节点上配置 interserver https 端口,并禁用默认的非安全端口:
<interserver_https_port>9010</interserver_https_port>
<!--<interserver_http_port>9009</interserver_http_port>-->
使用证书和路径配置 OpenSSL
注意
每个文件名和路径都必须更新为与其配置所在的节点匹配。
例如,在 chnode2 主机上配置时,将 <certificateFile> 条目更新为 chnode2.crt。
<openSSL>
<server>
<certificateFile>/etc/clickhouse-server/certs/chnode1.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-server/certs/chnode1.key</privateKeyFile>
<verificationMode>relaxed</verificationMode>
<caConfig>/etc/clickhouse-server/certs/marsnet_ca.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
<client>
<loadDefaultCAFile>false</loadDefaultCAFile>
<caConfig>/etc/clickhouse-server/certs/marsnet_ca.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<verificationMode>relaxed</verificationMode>
<invalidCertificateHandler>
<name>RejectCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
有关更多信息,请访问 https://clickhouse.com/docs/operations/server-configuration-parameters/settings/#server_configuration_parameters-openssl
在每个节点上为 gRPC 配置 TLS:
<grpc>
<enable_ssl>1</enable_ssl>
<ssl_cert_file>/etc/clickhouse-server/certs/chnode1.crt</ssl_cert_file>
<ssl_key_file>/etc/clickhouse-server/certs/chnode1.key</ssl_key_file>
<ssl_require_client_auth>true</ssl_require_client_auth>
<ssl_ca_cert_file>/etc/clickhouse-server/certs/marsnet_ca.crt</ssl_ca_cert_file>
<transport_compression_type>none</transport_compression_type>
<transport_compression_level>0</transport_compression_level>
<max_send_message_size>-1</max_send_message_size>
<max_receive_message_size>-1</max_receive_message_size>
<verbose_logs>false</verbose_logs>
</grpc>
有关更多信息,请访问 https://clickhouse.com/docs/interfaces/grpc/
在至少一个节点上配置 ClickHouse 客户端,使其在自身的 config.xml 文件中使用 TLS 进行连接(默认位于 /etc/clickhouse-client/):
<openSSL>
<client>
<loadDefaultCAFile>false</loadDefaultCAFile>
<caConfig>/etc/clickhouse-server/certs/marsnet_ca.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<invalidCertificateHandler>
<name>RejectCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
禁用默认的 MySQL 和 PostgreSQL 模拟端口:
<!--mysql_port>9004</mysql_port-->
<!--postgresql_port>9005</postgresql_port-->
测试
逐个启动所有节点:
service clickhouse-server start
验证安全端口已启动并处于监听状态,每个节点上的结果应与以下示例类似:
root@chnode1:/etc/clickhouse-server# netstat -ano | grep tcp
tcp 0 0 0.0.0.0:9010 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:9440 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:9281 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 192.168.1.221:33046 192.168.1.222:9444 ESTABLISHED off (0.00/0/0)
tcp 0 0 192.168.1.221:42730 192.168.1.223:9444 ESTABLISHED off (0.00/0/0)
tcp 0 0 192.168.1.221:51952 192.168.1.222:9281 ESTABLISHED off (0.00/0/0)
tcp 0 0 192.168.1.221:22 192.168.1.210:49801 ESTABLISHED keepalive (6618.05/0/0)
tcp 0 64 192.168.1.221:22 192.168.1.210:59195 ESTABLISHED on (0.24/0/0)
tcp6 0 0 :::22 :::* LISTEN off (0.00/0/0)
tcp6 0 0 :::9444 :::* LISTEN off (0.00/0/0)
tcp6 0 0 192.168.1.221:9444 192.168.1.222:59046 ESTABLISHED off (0.00/0/0)
tcp6 0 0 192.168.1.221:9444 192.168.1.223:41976 ESTABLISHED off (0.00/0/0)
ClickHouse Port Description 8443 https 接口 9010 interserver https 端口 9281 ClickHouse Keeper 安全端口 9440 安全 Native TCP 协议 9444 ClickHouse Keeper Raft 端口
验证 ClickHouse Keeper 健康状况
The typical 4 letter word (4lW) 命令在不使用 TLS 的情况下无法通过 echo 使用,以下介绍如何结合 openssl 使用这些命令。
openssl s_client -connect chnode1.marsnet.local:9281
CONNECTED(00000003)
depth=0 CN = chnode1
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = chnode1
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:CN = chnode1
i:CN = marsnet.local CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICtDCCAZwCFD321grxU3G5pf6hjitf2u7vkusYMA0GCSqGSIb3DQEBCwUAMBsx
...
在 OpenSSL 会话中发送 4LW 命令
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
...
read R BLOCK
zk_version v22.7.3.5-stable-e140b8b5f3a5b660b6b576747063fd040f583cf3
zk_avg_latency 0
# highlight-next-line
zk_max_latency 4087
zk_min_latency 0
zk_packets_received 4565774
zk_packets_sent 4565773
zk_num_alive_connections 2
zk_outstanding_requests 0
# highlight-next-line
zk_server_state leader
zk_znode_count 1087
zk_watch_count 26
zk_ephemerals_count 12
zk_approximate_data_size 426062
zk_key_arena_size 258048
zk_latest_snapshot_size 0
zk_open_file_descriptor_count 187
zk_max_file_descriptor_count 18446744073709551615
# highlight-next-line
zk_followers 2
zk_synced_followers 1
closed
使用 --secure 标志和 TLS 端口启动 ClickHouse 客户端:
root@chnode1:/etc/clickhouse-server# clickhouse-client --user default --password ClickHouse123! --port 9440 --secure --host chnode1.marsnet.local
ClickHouse client version 22.3.3.44 (official build).
Connecting to chnode1.marsnet.local:9440 as user default.
Connected to ClickHouse server version 22.3.3 revision 54455.
clickhouse :)
使用位于 https://chnode1.marsnet.local:8443/play 的 https 接口登录 Play UI。
注意
浏览器会显示不受信任的证书,因为这是从工作站访问的,而这些证书不在客户端计算机的根 CA 存储中。
使用由公共机构或企业 CA 签发的证书时,应显示为受信任。
创建复制表:
clickhouse :) CREATE TABLE repl_table ON CLUSTER cluster_1S_2R
(
id UInt64,
column1 Date,
column2 String
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/default/repl_table', '{replica}' )
ORDER BY (id);
┌─host──────────────────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ chnode2.marsnet.local │ 9440 │ 0 │ │ 1 │ 0 │
│ chnode1.marsnet.local │ 9440 │ 0 │ │ 0 │ 0 │
└───────────────────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
在 chnode1 上添加几行:
INSERT INTO repl_table
(id, column1, column2)
VALUES
(1,'2022-04-01','abc'),
(2,'2022-04-02','def');
通过查看 chnode2 上的行来验证复制:
┌─id─┬────column1─┬─column2─┐
│ 1 │ 2022-04-01 │ abc │
│ 2 │ 2022-04-02 │ def │
└────┴────────────┴─────────┘
当 ClickHouse Keeper 作为独立进程运行时 (而不是嵌入在 ClickHouse 服务器中) ,必须在 Keeper 配置文件中单独配置 OpenSSL 证书和相关设置。否则,Keeper 将无法为客户端通信 (tcp_port_secure) 或 Keeper 节点之间的 Raft 复制建立安全连接。
在每个节点的独立 ClickHouse Keeper 配置文件中添加以下 <openSSL> 部分:
注意
必须将每个文件名更新为与当前配置的节点相匹配。
例如,在 chnode2 主机上进行配置时,将 <certificateFile> 条目更新为 chnode2.crt。
<openSSL>
<server>
<certificateFile>/etc/clickhouse-keeper/certs/chnode1.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-keeper/certs/chnode1.key</privateKeyFile>
<verificationMode>relaxed</verificationMode>
<caConfig>/etc/clickhouse-keeper/certs/marsnet_ca.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
<client>
<loadDefaultCAFile>false</loadDefaultCAFile>
<caConfig>/etc/clickhouse-keeper/certs/marsnet_ca.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<verificationMode>relaxed</verificationMode>
<invalidCertificateHandler>
<name>RejectCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
<server> 部分用于安全的 Keeper 端口 (tcp_port_secure) 上的入站客户端连接。<client> 部分用于 Raft 复制期间 Keeper 节点之间的出站连接。
注意
上述证书路径使用 /etc/clickhouse-keeper/certs/,这是独立部署 Keeper 时的典型路径。如果你通过其他路径安装了 Keeper,请相应调整。证书本身与步骤 2 中创建的证书相同。
OpenSSL 验证模式和证书 handler
<openSSL> 配置提供了多个 <verificationMode> 和 <invalidCertificateHandler> 选项,用于控制 ClickHouse 如何验证 TLS 证书。这些设置适用于 clickhouse-server、clickhouse-client 以及独立运行的 ClickHouse Keeper。
验证模式
在 <openSSL> 的 <server> 或 <client> 部分中设置 <verificationMode>:
模式 说明 none不验证证书。连接会加密,但不会检查对端身份。仅用于测试。 relaxed如果对端提供了证书,则会验证该证书;但如果未提供证书,也不会报错。 once在服务器端,仅在初始握手时验证客户端证书,并跳过重新协商。在客户端,其行为与 relaxed 相同。 strict需要提供对端证书并进行完整验证。如果证书缺失、已过期,或不是由受信任 CA 签名,连接将失败。建议用于生产环境。
无效证书 handler
在 <openSSL> 的 <server> 或 <client> 部分中设置 <invalidCertificateHandler>。该 handler 用于确定证书验证失败时的处理方式。在服务器端,它控制如何响应无效的客户端证书;在客户端,它控制如何响应无效的服务器证书。
Handler Description RejectCertificateHandler如果证书无效,则拒绝连接。这是默认且推荐的设置。 AcceptCertificateHandler即使证书无效,也接受连接。仅用于测试。
示例:禁用证书验证
注意
禁用证书验证会取消 TLS 身份检查,使连接暴露在中间人攻击风险之下。仅应在隔离的开发或测试环境中使用此配置。
要完全跳过证书验证 (例如在测试环境中使用自签名证书时) ,请将 verificationMode 设置为 none,并使用 AcceptCertificateHandler。
对于 clickhouse-client,您也可以使用 --accept-invalid-certificate CLI 参数,该参数会自动应用这两项设置。
clickhouse-client (/etc/clickhouse-client/config.xml):
<openSSL>
<client>
<loadDefaultCAFile>false</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<verificationMode>none</verificationMode>
<invalidCertificateHandler>
<name>AcceptCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
clickhouse-server (config.xml 或 config.d/ 中的某个文件) 。<server> 部分仍需要提供证书和密钥路径,因为服务器必须向客户端出示自己的证书,即使它并不验证客户端的证书:
<openSSL>
<server>
<certificateFile>/etc/clickhouse-server/certs/server.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-server/certs/server.key</privateKeyFile>
<verificationMode>none</verificationMode>
<caConfig>/etc/clickhouse-server/certs/ca.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
<client>
<loadDefaultCAFile>false</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<verificationMode>none</verificationMode>
<invalidCertificateHandler>
<name>AcceptCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
独立运行的 ClickHouse Keeper (Keeper 配置文件) :
<openSSL>
<server>
<certificateFile>/etc/clickhouse-keeper/certs/keeper.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-keeper/certs/keeper.key</privateKeyFile>
<verificationMode>none</verificationMode>
<caConfig>/etc/clickhouse-keeper/certs/ca.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
<client>
<loadDefaultCAFile>false</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<verificationMode>none</verificationMode>
<invalidCertificateHandler>
<name>AcceptCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
本文重点介绍了如何在 ClickHouse 环境中配置 TLS。针对生产环境中的不同需求(例如证书验证级别、协议、密码套件等),具体配置会有所差异。但现在你应该已经对配置和实现安全连接所需的各个步骤有了清晰的理解。