为 Kafka 配置 TLS

此页面介绍为 Vertica、Kafka 和调度程序配置 TLS 连接的过程。

请注意,以下示例会为 ssl.client.auth=required 的 Kafka 服务器配置 TLS,该操作需要以下各项:

  • kafka_SSL_Certificate

  • kafka_SSL_PrivateKey_secret

  • kafka_SSL_PrivateKeyPassword_secret

  • 调度程序的密钥库

如果您的配置使用 ssl.client.auth=nonessl.client.auth=requested,则这些参数和调度程序密钥库为可选项。

为 Vertica 和客户端创建证书

以下示例中的 CA 证书为自签名证书。在生产环境中,应该为使用可信 CA。

以下示例将使用同一自签名根 CA 对调度程序、Kafka 代理和 Vertica 使用的所有证书进行签名。如果不能使用同一 CA 对所有这些系统的密钥进行签名,请确保将整个信任链包含在密钥库中。

有关详细信息,请参阅生成 TLS 证书和密钥

  1. 生成私钥 root.key

    $ openssl genrsa -out root.key
    Generating RSA private key, 2048 bit long modulus
    ..............................................................................
    ............................+++
    ...............+++
    e is 65537 (0x10001)
    
  2. 生成自签名 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
    
  3. 限制所有者对 root.keyroot.crt 的读取/写入权限。向其他组授予对 root.crt 的读取权限。

    
    $ ls
    root.crt  root.key
    $ chmod 600 root.key
    $ chmod 644 root.crt
    
  4. 生成服务器私钥 server.key

    $ openssl genrsa -out server.key
    Generating RSA private key, 2048 bit long modulus
    ....................................................................+++
    ......................................+++
    e is 65537 (0x10001)
    
  5. 为您的 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 []:
    
  6. 使用您的 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
    
  7. 为密钥和证书设置相应的权限。

    $ 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_KEYSCERTIFICATES 来查看现有的密钥和证书。

  1. 使用 CREATE KEYCREATE 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.keyroot.crtserver.keyserver.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
    
  2. 按照配置客户端-服务器 TLS 中针对相互模式 的步骤设置合适的 TLSMODE 和 TLS CONFIGURATION 参数。

为相互模式配置客户端

客户端必须有自己的私钥、证书和 CA 证书。建立连接时,证书将提供给 Vertica,并将使用 CA 证书来验证 Vertica 中的服务器证书。

以下示例为相互模式配置 vsql 客户端。

  1. 在用户的主目录中创建 .vsql 目录。

    $ mkdir ~/.vsql
    
  2. client.keyclient.crtroot.crt 复制到 vsql 目录。

    $ cp client.key client.crt root.crt ~/.vsql
    
  3. 使用 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 之间建立加密连接没有影响。

  1. 为所有 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
    
  2. 为名为 kafka01 的 Kafka 代理创建密钥库文件。每个代理的密钥库都应该唯一。

    keytool 命令会添加在建立 TLS 连接时用作备用名称的主题备用名称 (SAN)。使用 Kafka 代理的完全限定域名 (FQDN) 作为 SAN 和“您的名字和姓氏是什么? (What is your first and last name?)”提示问题的值。

    在以下示例中,FQDN 为 kafka01.example.comkeytool 的别名将设置为 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):
    
  3. 导出 Kafka 代理的证书。在以下示例中,证书将导出为 kafka01.unsigned.crt

    $ keytool -keystore kafka01.keystore.jks -alias localhost \
                    -certreq -file kafka01.unsigned.crt
     Enter keystore password: some_password
    
  4. 使用 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
    
  5. 将 CA 证书导入到代理的密钥库中。

    $ 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
    
  6. 将已签名的 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
    
  7. 如果未登录到要为其准备密钥库的 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
    
  8. 对剩余的 Kafka 代理重复步骤 2 到 7。

允许 Kafka 读取密钥库和信任库

如果在上一步中没有将信任库和密钥库复制到 Kafka 可以读取它们的目录,则必须将其复制到代理上的最终位置。此外,还必须允许用于运行 Kafka 的用户帐户读取这些文件。确保该用户能够访问这些文件的最简单方法是授予该用户对这些文件的所有权。

在以下示例中,Kafka 由 Linux 用户 kafka 运行。如果使用其他用户运行 Kafka,请务必对信任库和密钥库文件设置相应的权限。

  1. 以 root 用户身份登录到 Kafka 代理。

  2. 将信任库和密钥库复制到 Kafka 可以访问它们的目录。这些文件没有固定位置:您可以选择 /etc 下的目录,也可以选择通常用于存储配置文件的某个其他位置。以下示例会将它们从 root 用户的主目录复制到名为 /opt/kafka/config/ 的 Kafka 配置目录。在您自己的系统中,此配置目录可能位于不同的位置,具体取决于您安装 Kafka 的方式。

  3. 将信任库和密钥库复制到 Kafka 可以访问它们的目录。这些文件没有固定位置:您可以选择 /etc 下的目录,也可以选择通常用于存储配置文件的某个其他位置。以下示例会将它们从 root 用户的主目录复制到名为 /opt/kafka/config/ 的 Kafka 配置目录。在您自己的系统中,此配置目录可能位于不同的位置,具体取决于您安装 Kafka 的方式。

    ~# cd /opt/kafka/config/
    /opt/kafka/config# cp /root/kafka01.keystore.jks /root/kafka.truststore.jks .
    
  4. 如果您未以运行 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
    ...
    
  5. 对剩余的 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

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 配置为通过 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 作为 Hadoop 群集的一部分运行,则通常可以从用于控制 Hadoop 的任何界面(例如 Ambari)中重新启动它。

  • 如果 Kafka 是直接安装的,则可以通过直接运行 kafka-server-stop.shkafka-server-start.sh 脚本或者通过 Linux 系统的服务控制命令(如 systemctl)来重新启动它。必须在每个代理上运行此命令。

测试配置

如果尚未配置客户端身份验证,可以通过运行以下命令快速测试 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 生产者和使用者。要配置这些工具,必须先创建一个客户端密钥库。这些步骤与创建代理密钥库相同。

  1. 创建客户端密钥库:

    keytool -keystore client.keystore.jks -alias localhost -validity 365 -genkey -keyalg RSA -ext SAN=DNS:fqdn_of_client_system
    
  2. 使用您将用于运行生产者和/或使用者的系统的 FQDN 来回答“您的名字和姓氏是什么? (What is your first and last name)?”。使用贵组织的详细信息回答剩余提示问题。

  3. 导出客户端证书以便可以对其进行签名:

    keytool -keystore client.keystore.jks -alias localhost -certreq -file client.unsigned.cert
    
  4. 使用根 CA 对客户端证书进行签名:

    openssl x509 -req -CA root.crt -CAkey root.key -in client.unsigned.cert -out client.signed.cert \
            -days 365 -CAcreateserial
    
  5. 将根 CA 添加到密钥库:

    keytool -keystore client.keystore.jks -alias CARoot -import -file root.crt
    
  6. 将已签名的客户端证书添加到密钥库:

    keytool -keystore client.keystore.jks -alias localhost -import -file client.signed.cert
    
  7. 将密钥库复制到将使用它的位置。例如,可以选择将其复制到为 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 设为 nonerequested,则创建密钥库是可选的。

此过程类似于为 Kafka 代理创建信任库和密钥库。主要区别在于使用 keytool-dname 选项将密钥的公用名称 (CN) 设为域通配符。使用此设置可使密钥和证书与网络中的任何主机匹配。如果在不同的服务器上运行多个调度程序以提供冗余,则此选项特别有用。无论调度程序在域中的哪个服务器上运行,它们都可以使用相同的密钥和证书。

  1. 为调度程序创建信任库文件。添加已用于对 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
    
  2. 初始化密钥库,从而向其传递作为公用名称的通配符主机名。此命令中的 alias 参数非常重要,因为稍后您会使用它来标识调度程序在创建 SSL 连接时必须使用的密钥:

    keytool -keystore scheduler.keystore.jks -alias vsched -validity 365 -genkey \
            -keyalg RSA  -dname CN=*.mycompany.com
    
  3. 导出调度程序的密钥,以便可以使用根 CA 对其进行签名:

    $ keytool -keystore scheduler.keystore.jks -alias vsched -certreq \
            -file scheduler.unsigned.cert
    
  4. 使用根 CA 对调度程序密钥进行签名:

    $ openssl x509 -req -CA root.crt -CAkey root.key -in scheduler.unsigned.cert \
            -out scheduler.signed.cert -days 365 -CAcreateserial
    
  5. 将调度程序密钥重新导入到密钥库中:

    $ 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"

例如,假设调度程序的信任库和密钥库位于目录 /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"

要确保始终设置此变量,请将该命令添加到运行调度程序的用户帐户的 ~/.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 导入到信任库中。
--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 &