4 - 为 Kafka 配置 TLS
此页面介绍为 Vertica、Kafka 和调度程序配置 TLS 连接的过程。
请注意,以下示例会为 ssl.client.auth=required
的 Kafka 服务器配置 TLS,该操作需要以下各项:
如果您的配置使用 ssl.client.auth=none
或 ssl.client.auth=requested
,则这些参数和调度程序密钥库为可选项。
为 Vertica 和客户端创建证书
以下示例中的 CA 证书为自签名证书。在生产环境中,应该为使用可信 CA。
以下示例将使用同一自签名根 CA 对调度程序、Kafka 代理和 Vertica 使用的所有证书进行签名。如果不能使用同一 CA 对所有这些系统的密钥进行签名,请确保将整个信任链包含在密钥库中。
有关详细信息,请参阅生成 TLS 证书和密钥。
-
生成私钥 root.key
。
$ openssl genrsa -out root.key
Generating RSA private key, 2048 bit long modulus
..............................................................................
............................+++
...............+++
e is 65537 (0x10001)
-
生成自签名 CA 证书。
$ openssl req -new -x509 -key root.key -out root.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MA
Locality Name (eg, city) []:Cambridge
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:*.mycompany.com
Email Address []:myemail@mycompany.com
-
限制所有者对 root.key
和 root.crt
的读取/写入权限。向其他组授予对 root.crt
的读取权限。
$ ls
root.crt root.key
$ chmod 600 root.key
$ chmod 644 root.crt
-
生成服务器私钥 server.key。
$ openssl genrsa -out server.key
Generating RSA private key, 2048 bit long modulus
....................................................................+++
......................................+++
e is 65537 (0x10001)
-
为您的 CA 创建证书签名请求 (CSR)。请务必将“公用名称 (Common Name)”设置为通配符(星号),以便群集中的所有 Vertica 节点都接受证书:
$ openssl req -new -key server.key -out server_reqout.txt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MA
Locality Name (eg, city) []:Cambridge
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:*.mycompany.com
Email Address []:myemail@mycompany.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: server_key_password
An optional company name []:
-
使用您的 CA 对服务器证书进行签名。这将创建服务器证书 server.crt
。
$ openssl x509 -req -in server_reqout.txt -days 3650 -sha1 -CAcreateserial -CA root.crt \
-CAkey root.key -out server.crt
Signature ok
subject=/C=US/ST=MA/L=Cambridge/O=My Company/CN=*.mycompany.com/emailAddress=myemail@mycompany.com
Getting CA Private Key
-
为密钥和证书设置相应的权限。
$ chmod 600 server.key
$ chmod 644 server.crt
创建客户端密钥和证书(仅限相互模式)
在相互模式 下,客户端和服务器会在建立连接之前会验证彼此的证书。以下过程会创建客户端密钥和证书以提供给 Vertica。证书必须由 Vertica 信任的 CA 进行签名。
此操作的步骤与上述为 Vertica 创建服务器密钥和证书的步骤相同。
$ openssl genrsa -out client.key
Generating RSA private key, 2048 bit long modulus
................................................................+++
..............................+++
e is 65537 (0x10001)
$ openssl req -new -key client.key -out client_reqout.txt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MA
Locality Name (eg, city) []:Cambridge
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:*.mycompany.com
Email Address []:myemail@mycompany.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: server_key_password
An optional company name []:
$ openssl x509 -req -in client_reqout.txt -days 3650 -sha1 -CAcreateserial -CA root.crt \
-CAkey root.key -out client.crt
Signature ok
subject=/C=US/ST=MA/L=Cambridge/O=My Company/CN=*.mycompany.com/emailAddress=myemail@mycompany.com
Getting CA Private Key
$ chmod 600 client.key
$ chmod 644 client.crt
设置相互模式客户端-服务器 TLS
为相互模式配置 Vertica
对于相互模式,必须导入以下密钥和证书,然后使用 TLS CONFIGURATION 将其分发到 Vertica 群集上的节点:
-
root.key
-
root.crt
-
server.key
-
server.crt
您可以通过查询 CRYPTOGRAPHIC_KEYS 和 CERTIFICATES 来查看现有的密钥和证书。
-
使用 CREATE KEY 和 CREATE CERTIFICATE 将服务器和根密钥及证书导入到 Vertica 中。有关详细信息,请参阅生成 TLS 证书和密钥。
=> CREATE KEY imported_key TYPE 'RSA' AS '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----';
=> CREATE CA CERTIFICATE imported_ca AS '-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----';
=> CREATE CERTIFICATE imported_cert AS '-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----';
在以下示例中,\set 用于检索 root.key
、root.crt
、server.key
和 server.crt
的内容。
=> \set ca_cert ''''`cat root.crt`''''
=> \set serv_key ''''`cat server.key`''''
=> \set serv_cert ''''`cat server.crt`''''
=> CREATE CA CERTIFICATE root_ca AS :ca_cert;
CREATE CERTIFICATE
=> CREATE KEY server_key TYPE 'RSA' AS :serv_key;
CREATE KEY
=> CREATE CERTIFICATE server_cert AS :serv_cert;
CREATE CERTIFICATE
-
按照配置客户端-服务器 TLS 中针对相互模式 的步骤设置合适的 TLSMODE 和 TLS CONFIGURATION 参数。
为相互模式配置客户端
客户端必须有自己的私钥、证书和 CA 证书。建立连接时,证书将提供给 Vertica,并将使用 CA 证书来验证 Vertica 中的服务器证书。
以下示例为相互模式配置 vsql
客户端。
-
在用户的主目录中创建 .vsql
目录。
$ mkdir ~/.vsql
-
将 client.key
、client.crt
和 root.crt
复制到 vsql
目录。
$ cp client.key client.crt root.crt ~/.vsql
-
使用 vsql
登录到 Vertica 并查询 SESSIONS 系统表,以验证连接是否使用的是相互模式:
$ vsql
Password: user-password
Welcome to vsql, the Vertica Analytic Database interactive terminal.
Type: \h or \? for help with vsql commands
\g or terminate with semicolon to execute query
\q to quit
SSL connection (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256, protocol: TLSv1.2)
=> select user_name,ssl_state from sessions;
user_name | ssl_state
-----------+-----------
dbadmin | Mutual
(1 row)
为 Kafka 配置 TLS
配置 Kafka 代理
以下过程会将 Kafka 配置为对客户端连接使用 TLS。此外,还可以将 Kafka 配置为使用 TLS 在代理之间进行通信。但是,代理间的 TLS 对在 Vertica 与 Kafka 之间建立加密连接没有影响。
-
为所有 Kafka 代理创建信任库文件,从而导入 CA 证书。以下示例将使用上面创建的自签名 root.crt
。
=> $ keytool -keystore kafka.truststore.jks -alias CARoot -import \
-file root.crt
Enter keystore password: some_password
Re-enter new password: some_password
Owner: EMAILADDRESS=myemail@mycompany.com, CN=*.mycompany.com, O=MyCompany, L=Cambridge, ST=MA, C=US
Issuer: EMAILADDRESS=myemail@mycompany.com, CN=*.mycompany.com, O=MyCompany, L=Cambridge, ST=MA, C=US
Serial number: c3f02e87707d01aa
Valid from: Fri Mar 22 13:37:37 EDT 2019 until: Sun Apr 21 13:37:37 EDT 2019
Certificate fingerprints:
MD5: 73:B1:87:87:7B:FE:F1:6E:94:55:FD:AF:5D:D0:C3:0C
SHA1: C0:69:1C:93:54:21:87:C7:03:93:FE:39:45:66:DE:22:18:7E:CD:94
SHA256: 23:03:BB:B7:10:12:50:D9:C5:D0:B7:58:97:41:1E:0F:25:A0:DB:
D0:1E:7D:F9:6E:60:8F:79:A6:1C:3F:DD:D5
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 50 69 11 64 45 E9 CC C5 09 EE 26 B5 3E 71 39 7C Pi.dE.....&.>q9.
0010: E5 3D 78 16 .=x.
]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 50 69 11 64 45 E9 CC C5 09 EE 26 B5 3E 71 39 7C Pi.dE.....&.>q9.
0010: E5 3D 78 16 .=x.
]
]
Trust this certificate? [no]: yes
Certificate was added to keystore
-
为名为 kafka01
的 Kafka 代理创建密钥库文件。每个代理的密钥库都应该唯一。
keytool
命令会添加在建立 TLS 连接时用作备用名称的主题备用名称 (SAN)。使用 Kafka 代理的完全限定域名 (FQDN) 作为 SAN 和“您的名字和姓氏是什么? (What is your first and last name?)”提示问题的值。
在以下示例中,FQDN 为 kafka01.example.com
。keytool
的别名将设置为 localhost
,因此与代理的本地连接将使用 TLS。
$ keytool -keystore kafka01.keystore.jks -alias localhost -validity 365 -genkey -keyalg RSA \
-ext SAN=DNS:kafka01.mycompany.com
Enter keystore password: some_password
Re-enter new password: some_password
What is your first and last name?
[Unknown]: kafka01.mycompany.com
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]: MyCompany
What is the name of your City or Locality?
[Unknown]: Cambridge
What is the name of your State or Province?
[Unknown]: MA
What is the two-letter country code for this unit?
[Unknown]: US
Is CN=Database Admin, OU=MyCompany, O=Unknown, L=Cambridge, ST=MA, C=US correct?
[no]: yes
Enter key password for <localhost>
(RETURN if same as keystore password):
-
导出 Kafka 代理的证书。在以下示例中,证书将导出为 kafka01.unsigned.crt
。
$ keytool -keystore kafka01.keystore.jks -alias localhost \
-certreq -file kafka01.unsigned.crt
Enter keystore password: some_password
-
使用 CA 证书对代理的证书进行签名。
$ openssl x509 -req -CA root.crt -CAkey root.key -in kafka01.unsigned.crt \
-out kafka01.signed.crt -days 365 -CAcreateserial
Signature ok
subject=/C=US/ST=MA/L=Cambridge/O=Unknown/OU=MyCompany/CN=Database Admin
Getting CA Private Key
-
将 CA 证书导入到代理的密钥库中。
注意
如果在环境中使用不同的 CA 对证书进行签名,则必须将用于对证书进行签名的整个 CA 链(直到根 CA)添加到密钥库中。添加整个信任链有助于其他系统验证 Kafka 代理的身份。
$ keytool -keystore kafka01.keystore.jks -alias CARoot -import -file root.crt
Enter keystore password: some_password
Owner: EMAILADDRESS=myemail@mycompany.com, CN=*.mycompany.com, O=MyCompany, L=Cambridge, ST=MA, C=US
Issuer: EMAILADDRESS=myemail@mycompany.com, CN=*.mycompany.com, O=MyCompany, L=Cambridge, ST=MA, C=US
Serial number: c3f02e87707d01aa
Valid from: Fri Mar 22 13:37:37 EDT 2019 until: Sun Apr 21 13:37:37 EDT 2019
Certificate fingerprints:
MD5: 73:B1:87:87:7B:FE:F1:6E:94:55:FD:AF:5D:D0:C3:0C
SHA1: C0:69:1C:93:54:21:87:C7:03:93:FE:39:45:66:DE:22:18:7E:CD:94
SHA256: 23:03:BB:B7:10:12:50:D9:C5:D0:B7:58:97:41:1E:0F:25:A0:DB:D0:1E:7D:F9:6E:60:8F:79:A6:1C:3F:DD:D5
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 50 69 11 64 45 E9 CC C5 09 EE 26 B5 3E 71 39 7C Pi.dE.....&.>q9.
0010: E5 3D 78 16 .=x.
]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 50 69 11 64 45 E9 CC C5 09 EE 26 B5 3E 71 39 7C Pi.dE.....&.>q9.
0010: E5 3D 78 16 .=x.
]
]
Trust this certificate? [no]: yes
Certificate was added to keystore
-
将已签名的 Kafka 代理证书导入到密钥库中。
$ keytool -keystore kafka01.keystore.jks -alias localhost \
-import -file kafka01.signed.crt
Enter keystore password: some_password
Owner: CN=Database Admin, OU=MyCompany, O=Unknown, L=Cambridge, ST=MA, C=US
Issuer: EMAILADDRESS=myemail@mycompany.com, CN=*.mycompany.com, O=MyCompany, L=Cambridge, ST=MA, C=US
Serial number: b4bba9a1828ecaaf
Valid from: Tue Mar 26 12:26:34 EDT 2019 until: Wed Mar 25 12:26:34 EDT 2020
Certificate fingerprints:
MD5: 17:EA:3E:15:B4:15:E9:93:67:EE:59:C0:4F:D1:4C:01
SHA1: D5:35:B7:F7:44:7C:D6:B4:56:6F:38:2D:CD:3A:16:44:19:C1:06:B7
SHA256: 25:8C:46:03:60:A7:4C:10:A8:12:8E:EA:4A:FA:42:1D:A8:C5:FB:65:81:74:CB:46:FD:B1:33:64:F2:A3:46:B0
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 1
Trust this certificate? [no]: yes
Certificate was added to keystore
-
如果未登录到要为其准备密钥库的 Kafka 代理,请使用 scp 将信任库和密钥库复制到该代理中。如果您已决定在代理的文件系统中存储密钥库和信任库文件的位置,可以直接将其复制到最终目标位置。以下示例只是将它们临时复制到 root 用户的主目录。下一步将它们移动到最终位置。
$ scp kafka.truststore.jks kafka01.keystore.jks root@kafka01.mycompany.com:
root@kafka01.mycompany.com's password: root_password
kafka.truststore.jks 100% 1048 1.0KB/s 00:00
kafka01.keystore.jks 100% 3277 3.2KB/s 00:00
-
对剩余的 Kafka 代理重复步骤 2 到 7。
允许 Kafka 读取密钥库和信任库
如果在上一步中没有将信任库和密钥库复制到 Kafka 可以读取它们的目录,则必须将其复制到代理上的最终位置。此外,还必须允许用于运行 Kafka 的用户帐户读取这些文件。确保该用户能够访问这些文件的最简单方法是授予该用户对这些文件的所有权。
在以下示例中,Kafka 由 Linux 用户 kafka
运行。如果使用其他用户运行 Kafka,请务必对信任库和密钥库文件设置相应的权限。
-
以 root 用户身份登录到 Kafka 代理。
-
将信任库和密钥库复制到 Kafka 可以访问它们的目录。这些文件没有固定位置:您可以选择 /etc 下的目录,也可以选择通常用于存储配置文件的某个其他位置。以下示例会将它们从 root 用户的主目录复制到名为 /opt/kafka/config/ 的 Kafka 配置目录。在您自己的系统中,此配置目录可能位于不同的位置,具体取决于您安装 Kafka 的方式。
-
将信任库和密钥库复制到 Kafka 可以访问它们的目录。这些文件没有固定位置:您可以选择 /etc
下的目录,也可以选择通常用于存储配置文件的某个其他位置。以下示例会将它们从 root 用户的主目录复制到名为 /opt/kafka/config/
的 Kafka 配置目录。在您自己的系统中,此配置目录可能位于不同的位置,具体取决于您安装 Kafka 的方式。
~# cd /opt/kafka/config/
/opt/kafka/config# cp /root/kafka01.keystore.jks /root/kafka.truststore.jks .
-
如果您未以运行 Kafka 的用户帐户身份登录,请更改信任库和密钥库文件的所有权。以下示例会将所有权从 root 用户(即当前登录的用户)更改为 Kafka 用户:
/opt/kafka/config# ls -l
total 80
...
-rw-r--r-- 1 kafka nogroup 1221 Feb 21 2018 consumer.properties
-rw------- 1 root root 3277 Mar 27 08:03 kafka01.keystore.jks
-rw-r--r-- 1 root root 1048 Mar 27 08:03 kafka.truststore.jks
-rw-r--r-- 1 kafka nogroup 4727 Feb 21 2018 log4j.properties
...
/opt/kafka/config# chown kafka kafka01.keystore.jks kafka.truststore.jks
/opt/kafka/config# ls -l
total 80
...
-rw-r--r-- 1 kafka nogroup 1221 Feb 21 2018 consumer.properties
-rw------- 1 kafka root 3277 Mar 27 08:03 kafka01.keystore.jks
-rw-r--r-- 1 kafka root 1048 Mar 27 08:03 kafka.truststore.jks
-rw-r--r-- 1 kafka nogroup 4727 Feb 21 2018 log4j.properties
...
-
对剩余的 Kafka 代理重复步骤 1 到 3。
将 Kafka 配置为使用 TLS
信任库和密钥库就位后,下一步是编辑 Kafka 的 server.properties
配置文件,以告知 Kafka 使用 TLS/SSL 加密。此文件通常存储在 Kafka 配置目录中。此目录的位置取决于您安装的 Kafka 方式。在以下示例中,该文件位于 /opt/kafka/config
中。
编辑这些文件时,请务必不要更改其所有权。确保 Linux 不会更改文件所有权的最佳方法是使用 su 成为运行 Kafka 的用户帐户(假设您尚未以该用户身份登录):
$ /opt/kafka/config# su -s /bin/bash kafka
注意
使用前面的命令能够以 Kafka 系统用户身份启动 shell,即使该用户无法登录也是如此。
server.properties
文件包含采用
property=value
格式的 Kafka 代理设置。要将 Kafka 代理配置为使用 SSL,请更改或添加以下属性设置:
listeners
- Kafka 代理侦听的主机名和端口。如果不使用 SSL 在代理之间建立连接,则必须同时提供 PLANTEXT 和 SSL 选项。例如:
listeners=PLAINTEXT://hostname:9092,SSL://hostname:9093
ssl.keystore.location
- 密钥库文件的绝对路径。
ssl.keystore.password
- 密钥库文件的密码。
ssl.key.password
- 密钥库中 Kafka 代理密钥的密码。如果愿意,可以将此密码设为与密钥库密码不同。
ssl.truststore.location
- 信任库文件的位置。
ssl.truststore.password
- 用于访问信任库的密码。
ssl.enabled.protocols
- Kafka 允许客户端使用的 TLS/SSL 协议。
ssl.client.auth
- 指定 SSL 身份验证是必需还是可选的。验证客户端身份需要使用此设置的最安全设置。
重要
这些设置因 Kafka 版本而异。对
server.properties
进行更改之前,请务必查阅适用于您所用的 Kafka 版本的
Apache Kafka 文档。特别要注意的是,Kafka 版本 2.0 及更高版本默认为客户端和代理间的通信启用主机名验证。
以下示例会将 Kafka 配置为通过 SSL 身份验证验证客户端身份。它不使用 SSL 与其他代理通信,因此 server.properties
文件会定义 SSL 和 PLAINTEXT 侦听器端口。它不会为侦听器端口提供主机名,以告知 Kafka 侦听默认网络接口。
为此配置添加到 kafka01 代理的 server.properties
副本的行如下所示:
listeners=PLAINTEXT://:9092,SSL://:9093
ssl.keystore.location=/opt/kafka/config/kafka01.keystore.jks
ssl.keystore.password=vertica
ssl.key.password=vertica
ssl.truststore.location=/opt/kafka/config/kafka.truststore.jks
ssl.truststore.password=vertica
ssl.enabled.protocols=TLSv1.2,TLSv1.1,TLSv1
ssl.client.auth=required
必须对所有代理上的 server.properties
文件进行此类更改。
对代理的 server.properties
文件进行更改后,请重新启动 Kafka。如何重新启动 Kafka 取决于安装方式:
测试配置
如果尚未配置客户端身份验证,可以通过运行以下命令快速测试 Kafka 是否能够访问其密钥库:
$ openssl s_client -debug -connect broker_host_name:9093 -tls1
如果 Kafka 能够访问其密钥库,则以下命令将输出代理证书的转储(使用 CTRL+C 退出):
=> # openssl s_client -debug -connect kafka01.mycompany.com:9093 -tls1
CONNECTED(00000003)
write to 0xa4e4f0 [0xa58023] (197 bytes => 197 (0xC5))
0000 - 16 03 01 00 c0 01 00 00-bc 03 01 76 85 ed f0 fe ...........v....
0010 - 60 60 7e 78 9d d4 a8 f7-e6 aa 5c 80 b9 a7 37 61 ``~x......\...7a
0020 - 8e 04 ac 03 6d 52 86 f5-84 4b 5c 00 00 62 c0 14 ....mR...K\..b..
0030 - c0 0a 00 39 00 38 00 37-00 36 00 88 00 87 00 86 ...9.8.7.6......
0040 - 00 85 c0 0f c0 05 00 35-00 84 c0 13 c0 09 00 33 .......5.......3
0050 - 00 32 00 31 00 30 00 9a-00 99 00 98 00 97 00 45 .2.1.0.........E
0060 - 00 44 00 43 00 42 c0 0e-c0 04 00 2f 00 96 00 41 .D.C.B...../...A
0070 - c0 11 c0 07 c0 0c c0 02-00 05 00 04 c0 12 c0 08 ................
0080 - 00 16 00 13 00 10 00 0d-c0 0d c0 03 00 0a 00 ff ................
0090 - 01 00 00 31 00 0b 00 04-03 00 01 02 00 0a 00 1c ...1............
00a0 - 00 1a 00 17 00 19 00 1c-00 1b 00 18 00 1a 00 16 ................
00b0 - 00 0e 00 0d 00 0b 00 0c-00 09 00 0a 00 23 00 00 .............#..
00c0 - 00 0f 00 01 01 .....
read from 0xa4e4f0 [0xa53ad3] (5 bytes => 5 (0x5))
0000 - 16 03 01 08 fc .....
. . .
但是,上述方法不是决定性方法;它只是告知您 Kafka 能否找到其密钥库。
Kafka 能否接受 TLS 连接的最佳测试是配置命令行 Kafka 生产者和使用者。要配置这些工具,必须先创建一个客户端密钥库。这些步骤与创建代理密钥库相同。
注意
以下示例假设 Kafka 存在名为 test 的主题,您可以将测试消息发送到该主题。
-
创建客户端密钥库:
keytool -keystore client.keystore.jks -alias localhost -validity 365 -genkey -keyalg RSA -ext SAN=DNS:fqdn_of_client_system
-
使用您将用于运行生产者和/或使用者的系统的 FQDN 来回答“您的名字和姓氏是什么? (What is your first and last name)?”。使用贵组织的详细信息回答剩余提示问题。
-
导出客户端证书以便可以对其进行签名:
keytool -keystore client.keystore.jks -alias localhost -certreq -file client.unsigned.cert
-
使用根 CA 对客户端证书进行签名:
openssl x509 -req -CA root.crt -CAkey root.key -in client.unsigned.cert -out client.signed.cert \
-days 365 -CAcreateserial
-
将根 CA 添加到密钥库:
keytool -keystore client.keystore.jks -alias CARoot -import -file root.crt
-
将已签名的客户端证书添加到密钥库:
keytool -keystore client.keystore.jks -alias localhost -import -file client.signed.cert
-
将密钥库复制到将使用它的位置。例如,可以选择将其复制到为 Kafka 代理复制了密钥库的同一目录中。如果选择将其复制到某个其他位置,或者打算使用某个其他用户来运行命令行客户端,请务必添加您为代理创建的信任库文件的副本。客户端可以重复使用此信任库文件以对 Kafka 代理进行身份验证,因为系统会使用同一 CA 对所有证书进行签名。此外,还要相应地设置该文件的所有权和权限。
接下来,必须创建将命令行客户端配置为使用 TLS 的属性文件(类似于代理的 server.properties
文件)。对于在名为 kafka01 的 Kafka 代理上运行的客户端,您的配置文件可能如下所示:
security.protocol=SSL
ssl.truststore.location=/opt/kafka/config/kafka.truststore.jks
ssl.truststore.password=trustore_password
ssl.keystore.location=/opt/kafka/config/client.keystore.jks
ssl.keystore.password=keystore_password
ssl.key.password=key_password
ssl.enabled.protocols=TLSv1.2,TLSv1.1,TLSv1
ssl.client.auth=required
此属性文件假设密钥库文件位于 Kafka 配置目录中。
最后,您可以运行命令行生产者或使用者,以确保他们可以连接和处理数据。您将向这些客户端提供刚创建的属性文件。以下示例假设已将属性文件存储在 Kafka 配置目录中,以及 Kafka 安装在 /opt/kafka
中:
~# cd /opt/kafka
/opt/kafka# bin/kafka-console-producer.sh --broker-list kafka01.mycompany.com:9093 \
--topic test --producer.config config/client.properties
>test
>test again
>More testing. These messages seem to be getting through!
^D
/opt/kafka# bin/kafka-console-consumer.sh --bootstrap-server kafaka01.mycompany.com:9093 --topic test \
--consumer.config config/client.properties --from-beginning
test
test again
More testing. These messages seem to be getting through!
^C
Processed a total of 3 messages
从 Kafka 加载数据
将 Kafka 配置为接受 TLS 连接后,验证是否可以直接将数据从其加载到 Vertica 中。即使计划创建调度程序以自动流式传输数据,也应该执行此步骤。
您可以选择创建单独的密钥和证书,用于直接从 Kafka 加载数据。以下示例会重复使用在此示例的第 2 部分中为 Vertica 服务器创建的密钥和证书。
您可以使用含有 COPY 语句的 KafkaSource 数据源函数直接从 Kafka 加载数据(请参阅手动使用来自 Kafka 的数据)。KafkaSource 函数会创建与 Kafka 的连接,因此它需要密钥、证书和相关密码来创建加密连接。您将通过会话参数传递这些信息。有关这些参数的列表,请参阅 Kafka 用户定义的会话参数。
将密钥和证书添加到该参数中的最简单方法是先将其读取到 vsql 变量中。您可以通过 Linux shell 使用左引号读取文件内容来获取它们的内容。然后,设置变量中的会话参数。在设置会话参数之前,增大 MaxSessionUDParameterSize 会话参数以在会话变量中为密钥和证书添加足够的存储空间。它们可以大于会话变量的默认大小限制(1000 字节)。
以下示例将从名为 /home/dbadmin/SSL
的目录中读取服务器密钥和证书以及根 CA。由于服务器的密钥密码未保存在文件中,该示例会在运行 vsql 之前在名为 KVERTICA_PASS 的 Linux 环境变量中设置该密码。该示例会在设置会话变量之前先将 MaxSessionUDParameterSize 设为 100000。最后,它会为 Kafka 连接启用 TLS,并从名为 test 的主题流式传输数据。
$ export KVERTICA_PASS=server_key_password
$ vsql
Password:
Welcome to vsql, the Vertica Analytic Database interactive terminal.
Type: \h or \? for help with vsql commands
\g or terminate with semicolon to execute query
\q to quit
SSL connection (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256, protocol: TLSv1.2)
=> \set cert '\''`cat /home/dbadmin/SSL/server.crt`'\''
=> \set pkey '\''`cat /home/dbadmin/SSL/server.key`'\''
=> \set ca '\''`cat /home/dbadmin/SSL/root.crt`'\''
=> \set pass '\''`echo $KVERTICA_PASS`'\''
=> alter session set MaxSessionUDParameterSize=100000;
ALTER SESSION
=> ALTER SESSION SET UDPARAMETER kafka_SSL_Certificate=:cert;
ALTER SESSION
=> ALTER SESSION SET UDPARAMETER kafka_SSL_PrivateKey_secret=:pkey;
ALTER SESSION
=> ALTER SESSION SET UDPARAMETER kafka_SSL_PrivateKeyPassword_secret=:pass;
ALTER SESSION
=> ALTER SESSION SET UDPARAMETER kafka_SSL_CA=:ca;
ALTER SESSION
=> ALTER SESSION SET UDPARAMETER kafka_Enable_SSL=1;
ALTER SESSION
=> CREATE TABLE t (a VARCHAR);
CREATE TABLE
=> COPY t SOURCE KafkaSource(brokers='kafka01.mycompany.com:9093',
stream='test|0|-2', stop_on_eof=true,
duration=interval '5 seconds')
PARSER KafkaParser();
Rows Loaded
-------------
3
(1 row)
=> SELECT * FROM t;
a
---------------------------------------------------------
test again
More testing. These messages seem to be getting through!
test
(3 rows)
配置调度程序
配置的最后一部分是将调度程序设置为在与 Kafka(以及 Vertica,可选)通信时使用 SSL。当调度程序运行 COPY 命令从 Kafka 获取数据时,它会使用自己的密钥和证书对 Kafka 进行身份验证。如果选择让调度程序使用 TLS/SSL 连接到 Vertica,则它可以重复使用相同的密钥库和信任库建立此连接。
为调度程序创建信任库和密钥库
由于调度程序是一个单独的组件,因此它必须具有自己的密钥和证书。调度程序在 Java 中运行并使用 JDBC 接口连接到 Vertica。因此,必须为它创建在建立与 Vertica 的 TLS 加密连接时使用的密钥库(当 ssl.client.auth=required
时)和信任库。
请记住,如果 Kafka 服务器将 ssl.client.auth
设为 none
或 requested
,则创建密钥库是可选的。
此过程类似于为 Kafka 代理创建信任库和密钥库。主要区别在于使用 keytool
的 -dname
选项将密钥的公用名称 (CN) 设为域通配符。使用此设置可使密钥和证书与网络中的任何主机匹配。如果在不同的服务器上运行多个调度程序以提供冗余,则此选项特别有用。无论调度程序在域中的哪个服务器上运行,它们都可以使用相同的密钥和证书。
-
为调度程序创建信任库文件。添加已用于对 Kafka 群集和 Vertica 群集的密钥库进行签名的 CA 证书。如果使用多个 CA 对证书进行签名,请添加已使用的所有 CA。
$ keytool -keystore scheduler.truststore.jks -alias CARoot -import \
-file root.crt
Enter keystore password: some_password
Re-enter new password: some_password
Owner: EMAILADDRESS=myemail@mycompany.com, CN=*.mycompany.com, O=MyCompany, L=Cambridge, ST=MA, C=US
Issuer: EMAILADDRESS=myemail@mycompany.com, CN=*.mycompany.com, O=MyCompany, L=Cambridge, ST=MA, C=US
Serial number: c3f02e87707d01aa
Valid from: Fri Mar 22 13:37:37 EDT 2019 until: Sun Apr 21 13:37:37 EDT 2019
Certificate fingerprints:
MD5: 73:B1:87:87:7B:FE:F1:6E:94:55:FD:AF:5D:D0:C3:0C
SHA1: C0:69:1C:93:54:21:87:C7:03:93:FE:39:45:66:DE:22:18:7E:CD:94
SHA256: 23:03:BB:B7:10:12:50:D9:C5:D0:B7:58:97:41:1E:0F:25:A0:DB:
D0:1E:7D:F9:6E:60:8F:79:A6:1C:3F:DD:D5
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 50 69 11 64 45 E9 CC C5 09 EE 26 B5 3E 71 39 7C Pi.dE.....&.>q9.
0010: E5 3D 78 16 .=x.
]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 50 69 11 64 45 E9 CC C5 09 EE 26 B5 3E 71 39 7C Pi.dE.....&.>q9.
0010: E5 3D 78 16 .=x.
]
]
Trust this certificate? [no]: yes
Certificate was added to keystore
-
初始化密钥库,从而向其传递作为公用名称的通配符主机名。此命令中的 alias 参数非常重要,因为稍后您会使用它来标识调度程序在创建 SSL 连接时必须使用的密钥:
keytool -keystore scheduler.keystore.jks -alias vsched -validity 365 -genkey \
-keyalg RSA -dname CN=*.mycompany.com
重要
如果您选择使用文件格式,而不是密钥库或信任库文件的标准 Java 密钥库 (JKS) 格式,则必须在文件名中使用正确的文件扩展名。例如,假设您选择使用以 PKCS#12 格式保存的密钥库和信任库,则密钥库和信任库文件必须以 .pfx
或 .p12
扩展名结尾。
如果调度程序无法识别文件的扩展名(或者文件名中没有扩展名),则它将假定该文件为 JKS 格式。如果文件不是 JKS 格式,则启动调度程序时将显示错误消息,类似于“设置 TLS 时无法创建 SSLSocketFactory: 未找到密钥库 (Failed to create an SSLSocketFactory when setting up TLS: keystore not found)”。
-
导出调度程序的密钥,以便可以使用根 CA 对其进行签名:
$ keytool -keystore scheduler.keystore.jks -alias vsched -certreq \
-file scheduler.unsigned.cert
-
使用根 CA 对调度程序密钥进行签名:
$ openssl x509 -req -CA root.crt -CAkey root.key -in scheduler.unsigned.cert \
-out scheduler.signed.cert -days 365 -CAcreateserial
-
将调度程序密钥重新导入到密钥库中:
$ keytool -keystore scheduler.keystore.jks -alias localhost -import -file scheduler.signed.cert
设置环境变量 VKCONFIG_JVM_OPTS
您必须将多个设置传递给运行调度程序的 Java 虚拟机 (JVM) 的 JDBC 接口。这些设置会告知 JDBC 驱动程序在哪里找到密钥库和信任库,以及密钥的密码。传递这些设置的最简单方法是设置名为 VKCONFIG_JVM_OPTS 的 Linux 环境变量。启动时,调度程序会检查此环境变量并将其中定义的任何属性传递给 JVM。
您需要设置的属性如下:
-
javax.net.ssl.keystore:要使用的密钥库文件的绝对路径。
-
javax.net.ssl.keyStorePassword:调度程序的密钥密码。
-
javax.net.ssl.trustStore:信任库文件的绝对路径。
用于设置环境变量的 Linux 命令行为:
export VKCONFIG_JVM_OPTS="$VKCONFIG_JVM_OPTS -Djavax.net.ssl.trustStore=/path/to/truststore \
-Djavax.net.ssl.keyStore=/path/to/keystore \
-Djavax.net.ssl.keyStorePassword=keystore_password"
注意
前面的命令会保留 VKCONFIG_JVM_OPTS 变量的所有现有内容。如果您发现该变量存在重复设置,请从语句中移除 $VKCONFIG_JVM_OPTS
,以便覆盖该变量中的现有值。
例如,假设调度程序的信任库和密钥库位于目录 /home/dbadmin/SSL
中。那么您可以使用以下命令设置 VKCONFIG_JVM_OPTS 变量:
$ export VKCONFIG_JVM_OPTS="$VKCONFIG_JVM_OPTS \
-Djavax.net.ssl.trustStore=/home/dbadmin/SSL/scheduler.truststore.jks \
-Djavax.net.ssl.keyStore=/home/dbadmin/SSL/scheduler.keystore.jks \
-Djavax.net.ssl.keyStorePassword=key_password"
重要
Java 属性名称区分大小写。
要确保始终设置此变量,请将该命令添加到运行调度程序的用户帐户的 ~/.bashrc
或其他启动文件中。
如果需要在 JDBC 连接到 Vertica 时使用 TLS,请将 TLSmode=require
添加到调度程序使用的 JDBC URL 中。添加此参数的最简单方法是使用调度程序的 --jdbc-url
选项。假设为调度程序使用了配置文件,则可以将以下行添加到配置文件中:
--jdbc-url=jdbc:vertica://VerticaHost:portNumber/databaseName?user=username&password=password&TLSmode=require
有关将 JDBC 与 Vertica 结合使用的详细信息,请参阅 Java。
在调度程序配置中启用 TLS
最后,启用 TLS。每次运行 vkconfig
时,都必须向它传递以下选项:
--enable-ssl
true
,允许调度程序在连接到 Kafka 时使用 SSL。
--ssl-ca-alias
- 用于对 Kafka 代理的密钥进行签名的 CA 的别名。此别名必须与您提供给 keytool 命令的
-alias
实参值相匹配才能将 CA 导入到信任库中。
注意
如果已使用多个 CA 对密钥进行签名,请忽略此选项以将所有 CA 导入到信任库中。
--ssl-key-alias
- 已分配给调度密钥的别名。此值必须与您在创建调度程序的密钥库时提供给 keytool 命令的 -alias 值相匹配。
--ssl-key-password
- 调度程序密钥的密码。
有关这些选项的详细信息,请参阅常用 vkconfig 脚本选项。出于便利性和安全考虑,请将这些选项添加到传递给 vkconfig 的配置文件中。否则,您将面临通过进程列表暴露密钥密码的风险,因为同一系统上的其他用户可以查看该进程列表。有关设置配置文件的详细信息,请参阅配置文件格式。
将以下内容添加到调度程序配置文件中,以允许它在连接到 Vertica 时使用密钥库和信任库并启用 TLS:
enable-ssl=true
ssl-ca-alias=CAroot
ssl-key-alias=vsched
ssl-key-password=vertica
jdbc-url=jdbc:vertica://VerticaHost:portNumber/databaseName?user=username&password=password&TLSmode=require
启动调度程序
将调度程序配置为使用 SSL 后,启动调度程序并验证它是否可以加载数据。例如,要使用名为 weblog.conf
的配置文件启动调度程序,请使用以下命令:
$ nohup vkconfig launch --conf weblog.conf >/dev/null 2>&1 &
5 - 对 Kafka TLS/SSL 连接问题进行故障排除
将 Vertica、Kafka 和调度程序配置为使用 TLS/SSL 身份验证和加密后,可能会遇到数据流式传输问题。此部分介绍您可能会遇到的一些常见错误,以及如何对这些错误进行故障排除。
启动调度程序时出错
启动调度程序时,可能会显示如下错误:
$ vkconfig launch --conf weblog.conf
java.sql.SQLNonTransientException: com.vertica.solutions.kafka.exception.ConfigurationException:
No keystore system property found: null
at com.vertica.solutions.kafka.util.SQLUtilities.getConnection(SQLUtilities.java:181)
at com.vertica.solutions.kafka.cli.CLIUtil.assertDBConnectionWorks(CLIUtil.java:40)
at com.vertica.solutions.kafka.Launcher.run(Launcher.java:135)
at com.vertica.solutions.kafka.Launcher.main(Launcher.java:263)
Caused by: com.vertica.solutions.kafka.exception.ConfigurationException: No keystore system property found: null
at com.vertica.solutions.kafka.security.KeyStoreUtil.loadStore(KeyStoreUtil.java:77)
at com.vertica.solutions.kafka.security.KeyStoreUtil.<init>(KeyStoreUtil.java:42)
at com.vertica.solutions.kafka.util.SQLUtilities.getConnection(SQLUtilities.java:179)
... 3 more
当调度程序找不到或无法读取密钥库或信任库文件时,就会引发这些错误。要解决此问题,请执行以下操作:
-
验证是否已设置 VKCONFIG_JVM_OPTS Linux 环境变量。如果没有此变量,调度程序将不知道在何处找到创建 TLS/SSL 连接时要使用的信任库和密钥库。请参阅步骤 2:设置 VKCONFIG_JVM_OPTS 环境变量以了解详细信息。
-
验证密钥库和信任库文件是否位于在 VKCONFIG_JVM_OPTS 环境变量中设置的路径中。
-
验证运行调度程序的用户帐户是否对信任库和密钥库文件具有读取权限。
-
验证在调度程序配置中提供的密钥密码是否正确。请注意,必须提供密钥的密码,而非密钥库。
另一个可能的错误消息是无法设置 TLS 密钥库:
Exception in thread "main" java.sql.SQLRecoverableException: [Vertica][VJDBC](100024) IOException while communicating with server: java.io.IOException: Failed to create an SSLSocketFactory when setting up TLS: keystore not found.
at com.vertica.io.ProtocolStream.logAndConvertToNetworkException(Unknown Source)
at com.vertica.io.ProtocolStream.enableSSL(Unknown Source)
at com.vertica.io.ProtocolStream.initSession(Unknown Source)
at com.vertica.core.VConnection.tryConnect(Unknown Source)
at com.vertica.core.VConnection.connect(Unknown Source)
. . .
使用非 JKS 格式的密钥库或信任库文件以及未提供正确的文件扩展名可能会导致此错误。如果调度程序无法识别密钥库或信任库文件名的文件扩展名,它会假设该文件采用 JKS 格式。如果该文件不是采用此格式,调度程序将退出并显示如上所示的错误消息。要更正此错误,请重命名密钥库和信任库文件,以使用正确的文件扩展名。例如,如果文件采用 PKCS 12 文件格式,请将其文件扩展名更改为 .p12
或 .pks
。
数据不加载
如果您发现调度程序未将数据加载到数据库,应先查询 stream_microbatch_history 表以确定调度程序是否正在执行微批处理。如果是,请记录其结果。错误的 TLS/SSL 配置通常会导致出现 NETWORK_ISSUE 状态:
=> SELECT frame_start, end_reason, end_reason_message FROM weblog_sched.stream_microbatch_history;
frame_start | end_reason | end_reason_message
-------------------------+---------------+--------------------
2019-04-05 11:35:18.365 | NETWORK_ISSUE |
2019-04-05 11:35:38.462 | NETWORK_ISSUE |
如果您怀疑是 SSL 问题,可通过查看 Kafka 的 server.log
文件来验证 Vertica 是否正在建立与 Kafka 的连接。失败的 SSL 连接尝试会显示在此日志中,如以下示例所示:
java.io.IOException: Unexpected status returned by SSLEngine.wrap, expected
CLOSED, received OK. Will not send close message to peer.
at org.apache.kafka.common.network.SslTransportLayer.close(SslTransportLayer.java:172)
at org.apache.kafka.common.utils.Utils.closeAll(Utils.java:703)
at org.apache.kafka.common.network.KafkaChannel.close(KafkaChannel.java:61)
at org.apache.kafka.common.network.Selector.doClose(Selector.java:739)
at org.apache.kafka.common.network.Selector.close(Selector.java:727)
at org.apache.kafka.common.network.Selector.pollSelectionKeys(Selector.java:520)
at org.apache.kafka.common.network.Selector.poll(Selector.java:412)
at kafka.network.Processor.poll(SocketServer.scala:551)
at kafka.network.Processor.run(SocketServer.scala:468)
at java.lang.Thread.run(Thread.java:748)
如果未看到此类错误,则可能是 Kafka 与 Vertica 之间存在网络问题。如果确实看到这些错误,请考虑执行以下调试步骤:
-
验证 Kafka 群集的配置是否一致。例如,如果将某些 Kafka 节点设置为需要进行客户端身份验证,而其他节点不需要,则可能会看到连接错误。
-
验证证书和密钥中的公用名称 (CN) 是否与系统的主机名相匹配。
-
验证 Kafka 群集是否接受使用在 server.properties
文件的侦听器属性中指定的端口和主机名建立的连接。例如,假设在此设置中使用 IP 地址,但在调度程序的配置中定义群集时使用主机名。那么,Kafka 可能会拒绝 Vertica 进行的连接尝试,或者 Vertica 可能会拒绝 Kafka 节点的身份。
-
如果在 Kafka 中使用客户端身份验证,请尝试关闭它以查看调度程序是否可以连接。如果禁用身份验证后,调度程序可以流式传输数据,则可以证明该问题与客户端身份验证无关。在这种情况下,请查看 Kafka 群集和调度程序的证书与 CA。确保信任库包括用于对密钥进行签名的所有 CA,直到并包括根 CA。
Avro 架构注册表和 KafkaAvroParser
要在 Avro 架构注册表与 Vertica 之间创建 TLS 连接,KafkaAvroParser 至少需要以下参数:
当且仅当 TLS 访问失败时,请根据以下对象确定 Vertica 需要哪些 TLS 架构注册表信息:
-
证书颁发机构 (CA)
-
TLS 服务器证书
-
TLS 密钥
仅使用 KafkaAvroParser 参数提供必需的 TLS 架构注册表信息。必须能够在处理 Avro 数据的每个 Vertica 节点的文件系统中访问 TLS 信息。
以下示例显示如何将这些参数传递给 KafkaAvroParser:
KafkaAvroParser(
schema_registry_url='https://localhost:8081'
schema_registry_ssl_ca_path='path/to/certificate-authority',
schema_registry_ssl_cert_path='path/to/tls-server-certificate',
schema_registry_ssl_key_path='path/to/private-tls-key',
schema_registry_ssl_key_password_path='path/to/private-tls-key-password'
)