Transport Encryption using TLS

TLS 概述

默认情况下,Apache Pulsar 客户端使用纯文本与 Apache Pulsar 服务通信。 这意味着所有发送的数据都暴露在外。 您可以使用 TLS 对此流量进行加密,以保护流量不被中间人攻击者窥探。

您还可以使用 TLS 同时配置加密和身份认证。 本指南仅配置 TLS 传输加密,可参考 此处 来使用 TLS 配置身份验证。 Alternatively, you can use another authentication mechanism on top of TLS transport encryption.

请注意,由于加密的开销,启用 TLS 可能会影响性能。

TLS 概念

TLS是一种 公钥加密技术。 使用由公钥和私钥组成的密钥对来执行加密。 公钥加密消息,私钥解密消息。

To use TLS transport encryption, you need two kinds of key pairs, server key pairs and a certificate authority.

You can use a third kind of key pair, client key pairs, for client authentication.

You should store the certificate authority private key in a very secure location (a fully encrypted, disconnected, air gapped computer). As for the certificate authority public key, the trust cert, you can freely shared it.

对于客户端和服务端的密钥对,管理员首先都生成一个私钥和一个证书请求,然后使用证书颁发机构的私钥对证书请求进行签名,最后生成一个证书。 This certificate is the public key for the server/client key pair.

For TLS transport encryption, the clients can use the trust cert to verify that the server has a key pair that the certificate authority signed when the clients are talking to the server. 中间人攻击者不能访问证书颁发机构,因此他们不能创建有这样密钥对的服务。

For TLS authentication, the server uses the trust cert to verify that the client has a key pair that the certificate authority signed. The common name of the client cert is then used as the client’s role token (see Overview).

Pulsar 使用了Bouncy Castle Provider 提供的密码套件和算法。 如果你需要 FIPS 版本的 Bouncy Castle Provider,请参考 Bouncy Castle 页面

创建 TLS 证书

为 Pulsar 创建 TLS 证书涉及创建 证书颁发机构 (CA), 服务端证书客户端证书

按照下面的指南建立一个证书颁发机构。 你也可以参考互联网上的大量资源来了解更多细节。 我们推荐 此指南 作为您的详细参考。

证书颁授

  1. 为 CA 创建证书。 您可以使用 CA 来对 broker 和 客户端证书进行签名。 这确保了每一方都会信任其他方。 您应该将 CA 存储在一个非常安全的位置(理想情况是完全脱离网络、空间隔离和完全加密)。

  2. 输入下面的命令为 CA 创建一个目录,并将此 openssl 配置文件 放入该目录中。 You may want to modify the default answers for company name and department in the configuration file. Export the location of the CA directory to the environment variable, CA_HOME. 配置文件使用这个环境变量来查找 CA 需要的其余文件和目录。

  1. mkdir my-ca
  2. cd my-ca
  3. wget https://raw.githubusercontent.com/apache/pulsar/master/site2/website/static/examples/openssl.cnf
  4. export CA_HOME=$(pwd)
  1. 输入下面的命令来创建必要的目录、密钥和证书。
  1. mkdir certs crl newcerts private
  2. chmod 700 private/
  3. touch index.txt
  4. echo 1000 > serial
  5. openssl genrsa -aes256 -out private/ca.key.pem 4096
  6. chmod 400 private/ca.key.pem
  7. openssl req -config openssl.cnf -key private/ca.key.pem \
  8. -new -x509 -days 7300 -sha256 -extensions v3_ca \
  9. -out certs/ca.cert.pem
  10. chmod 444 certs/ca.cert.pem
  1. After you answer the question prompts, CA-related files are stored in the ./my-ca directory. Within that directory:
  • certs/ca.cert.pem is the public certificate. This public certificates is meant to be distributed to all parties involved.
  • private/ca.key.pem is the private key. You only need it when you are signing a new certificate for either broker or clients and you must safely guard this private key.

服务器端证书

创建了 CA 证书之后,您就可以创建证书请求并使用 CA 给他们签名。

下面的命令向您询问一些问题,然后创建证书。 当问到通用名称(common name)时,您应该匹配 broker 的主机名。 您可以使用通配符来匹配一组 broker 主机名,例如 *.brocher.usw.example.com。 这将确保多台机器可以共同使用同一个证书。

提示

有时候匹配主机名是不可能的,或者是没有意义的,比如当您创建带有随机主机名的 broker 时,或者您计划通过他们的 IP 连接到主机时。 在这些情况下,您需要配置客户端来禁用 TLS 主机名验证。 更多信息,您可以在 客户端配置文档主机验证部分 查看到。

  1. 输入下面的命令来生成密钥。
  1. openssl genrsa -out broker.key.pem 2048

Broker 需要密钥使用 PKCS 8 格式,因此输入以下命令进行转换。

  1. openssl pkcs8 -topk8 -inform PEM -outform PEM \
  2. -in broker.key.pem -out broker.key-pk8.pem -nocrypt
  1. 输入下面的命令生成证书请求。
  1. openssl req -config openssl.cnf \
  2. -key broker.key.pem -new -sha256 -out broker.csr.pem
  1. 输入下面的命令获取证书颁发机构的签名。
  1. openssl ca -config openssl.cnf -extensions server_cert \
  2. -days 1000 -notext -md sha256 \
  3. -in broker.csr.pem -out broker.cert.pem

此时,您拥有一个证书 broker.cert.pem,和一个密钥 broker.key-pk8.pem,可以与 ca.cert.pem 一起使用,来为 broker 和 proxy 节点配置 TLS 传输加密。

Configure broker

为了配置 Pulsar broker 使用 TLS 传输加密,需要对位于 Pulsar 安装 目录conf 中的 broker.conf 文件进行一些更改。

Add these values to the configuration file (substituting the appropriate certificate paths where necessary):

  1. tlsEnabled=true
  2. tlsRequireTrustedClientCertOnConnect=true
  3. tlsCertificateFilePath=/path/to/broker.cert.pem
  4. tlsKeyFilePath=/path/to/broker.key-pk8.pem
  5. tlsTrustCertsFilePath=/path/to/ca.cert.pem

您可以在 conf/broker.conf 文件中找到完整的参数列表,以及在 Broker Configuration中找到这些参数的默认值。

TLS 协议版本和加密算法

您可以配置 broker (或 proxy) 以要求特定的 TLS 协议版本和加密算法。 您可以使用 TLS 协议版本和加密算法来阻止使用可能存在缺陷的低版本 TLS 协议或加密算法的客户端请求。

Both the TLS protocol versions and cipher properties can take multiple values, separated by commas. 协议版本和加密算法的值可能取决于您正在使用的 TLS 提供程序。 如果 OpenSSL 可用,Pulsar 将使用 OpenSSL,但如果 OpenSSL 不可用,Pulsar 将默认返回 JDK 实现。

  1. tlsProtocols=TLSv1.3,TLSv1.2
  2. tlsCiphers=TLS_DH_RSA_WITH_AES_256_GCM_SHA384,TLS_DH_RSA_WITH_AES_256_CBC_SHA

OpenSSL currently supports TLSv1.1, TLSv1.2 and TLSv1.3 for the protocol version. You can acquire a list of supported cipher from the openssl ciphers command, i.e. openssl ciphers -tls1_3.

For JDK 11, you can obtain a list of supported values from the documentation:

Proxy配置

代理需要为连接到代理的客户端和连接到 broker 的代理这两个方向上配置 TLS。

  1. # For clients connecting to the proxy
  2. tlsEnabledInProxy=true
  3. tlsCertificateFilePath=/path/to/broker.cert.pem
  4. tlsKeyFilePath=/path/to/broker.key-pk8.pem
  5. tlsTrustCertsFilePath=/path/to/ca.cert.pem
  6. # For the proxy to connect to brokers
  7. tlsEnabledWithBroker=true
  8. brokerClientTrustCertsFilePath=/path/to/ca.cert.pem

客户端配置

When you enable the TLS transport encryption, you need to configure the client to use https:// and port 8443 for the web service URL, and pulsar+ssl:// and port 6651 for the broker service URL.

As the server certificate that you generated above does not belong to any of the default trust chains, you also need to either specify the path the trust cert (recommended), or tell the client to allow untrusted server certs.

Hostname verification

主机名验证是一种 TLS 安全特性,如果 “CommonName” 与所连接的主机名不匹配,客户机可以拒绝连接到该服务器。 By default, Pulsar clients disable hostname verification, as it requires that each broker has a DNS record and a unique cert.

此外,由于管理员对证书颁发机构拥有完全的控制权,一个恶意参与者不太可能实现中间人攻击。 “allowInsecureConnection” allows the client to connect to servers whose cert has not been signed by an approved CA. 客户端默认禁用 “allowInsecureConnection”,您也应该始终在生产环境中禁用 “allowInsecureConnection”。 只要您禁用 “allowInsecureConnection”,中间人攻击就会要求攻击者具有访问 CA 的权限。

One scenario where you may want to enable hostname verification is where you have multiple proxy nodes behind a VIP, and the VIP has a DNS record, for example, pulsar.mycompany.com. In this case, you can generate a TLS cert with pulsar.mycompany.com as the “CommonName,” and then enable hostname verification on the client.

下面的例子展示了 Java 客户机禁用主机名验证,但是您可以忽略这一点,因为客户机默认禁用主机名验证。 C++/python/Node.js 客户端现在也已经允许配置这个了。

命令行工具

命令行工具如:pulsar-adminpulsar-perfpulsar-client都使用 Pulsar 安装路径中的conf/client.conf配置文件。

要使用 Pulsar 的 CLI 工具使用 TLS 传输,您需要向该文件添加以下参数:

  1. webServiceUrl=https://broker.example.com:8443/
  2. brokerServiceUrl=pulsar+ssl://broker.example.com:6651/
  3. useTls=true
  4. tlsAllowInsecureConnection=false
  5. tlsTrustCertsFilePath=/path/to/ca.cert.pem
  6. tlsEnableHostnameVerification=false

Java 客户端

  1. import org.apache.pulsar.client.api.PulsarClient;
  2. PulsarClient client = PulsarClient.builder()
  3. .serviceUrl("pulsar+ssl://broker.example.com:6651/")
  4. .enableTls(true)
  5. .tlsTrustCertsFilePath("/path/to/ca.cert.pem")
  6. .enableTlsHostnameVerification(false) // false by default, in any case
  7. .allowTlsInsecureConnection(false) // false by default, in any case
  8. .build();

Python client

  1. from pulsar import Client
  2. client = Client("pulsar+ssl://broker.example.com:6651/",
  3. tls_hostname_verification=True,
  4. tls_trust_certs_file_path="/path/to/ca.cert.pem",
  5. tls_allow_insecure_connection=False) // defaults to false from v2.2.0 onwards

C++ client

  1. #include <pulsar/Client.h>
  2. ClientConfiguration config = ClientConfiguration();
  3. config.setUseTls(true); // shouldn't be needed soon
  4. config.setTlsTrustCertsFilePath(caPath);
  5. config.setTlsAllowInsecureConnection(false);
  6. config.setAuth(pulsar::AuthTls::create(clientPublicKeyPath, clientPrivateKeyPath));
  7. config.setValidateHostName(true);

Node.js 客户端

  1. const Pulsar = require('pulsar-client');
  2. (async () => {
  3. const client = new Pulsar.Client({
  4. serviceUrl: 'pulsar+ssl://broker.example.com:6651/',
  5. tlsTrustCertsFilePath: '/path/to/ca.cert.pem',
  6. });
  7. })();

C# client

  1. var certificate = new X509Certificate2("ca.cert.pem");
  2. var client = PulsarClient.Builder()
  3. .TrustedCertificateAuthority(certificate) //If the CA is not trusted on the host, you can add it explicitly.
  4. .VerifyCertificateAuthority(true) //Default is 'true'
  5. .VerifyCertificateName(false) //Default is 'false'
  6. .Build();