Using TLS with KeyStore configure

概述

Apache Pulsar 支持在 Pulsar 服务端和客户端之间使用 TLS 加密TLS 认证。 默认使用 PEM 格式的配置文件。 本文包含了使用KeyStore配置TLS的描述信息。

KeyStore 配置 TLS 加密

生成 TLS key 和证书

部署 TLS 的第一步是为集群中的每台机器生成秘钥和证书。 你可以使用 Java 的keytool工具去完成这个任务。 我们首先将为每台 Broker 生成一个临时的 keystore,以便我们能够使用 CA 导出和进行签名。

  1. keytool -keystore broker.keystore.jks -alias localhost -validity {validity} -genkeypair -keyalg RSA

你必须在上面的命令中指定两个参数:

  1. keystore: 这个 keystore 文件保存了证书信息。 这个* keystore *文件包含了证书的私有秘钥信息;因此,你必须安全的保存它。
  2. validity: 证书的有效时间。

确保通用名称(CN) 与服务器完全合格的域名(FQDN) 完全匹配。 客户端将会把 CN 与 DNS 域名进行比较,以确保它确实连接到所需的服务器,而不是恶意的连接。

创建自定义 CA

在第一步之后,集群中的每个 Broker 将包含一个公私钥对,并且拥有用来识别机器的证书。 然而,证书是没有签名的,这意味着攻击者可以制作这样一份证书,来假装是任何机器。

因此,重要的是要防止伪造证书,为此要在为集群中的每台机器进行签名。 证书颁发机构(CA)负责签发证书。 CA 的工作内容类似签发护照的政府部门,即每本护照都有政府的印章(签名),这使得每本护照难以被伪造。 其他国家的政府通过验证这个印章,确保护照是真实的。 同样,CA 签署证书,并且通过签名加密证书,保证证书在不能被伪造。 因此,只要 CA 是一个可以信任的机构,就能确保客户端能够连上真正的服务器。

  1. openssl req -new -x509 -keyout ca-key -out ca-cert -days 365

CA 生成的是一个简单的公私钥对和证书,并打算签署其他证书。

下一步是将生成的CA 添加到客户端的信任秘钥库,以便客户端能够信任这个CA:

  1. keytool -keystore client.truststore.jks -alias CARoot -import -file ca-cert

注意:你可以通过在 Broker 上配置lsRequireTrustedClientCertOnConnecttrue来配置客户端需要经过认证才能访问。那么你必须总是为每个 Broker 提供一个可信任的库,并且它拥有所有用来给客户端秘钥签名的 CA 证书。

  1. keytool -keystore broker.truststore.jks -alias CARoot -import -file ca-cert

与存储每个机器自身身份的密钥库形成对比, 客户端信任的秘钥库是存储客户端应信任的所有证书 。 将证书导入一个可信赖库,意味着信任由该证书签名的所有证书。 As the analogy above, trusting the government (CA) also means trusting all passports (certificates) that it has issued. This attribute is called the chain of trust, and it is particularly useful when deploying TLS on a large BookKeeper cluster. You can sign all certificates in the cluster with a single CA, and have all machines share the same truststore that trusts the CA. That way all machines can authenticate all other machines.

签署证书

The next step is to sign all certificates in the keystore with the CA we generated. First, you need to export the certificate from the keystore:

  1. keytool -keystore broker.keystore.jks -alias localhost -certreq -file cert-file

Then sign it with the CA:

  1. openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file -out cert-signed -days {validity} -CAcreateserial -passin pass:{ca-password}

Finally, you need to import both the certificate of the CA and the signed certificate into the keystore:

  1. keytool -keystore broker.keystore.jks -alias CARoot -import -file ca-cert
  2. keytool -keystore broker.keystore.jks -alias localhost -import -file cert-signed

The definitions of the parameters are the following:

  1. keystore: the location of the keystore
  2. ca-cert: the certificate of the CA
  3. ca-key: the private key of the CA
  4. ca-password: the passphrase of the CA
  5. cert-file: the exported, unsigned certificate of the broker
  6. cert-signed: the signed certificate of the broker

Configuring brokers

Brokers enable TLS by provide valid brokerServicePortTls and webServicePortTls, and also need set tlsEnabledWithKeyStore to true for using KeyStore type configuration. Besides this, KeyStore path, KeyStore password, TrustStore path, and TrustStore password need to provided. And since broker will create internal client/admin client to communicate with other brokers, user also need to provide config for them, this is similar to how user config the outside client/admin-client. If tlsRequireTrustedClientCertOnConnect is true, broker will reject the Connection if the Client Certificate is not trusted.

The following TLS configs are needed on the broker side:

  1. tlsEnabledWithKeyStore=true
  2. # key store
  3. tlsKeyStoreType=JKS
  4. tlsKeyStore=/var/private/tls/broker.keystore.jks
  5. tlsKeyStorePassword=brokerpw
  6. # trust store
  7. tlsTrustStoreType=JKS
  8. tlsTrustStore=/var/private/tls/broker.truststore.jks
  9. tlsTrustStorePassword=brokerpw
  10. # interal client/admin-client config
  11. brokerClientTlsEnabled=true
  12. brokerClientTlsEnabledWithKeyStore=true
  13. brokerClientTlsTrustStoreType=JKS
  14. brokerClientTlsTrustStore=/var/private/tls/client.truststore.jks
  15. brokerClientTlsTrustStorePassword=clientpw

NOTE: it is important to restrict access to the store files via filesystem permissions.

Optional settings that may worth consider:

  1. tlsClientAuthentication=false: Enable/Disable using TLS for authentication. This config when enabled will authenticate the other end of the communication channel. It should be enabled on both brokers and clients for mutual TLS.
  2. tlsCiphers=[TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256], A cipher suite is a named combination of authentication, encryption, MAC and key exchange algorithm used to negotiate the security settings for a network connection using TLS network protocol. By default, it is null. OpenSSL Ciphers JDK Ciphers
  3. tlsProtocols=[TLSv1.3,TLSv1.2] (list out the TLS protocols that you are going to accept from clients). By default, it is not set.

Configuring Clients

This is similar to [TLS encryption configuing for client with PEM type](/docs/zh-CN/security-tls-transport#Client configuration). For a a minimal configuration, user need to provide the TrustStore information.

例如:

  1. for Command-line tools like pulsar-admin, pulsar-perf, and pulsar-client use the conf/client.conf config file in a Pulsar installation.

    1. webServiceUrl=https://broker.example.com:8443/
    2. brokerServiceUrl=pulsar+ssl://broker.example.com:6651/
    3. useKeyStoreTls=true
    4. tlsTrustStoreType=JKS
    5. tlsTrustStorePath=/var/private/tls/client.truststore.jks
    6. tlsTrustStorePassword=clientpw
  2. for java client

    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. .useKeyStoreTls(true)
    6. .tlsTrustStorePath("/var/private/tls/client.truststore.jks")
    7. .tlsTrustStorePassword("clientpw")
    8. .allowTlsInsecureConnection(false)
    9. .build();
  3. for java admin client

  1. PulsarAdmin amdin = PulsarAdmin.builder().serviceHttpUrl("https://broker.example.com:8443")
  2. .useKeyStoreTls(true)
  3. .tlsTrustStorePath("/var/private/tls/client.truststore.jks")
  4. .tlsTrustStorePassword("clientpw")
  5. .allowTlsInsecureConnection(false)
  6. .build();

TLS authentication with KeyStore configure

This similar to TLS authentication with PEM type

broker authentication config

broker.conf

  1. # Configuration to enable authentication
  2. authenticationEnabled=true
  3. authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderTls
  4. # this should be the CN for one of client keystore.
  5. superUserRoles=admin
  6. # Enable KeyStore type
  7. tlsEnabledWithKeyStore=true
  8. requireTrustedClientCertOnConnect=true
  9. # key store
  10. tlsKeyStoreType=JKS
  11. tlsKeyStore=/var/private/tls/broker.keystore.jks
  12. tlsKeyStorePassword=brokerpw
  13. # trust store
  14. tlsTrustStoreType=JKS
  15. tlsTrustStore=/var/private/tls/broker.truststore.jks
  16. tlsTrustStorePassword=brokerpw
  17. # interal client/admin-client config
  18. brokerClientTlsEnabled=true
  19. brokerClientTlsEnabledWithKeyStore=true
  20. brokerClientTlsTrustStoreType=JKS
  21. brokerClientTlsTrustStore=/var/private/tls/client.truststore.jks
  22. brokerClientTlsTrustStorePassword=clientpw
  23. # internal auth config
  24. brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls
  25. brokerClientAuthenticationParameters={"keyStoreType":"JKS","keyStorePath":"/var/private/tls/client.keystore.jks","keyStorePassword":"clientpw"}
  26. # currently websocket not support keystore type
  27. webSocketServiceEnabled=false

client authentication configuring

Besides the TLS encryption configuring. The main work is configuring the KeyStore, which contains a valid CN as client role, for client.

例如:

  1. for Command-line tools like pulsar-admin, pulsar-perf, and pulsar-client use the conf/client.conf config file in a Pulsar installation.

    1. webServiceUrl=https://broker.example.com:8443/
    2. brokerServiceUrl=pulsar+ssl://broker.example.com:6651/
    3. useKeyStoreTls=true
    4. tlsTrustStoreType=JKS
    5. tlsTrustStorePath=/var/private/tls/client.truststore.jks
    6. tlsTrustStorePassword=clientpw
    7. authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls
    8. authParams={"keyStoreType":"JKS","keyStorePath":"/path/to/keystorefile","keyStorePassword":"keystorepw"}
  2. for java client

    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. .useKeyStoreTls(true)
    6. .tlsTrustStorePath("/var/private/tls/client.truststore.jks")
    7. .tlsTrustStorePassword("clientpw")
    8. .allowTlsInsecureConnection(false)
    9. .authentication(
    10. "org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls",
    11. "keyStoreType:JKS,keyStorePath:/var/private/tls/client.keystore.jks,keyStorePassword:clientpw")
    12. .build();
  3. for java admin client

    1. PulsarAdmin amdin = PulsarAdmin.builder().serviceHttpUrl("https://broker.example.com:8443")
    2. .useKeyStoreTls(true)
    3. .tlsTrustStorePath("/var/private/tls/client.truststore.jks")
    4. .tlsTrustStorePassword("clientpw")
    5. .allowTlsInsecureConnection(false)
    6. .authentication(
    7. "org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls",
    8. "keyStoreType:JKS,keyStorePath:/var/private/tls/client.keystore.jks,keyStorePassword:clientpw")
    9. .build();

启用 TLS 日志

You can enable TLS debug logging at the JVM level by starting the brokers and/or clients with javax.net.debug system property. 例如:

  1. -Djavax.net.debug=all

You can find more details on this in Oracle documentation on debugging SSL/TLS connections.