这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

使用 Kafka 进行 TLS/SSL 加密

您可以在 Vertica、调度程序和 Kakfa 之间使用 TLS/SSL 加密。此加密可防止其他人访问在 Kafka 和 Vertica 之间发送的数据。此外,还可以验证数据流式传输过程中涉及的所有参与方的身份,以便没有冒充者可以冒充您的 Vertica 群集或 Kafka 代理。

在以下一些常见情况下,您会想要在 Vertica 与 Kafka 之间使用 SSL 加密:

  • 您的 Vertica 数据库和 Kafka 通过不安全的网络进行通信。例如,假设 Kafka 群集位于云服务中,而 Vertica 群集位于您的内部网络中。在这种情况下,从 Kafka 读取的任何数据都会通过不安全的连接在 Internet 上传输。

  • 根据安全策略、法律或其他要求,您需要对所有网络流量进行加密。

有关 Vertica 中 TLS/SSL 加密的详细信息,请参阅 TLS 协议

在调度程序与 Vertica 之间使用 TLS/SSL

调度程序连接到 Vertica 的方式与其他客户端应用程序连接到 Vertica 的方式相同。您可以通过两种方式将 Vertica 配置为对客户端使用 SSL/TLS 身份验证和加密:

  • 如果将 Vertica 配置为使用 SSL/TLS 服务器身份验证,则可以选择让调度程序确认 Vertica 服务器的身份。

  • 如果将 Vertica 配置为使用相互 SSL/TLS 身份验证,则可以将调度程序配置为向 Vertica 表明自己的身份,以及让它验证 Vertica 服务器的身份。根据您的数据库配置,Vertica 服务器可能会要求调度程序在连接时使用 TLS。有关详细信息,请参阅使用 TLS 进行客户端身份验证

有关与 Vertica 建立的加密客户端连接的信息,请参考 TLS 协议

调度程序在 Java 虚拟机 (JVM) 上运行,并使用 JDBC 连接到 Vertica。连接到 Vertica 时,它的行为与任何其他 JDBC 客户端一样。要对调度程序与 Vertica 的连接使用 TLS/SSL 加密,请使用 Java 密钥库和信任库机制来保存调度程序用于表明自己的身份和 Vertica 身份的密钥和证书。

  • 密钥库包含调度程序的私有加密密钥及其证书(公钥)。

  • 信任库包含您信任的 CA。如果启用身份验证,调度程序将使用这些 CA 来验证其连接到的 Vertica 群集的身份。如果已使用信任库中的某个 CA 对服务器的证书进行签名,则调度程序知道它可以信任 Vertica 服务器的身份。

您可以通过名为 VKCONFIG_JVM_OPTS 的 Linux 环境变量将各个选项传递给执行调度程序的 JVM。向修改调度程序的 JDBC 设置(例如,调度程序的 JDBC 连接的信任库和密钥库)的此变量添加参数。请参阅步骤 2:设置 VKCONFIG_JVM_OPTS 环境变量以查看相关示例。

此外,还可以使用 --jdbc-url 调度程序选项来修改 JDBC 配置。请参阅常用 vkconfig 脚本选项以了解有关调度程序选项的详细信息,并参阅 JDBC 连接属性以了解有关其可以修改的属性的详细信息。

在 Vertica 与 Kafka 之间使用 TLS/SSL

您可以通过两种方式将数据从 Kafka 流式传输到 Vertica:手动使用 COPY 语句和 KafkaSource UD 源函数,或自动使用调度程序。

要通过 SSL 连接直接从 Kafka 复制数据,需要设置包含 SSL 密钥和证书的会话变量。当 KafkaSource 发现您已设置这些变量时,它会使用该密钥和证书来创建与 Kafka 的安全连接。请参阅 Kafka TLS-SSL 示例第 4 部分:直接从 Kafka 加载数据以了解详细信息。

自动将数据从 Kafka 流式传输到 Vertica 时,配置调度程序的方式与使用 SSL 连接到 Vertica 的方式相同。当调度程序执行 COPY 语句以从 Kafka 加载数据时,它会使用自己的密钥库和信任库来创建与 Kafka 的 SSL 连接。

要在从 Vertica 向 Kafka 生成数据时使用 SSL 连接,需要设置通过 SSL 连接直接从 Kafka 流式传输数据时使用的同一会话变量。KafkaExport 函数会使用这些变量来建立与 Kafka 的安全连接。

有关对 Kafka 使用 SSL/TLS 身份验证的详细信息,请参阅 Apache Kafka 文档

1 - 计划在 Vertica 和 Kafka 之间进行 TLS/SSL 加密

开始配置 TLS/SSL 之前需注意的一些事项:

  • 需要对调度程序、Vertica 和 Kafka 之间的哪些连接加密?在某些情况下,可能只需在 Vertica 与 Kafka 之间启用加密。当 Vertica 和 Kafka 群集位于不同的网络中时,这种情况很常见。例如,假设 Kafka 托管在云提供商处,而 Vertica 托管在您的内部网络中。那么,数据在两者之间必须穿过不安全的 Internet。但是,如果 Vertica 和调度程序都位于本地网络中,则可以断定不需要将其配置为使用 SSL/TLS。在其他情况下,需要对系统的所有部分进行加密。例如,当 Kafka、Vertica 和调度程序都托管在网络可能不安全的云提供商处时,需要对所有流量进行加密。

  • 需要信任调度程序、Vertica 和 Kafka 之间的哪些连接?如果一个系统无法验证另一个系统的身份,则可以选择将其中的任意连接设为失败。请参阅下面的验证身份

  • 您将使用哪些 CA 对每个证书进行签名?配置调度程序、Kafka 和 Vertica 的最简单方法是使用同一 CA 对设置 TLS/SSL 时将使用的所有证书进行签名。使用同一根 CA 对证书进行签名时,需要能够编辑 Kafka、Vertica 和调度程序的配置。如果无法使用同一 CA 对所有证书进行签名,则所有信任库必须包含用于对证书进行签名的整个 CA 链(直到根 CA)。添加整个信任链可确保每个系统都可以验证彼此的身份。

验证身份

在 Vertica、调度程序和 Kafka 之间配置 TLS/SSL 加密时,主要挑战是确保调度程序、Kafka 和 Vertica 都可以验证彼此的身份。设置 TLS/SSL 加密时用户最常遇到的问题是,如何确保远程系统可以验证系统证书的真实性。防止出现此问题的最佳方法是,确保所有系统的证书均由所有系统明确信任的 CA 进行签名。

当一个系统尝试启动与另一个系统的加密连接时,它会将其证书发送到远程系统。此证书可由一个或多个帮助识别建立连接的系统的证书颁发机构 (CA) 进行签名。这些签名形成了“信任链”。一个证书由一个 CA 进行签名。反过来,该 CA 可能已由另一个 CA 进行签名,依此类推。通常,该链以来自知名商业证书提供商(例如 Comodo SSL 或 DigiCert)的 CA(称为根 CA)结束,默认情况下,这些证书在许多平台(例如操作系统和 Web 浏览器)上均受信任。

如果远程系统找到其信任的链中的某个 CA,则会验证建立连接的系统的身份,然后就可以继续建立连接。如果远程系统找不到其信任的 CA 的签名,则可能会阻止连接,具体取决于其配置。可以将系统配置为仅允许与身份已经过验证的系统建立的连接。

2 - 为调度程序配置 TLS 连接

调度程序可以将 TLS 用于两种不同的连接:一种是它与 Vertica 建立的连接,另一种是运行 COPY 语句从 Kafka 检索数据时建立的连接。由于调度程序是 Java 应用程序,因此需要提供 TLS 密钥以及用于在密钥库中对调度程序进行签名的证书。此外,还需要提供信任库,其中包含调度程序应信任的证书。与 Vertica 和 Kafka 建立的连接都可以使用相同的密钥库和信任库。您还可以通过为调度程序设置不同的 JDBC 设置,选择为这两个连接使用单独的密钥库和信任库。有关这些设置的列表,请参阅 JDBC 连接属性

请参阅 Kafka TLS-SSL 示例第 5 部分:配置调度程序以了解件将调度程序配置为使用 SSL 的详细步骤。

请注意,如果将 Kafka 服务器的参数 client.ssl.auth 设置为 nonerequested,则不需要创建密钥库。

3 - 直接从 Kafka 加载数据时使用 TLS/SSL

您可以使用 COPY 语句和 KafkaSource 用户定义的加载函数从 Kafka 手动加载数据(请参阅手动使用来自 Kafka 的数据)。要让 KafkaSource 打开与 Kafka 的安全连接,必须为它提供 SSL 密钥和其他信息。

启动时,KafkaSource 函数会检查是否已定义多个用户会话变量。这些变量包含 SSL 密钥、用于对密钥进行签名的证书,以及该函数创建 SSL 连接所需的其他信息。有关这些变量的列表,请参阅 Kafka 用户定义的会话参数。如果 KafkaSource 发现已定义这些变量,则会使用它们创建与 Kafka 的 SSL 连接。

请参阅 Kafka TLS-SSL 示例第 4 部分:直接从 Kafka 加载数据,以获取有关在直接从 Kafka 复制数据时如何配置和使用 SSL 连接的逐步指南。

导出数据时,KafkaExport 函数也会使用这些变量来建立与 Kafka 的安全连接。

4 - 为 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 &

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 至少需要以下参数:

  • schema_registry_url (对于 https 方案)

  • schema_registry_ssl_ca_path

当且仅当 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'
)