本指南介绍如何以简单、最少的配置,让 ClickHouse 使用 OpenSSL 证书验证连接。为便于演示,这里会创建自签名的证书颁发机构 (CA) 证书和密钥,以及节点证书,并使用适当的配置建立连接。
TLS 的实现较为复杂,需要综合考虑许多选项,才能确保部署既安全又稳健。本教程仅提供基础内容和基本 TLS 配置示例。请与你们的 PKI/安全团队协作,为你的组织生成正确的证书。如需入门概览,请参阅这篇证书使用基础教程。
创建 ClickHouse 部署
本指南基于 Ubuntu 20.04 编写,且 ClickHouse 是在以下主机上通过 DEB 软件包 (使用 apt) 安装的。域名为 marsnet.local:| Host | IP Address |
|---|
chnode1 | 192.168.1.221 |
chnode2 | 192.168.1.222 |
chnode3 | 192.168.1.223 |
有关如何安装 ClickHouse 的更多信息,请参阅快速入门。 创建 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 和签发方:
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 server 的
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 server 的 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 client,使其在自身的
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 端口 | 描述 |
|---|
| 8443 | HTTPS 接口 |
| 9010 | 服务器间 HTTPS 端口 |
| 9281 | ClickHouse Keeper 安全端口 |
| 9440 | 安全的 native TCP 协议端口 |
| 9444 | ClickHouse Keeper Raft 端口 |
-
检查 ClickHouse Keeper 的健康状态
常见的 4 字母命令 (4lW) 在未启用 TLS 时无法直接通过
echo 使用,以下说明如何用 openssl 执行这些命令。
openssl s_client -connect chnode1.marsnet.local:9281
CONNECTED(00000003)
depth=0 CN = chnode1
verify error:num=20:无法获取本地签发方证书
verify return:1
depth=0 CN = chnode1
verify error:num=21:无法验证第一个证书
verify return:1
---
证书链
0 s:CN = chnode1
i:CN = marsnet.local CA
---
服务器证书
-----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
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
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
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 接口登录位于 https://chnode1.marsnet.local:8443/play 的 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 server 中) ,必须在 Keeper 配置文件中单独配置 OpenSSL 证书和相关设置。否则,Keeper 将无法为客户端通信 (tcp_port_secure) 或 Keeper 节点之间的 Raft 复制建立安全连接。
将以下 <openSSL> 部分添加到每个节点上的独立运行的 ClickHouse Keeper 配置文件中:
必须将每个文件名更新为与其所在节点匹配。
例如,在 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> 配置支持多种 <verificationMode> 和 <invalidCertificateHandler> 选项,用于控制 ClickHouse 如何验证 TLS 证书。这些设置适用于 clickhouse-server、clickhouse-client 以及独立运行的 ClickHouse Keeper。
在 <openSSL> 的 <server> 或 <client> 部分中设置 <verificationMode>:
| 模式 | 描述 |
|---|
none | 不进行证书验证。连接会被加密,但不会检查对端的身份。仅用于测试。 |
relaxed | 如果提供了对端证书,则验证该证书;但如果未提供证书,也不会失败。 |
once | 在服务端,仅在初始握手时验证客户端证书,并跳过重新协商。在客户端,其行为与 relaxed 相同。 |
strict | 要求提供对端证书并进行完整验证。如果证书缺失、已过期,或不是由受信任的 CA 签发,连接将失败。建议在生产环境中使用。 |
在 <openSSL> 的 <server> 或 <client> 部分中设置 <invalidCertificateHandler>。该处理程序用于确定证书验证失败时如何处理。在服务器端,它控制对无效客户端证书的响应;在客户端,它控制对无效服务器证书的响应。
| 处理程序 | 说明 |
|---|
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。生产环境中的具体设置会因需求不同而有所差异,例如证书验证级别、协议、密码套件等。不过,相信你现在已经对配置和建立安全连接所需的步骤有了较为清晰的认识。