Using TLS with KeyStore configure
概述
Apache Pulsar 支持在 Pulsar 服务端和客户端之间使用 TLS 加密和 TLS 认证。 默认使用 PEM 格式的配置文件。 本文包含了使用KeyStore配置TLS的描述信息。
KeyStore 配置 TLS 加密
生成 TLS key 和证书
部署 TLS 的第一步是为集群中的每台机器生成秘钥和证书。 你可以使用 Java 的keytool
工具去完成这个任务。 我们首先将为每台 Broker 生成一个临时的 keystore,以便我们能够使用 CA 导出和进行签名。
keytool -keystore broker.keystore.jks -alias localhost -validity {validity} -genkeypair -keyalg RSA
你必须在上面的命令中指定两个参数:
keystore
: 这个 keystore 文件保存了证书信息。 这个* keystore *文件包含了证书的私有秘钥信息;因此,你必须安全的保存它。validity
: 证书的有效时间。
确保通用名称(CN) 与服务器完全合格的域名(FQDN) 完全匹配。 客户端将会把 CN 与 DNS 域名进行比较,以确保它确实连接到所需的服务器,而不是恶意的连接。
创建自定义 CA
在第一步之后,集群中的每个 Broker 将包含一个公私钥对,并且拥有用来识别机器的证书。 然而,证书是没有签名的,这意味着攻击者可以制作这样一份证书,来假装是任何机器。
因此,重要的是要防止伪造证书,为此要在为集群中的每台机器进行签名。 证书颁发机构(CA)
负责签发证书。 CA 的工作内容类似签发护照的政府部门,即每本护照都有政府的印章(签名),这使得每本护照难以被伪造。 其他国家的政府通过验证这个印章,确保护照是真实的。 同样,CA 签署证书,并且通过签名加密证书,保证证书在不能被伪造。 因此,只要 CA 是一个可以信任的机构,就能确保客户端能够连上真正的服务器。
openssl req -new -x509 -keyout ca-key -out ca-cert -days 365
CA 生成的是一个简单的公私钥对和证书,并打算签署其他证书。
下一步是将生成的CA 添加到客户端的信任秘钥库,以便客户端能够信任这个CA:
keytool -keystore client.truststore.jks -alias CARoot -import -file ca-cert
注意:你可以通过在 Broker 上配置lsRequireTrustedClientCertOnConnect
为true
来配置客户端需要经过认证才能访问。那么你必须总是为每个 Broker 提供一个可信任的库,并且它拥有所有用来给客户端秘钥签名的 CA 证书。
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:
keytool -keystore broker.keystore.jks -alias localhost -certreq -file cert-file
Then sign it with the CA:
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:
keytool -keystore broker.keystore.jks -alias CARoot -import -file ca-cert
keytool -keystore broker.keystore.jks -alias localhost -import -file cert-signed
The definitions of the parameters are the following:
keystore
: the location of the keystoreca-cert
: the certificate of the CAca-key
: the private key of the CAca-password
: the passphrase of the CAcert-file
: the exported, unsigned certificate of the brokercert-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:
tlsEnabledWithKeyStore=true
# key store
tlsKeyStoreType=JKS
tlsKeyStore=/var/private/tls/broker.keystore.jks
tlsKeyStorePassword=brokerpw
# trust store
tlsTrustStoreType=JKS
tlsTrustStore=/var/private/tls/broker.truststore.jks
tlsTrustStorePassword=brokerpw
# interal client/admin-client config
brokerClientTlsEnabled=true
brokerClientTlsEnabledWithKeyStore=true
brokerClientTlsTrustStoreType=JKS
brokerClientTlsTrustStore=/var/private/tls/client.truststore.jks
brokerClientTlsTrustStorePassword=clientpw
NOTE: it is important to restrict access to the store files via filesystem permissions.
Optional settings that may worth consider:
- 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.
- 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
- tlsProtocols=[TLSv1.2,TLSv1.1,TLSv1] (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.
例如:
for Command-line tools like
pulsar-admin
,pulsar-perf
, andpulsar-client
use theconf/client.conf
config file in a Pulsar installation.webServiceUrl=https://broker.example.com:8443/
brokerServiceUrl=pulsar+ssl://broker.example.com:6651/
useKeyStoreTls=true
tlsTrustStoreType=JKS
tlsTrustStorePath=/var/private/tls/client.truststore.jks
tlsTrustStorePassword=clientpw
for java client
import org.apache.pulsar.client.api.PulsarClient;
PulsarClient client = PulsarClient.builder()
.serviceUrl("pulsar+ssl://broker.example.com:6651/")
.enableTls(true)
.useKeyStoreTls(true)
.tlsTrustStorePath("/var/private/tls/client.truststore.jks")
.tlsTrustStorePassword("clientpw")
.allowTlsInsecureConnection(false)
.build();
for java admin client
PulsarAdmin amdin = PulsarAdmin.builder().serviceHttpUrl("https://broker.example.com:8443")
.useKeyStoreTls(true)
.tlsTrustStorePath("/var/private/tls/client.truststore.jks")
.tlsTrustStorePassword("clientpw")
.allowTlsInsecureConnection(false)
.build();
TLS authentication with KeyStore configure
This similar to TLS authentication with PEM type
broker authentication config
broker.conf
# Configuration to enable authentication
authenticationEnabled=true
authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderTls
# this should be the CN for one of client keystore.
superUserRoles=admin
# Enable KeyStore type
tlsEnabledWithKeyStore=true
requireTrustedClientCertOnConnect=true
# key store
tlsKeyStoreType=JKS
tlsKeyStore=/var/private/tls/broker.keystore.jks
tlsKeyStorePassword=brokerpw
# trust store
tlsTrustStoreType=JKS
tlsTrustStore=/var/private/tls/broker.truststore.jks
tlsTrustStorePassword=brokerpw
# interal client/admin-client config
brokerClientTlsEnabled=true
brokerClientTlsEnabledWithKeyStore=true
brokerClientTlsTrustStoreType=JKS
brokerClientTlsTrustStore=/var/private/tls/client.truststore.jks
brokerClientTlsTrustStorePassword=clientpw
# internal auth config
brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls
brokerClientAuthenticationParameters={"keyStoreType":"JKS","keyStorePath":"/var/private/tls/client.keystore.jks","keyStorePassword":"clientpw"}
# currently websocket not support keystore type
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.
例如:
for Command-line tools like
pulsar-admin
,pulsar-perf
, andpulsar-client
use theconf/client.conf
config file in a Pulsar installation.webServiceUrl=https://broker.example.com:8443/
brokerServiceUrl=pulsar+ssl://broker.example.com:6651/
useKeyStoreTls=true
tlsTrustStoreType=JKS
tlsTrustStorePath=/var/private/tls/client.truststore.jks
tlsTrustStorePassword=clientpw
authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls
authParams={"keyStoreType":"JKS","keyStorePath":"/path/to/keystorefile","keyStorePassword":"keystorepw"}
for java client
import org.apache.pulsar.client.api.PulsarClient;
PulsarClient client = PulsarClient.builder()
.serviceUrl("pulsar+ssl://broker.example.com:6651/")
.enableTls(true)
.useKeyStoreTls(true)
.tlsTrustStorePath("/var/private/tls/client.truststore.jks")
.tlsTrustStorePassword("clientpw")
.allowTlsInsecureConnection(false)
.authentication(
"org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls",
"keyStoreType:JKS,keyStorePath:/var/private/tls/client.keystore.jks,keyStorePassword:clientpw")
.build();
for java admin client
PulsarAdmin amdin = PulsarAdmin.builder().serviceHttpUrl("https://broker.example.com:8443")
.useKeyStoreTls(true)
.tlsTrustStorePath("/var/private/tls/client.truststore.jks")
.tlsTrustStorePassword("clientpw")
.allowTlsInsecureConnection(false)
.authentication(
"org.apache.pulsar.client.impl.auth.AuthenticationKeyStoreTls",
"keyStoreType:JKS,keyStorePath:/var/private/tls/client.keystore.jks,keyStorePassword:clientpw")
.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. 例如:
-Djavax.net.debug=all
You can find more details on this in Oracle documentation on debugging SSL/TLS connections.