启用 SSL

Solr 可以使用安全套接字层加密 (SSL) 加密与客户端之间的通信以及 SolrCloud 模式中的节点之间的通信。

本部分介绍如何使用自签名证书启用 SSL。

有关 SSL 证书和密钥的背景信息,请参阅 http://www.tldp.org/HOWTO/SSL-Certificates-HOWTO/

为 Solr 配置 SSL

生成自签名证书和密钥

要生成自签名证书和用于对服务器和客户端进行身份验证的单个密钥,我们将使用 JDK keytool 命令并创建一个单独的关键库。此关键库还将用作下面的信任库。可以将 JDK 附带的关键库用于这些目的,并使用单独的信任库,但此处未介绍这些选项。

在二进制 Solr 发行版的 server/etc/ 目录中运行以下命令。假设您在 PATH 中有 JDK keytool 实用程序,并且 openssl 也在您的 PATH 中。有关 Windows 和 Solaris 的 OpenSSL 二进制文件,请参阅 https://wiki.openssl.org/index.php/Binaries

-ext SAN=…​ keytool 选项允许您指定如果选择需要,将在主机名验证期间允许的所有 DNS 名称和/或 IP 地址。

除了 localhost127.0.0.1,此示例还包括 Solr 节点将运行在其上的机器的 LAN IP 地址 192.168.1.3

$ keytool -genkeypair -alias solr-ssl -keyalg RSA -keysize 2048 -keypass secret -storepass secret -validity 9999 -keystore solr-ssl.keystore.p12 -storetype PKCS12 -ext SAN=DNS:localhost,IP:192.168.1.3,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country"

上述命令将在当前目录中创建一个名为 solr-ssl.keystore.p12 的关键库文件。

将证书和密钥转换为 PEM 格式以供 curl 使用

使用 openssl 命令将包括证书和密钥的 PKCS12 格式关键库转换为 PEM 格式

$ openssl pkcs12 -in solr-ssl.keystore.p12 -out solr-ssl.pem

如果您想在 OS X Yosemite (10.10) 上使用 curl,则需要创建 PEM 格式的仅证书版本,如下所示

$ openssl pkcs12 -nokeys -in solr-ssl.keystore.p12 -out solr-ssl.cacert.pem

Solr 控制脚本已设置好将与 SSL 相关的 Java 系统属性传递给 JVM。要激活 SSL 设置,请取消注释并更新以 SOLR_SSL_* 开头的属性集,在 *nix 系统上为 bin/solr.in.sh,在 Windows 上为 bin\solr.in.cmd

*nix (solr.in.sh)

如果您按照 将 Solr 投入生产 中概述的步骤在 Linux 上将 Solr 设置为服务,则在 /var/solr/solr.in.sh 中进行这些更改。
# Enables HTTPS. It is implicitly true if you set SOLR_SSL_KEY_STORE. Use this config
# to enable https module with custom jetty configuration.
SOLR_SSL_ENABLED=true
# Uncomment to set SSL-related system properties
# Be sure to update the paths to the correct keystore for your environment
SOLR_SSL_KEY_STORE=etc/solr-ssl.keystore.p12
SOLR_SSL_KEY_STORE_PASSWORD=secret
SOLR_SSL_TRUST_STORE=etc/solr-ssl.keystore.p12
SOLR_SSL_TRUST_STORE_PASSWORD=secret
# Require clients to authenticate
SOLR_SSL_NEED_CLIENT_AUTH=false
# Enable clients to authenticate (but not require)
SOLR_SSL_WANT_CLIENT_AUTH=false
# SSL Certificates contain host/ip "peer name" information that is validated by default. Setting
# this to false can be useful to disable these checks when re-using a certificate on many hosts.
# This will also be used for the default value of whether SNI Host checking should be enabled.
SOLR_SSL_CHECK_PEER_NAME=true

Windows (solr.in.cmd)

REM Enables HTTPS. It is implicitly true if you set SOLR_SSL_KEY_STORE. Use this config
REM to enable https module with custom jetty configuration.
set SOLR_SSL_ENABLED=true
REM Uncomment to set SSL-related system properties
REM Be sure to update the paths to the correct keystore for your environment
set SOLR_SSL_KEY_STORE=etc/solr-ssl.keystore.p12
set SOLR_SSL_KEY_STORE_PASSWORD=secret
set SOLR_SSL_TRUST_STORE=etc/solr-ssl.keystore.p12
set SOLR_SSL_TRUST_STORE_PASSWORD=secret
REM Require clients to authenticate
set SOLR_SSL_NEED_CLIENT_AUTH=false
REM Enable clients to authenticate (but not require)
set SOLR_SSL_WANT_CLIENT_AUTH=false
REM SSL Certificates contain host/ip "peer name" information that is validated by default. Setting
REM this to false can be useful to disable these checks when re-using a certificate on many hosts.
REM This will also be used for the default value of whether SNI Host checking should be enabled.
set SOLR_SSL_CHECK_PEER_NAME=true
客户端身份验证设置
启用 SOLR_SSL_NEED_CLIENT_AUTHSOLR_SSL_WANT_CLIENT_AUTH,但不能同时启用两者。它们是互斥的,Jetty 将选择其中一个,这可能不是您所期望的。如果您想禁用客户端证书的主机名验证,应将 SOLR_SSL_CLIENT_HOSTNAME_VERIFICATION 设置为 false。

启动 Solr 时,bin/solr 脚本会包含这些设置,并将它们作为系统属性传递给 JVM。

如果您在用户管理的集群或单节点安装中运行 Solr,则可以跳过 启动用户管理的集群或单节点 Solr

但是,如果您使用 SolrCloud,则需要在启动 Solr 之前 配置 ZooKeeper

通过 Hadoop 凭据存储进行密码分发

Solr 支持从 Hadoop 凭据存储中读取密钥库和信任库密码。如果凭据存储已经处理密码轮换和分发,则这种方法可能很有用。

如果您不使用 Hadoop 凭据存储,则可以跳过此步骤。

Hadoop 凭据存储可以使用以下两个步骤与 Solr 一起使用。

提供 Hadoop 凭据存储

创建 Hadoop credstore 文件,并使用实际密钥库密码定义以下条目。

solr.jetty.keystore.password
solr.jetty.truststore.password
javax.net.ssl.keyStorePassword
javax.net.ssl.trustStorePassword

请注意,如果未设置 javax.net.ssl.* 配置,它们将回退到相应的 solr.jetty.* 配置。

配置 Solr 以使用 Hadoop 凭据存储

Solr 需要配置三个参数才能将凭据存储文件用于密钥库密码。

solr.ssl.credential.provider.chain

必需

默认值:无

凭据提供程序链。这应设置为 hadoop

SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH

必需

默认值:无

凭据存储文件的路径。

HADOOP_CREDSTORE_PASSWORD

必需

默认值:无

凭据存储的密码。

*nix (solr.in.sh)

SOLR_OPTS=" -Dsolr.ssl.credential.provider.chain=hadoop"
SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH=localjceks://file/home/solr/hadoop-credential-provider.jceks
HADOOP_CREDSTORE_PASSWORD="credStorePass123"

Windows (solr.in.cmd)

set SOLR_OPTS=" -Dsolr.ssl.credential.provider.chain=hadoop"
set SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH=localjceks://file/home/solr/hadoop-credential-provider.jceks
set HADOOP_CREDSTORE_PASSWORD="credStorePass123"

配置 ZooKeeper

ZooKeeper 不支持与 Solr 等客户端的加密通信。有几个相关的 JIRA 工单正在规划/处理 SSL 支持:ZOOKEEPER-235ZOOKEEPER-236ZOOKEEPER-1000;和 ZOOKEEPER-2120

在创建上面描述的关键库且在启动任何 SolrCloud 节点之前,您必须在 ZooKeeper 中配置 Solr 集群属性,以便 Solr 节点了解通过 SSL 进行通信。

本部分假定您已创建并启动了外部 ZooKeeper。有关更多信息,请参阅 ZooKeeper 集群配置

在任何 Solr 节点启动之前,需要将 urlScheme 集群范围属性设置为 https。以下示例使用 Solr 附带的 zkcli 工具来执行此操作。

*nix 命令

$ server/scripts/cloud-scripts/zkcli.sh -zkhost server1:2181,server2:2181,server3:2181 -cmd clusterprop -name urlScheme -val https

Windows 命令

C:\> server\scripts\cloud-scripts\zkcli.bat -zkhost server1:2181,server2:2181,server3:2181 -cmd clusterprop -name urlScheme -val https

务必针对您的系统使用正确的 zkhost 值。如果您已将 ZooKeeper 集群设置为对 Solr 使用 chroot,请确保将其包含在 zkhost 字符串中,例如 -zkhost server1:2181,server2:2181,server3:2181/solr

更新现有集合的集群属性

如果您正在使用 SolrCloud 且在启用 SSL 之前已创建集合,则需要更新集群属性以使用 HTTPS。

如果您没有现有集合或未使用 SolrCloud,则可以跳过此步骤并启动 Solr。

可以使用集合 API CLUSTERPROP 命令更新集群属性,如下例所示(根据您的系统更新主机名和端口)

$ http://localhost:8983/solr/admin/collections?action=CLUSTERPROP&name=urlScheme&val=https

此命令只需在集群的一个节点上运行,更改将应用于所有节点。

一旦完成此步骤和所有其他步骤,您就可以继续启动 Solr。

在启用 SSL 后启动 Solr

启动用户管理的集群或单节点 Solr

使用 Solr 控制脚本启动 Solr,如下面的示例所示。根据需要自定义所示参数的值,并添加系统中使用的任何参数。

*nix 命令

$ bin/solr -p 8984

Windows 命令

C:\> bin\solr.cmd -p 8984

启动 SolrCloud

如果您已在 solr.in.sh/solr.in.cmd 中定义了 ZK_HOST(请参阅 更新 Solr 包含文件),则可以从以下所有 bin/solr/bin\solr.cmd 命令中省略 -z <zk host string>

使用 Solr 控制脚本启动每个 Solr 节点,如下面的示例所示。根据需要自定义所示参数的值,并添加系统中使用的任何参数。

如果您创建的 SSL 密钥不包含 Solr 节点运行的所有 DNS 名称或 IP 地址,您可以通过设置 -Dsolr.ssl.checkPeerName=false 系统属性来告知 Solr 跳过节点间通信的主机名验证。

\*nix

$ bin/solr -cloud -s cloud/node1 -z server1:2181,server2:2181,server3:2181 -p 8984

Windows

C:\> bin\solr.cmd -cloud -s cloud\node1 -z server1:2181,server2:2181,server3:2181

自动重新加载 KeyStore/TrustStore

Solr 服务器

在更新证书时,Solr 可以自动重新加载 KeyStore/TrustStore,无需重新启动。使用 SSL 时默认启用此功能,但可以通过将环境变量 SOLR_SSL_RELOAD_ENABLED 设置为 false 来禁用。默认情况下,Solr 每 30 秒检查一次 KeyStore 中的更新,但可以在启动时通过传递系统属性 solr.jetty.sslContext.reload.scanInterval 和新的间隔(以秒为单位)来更新此间隔。请注意,不会主动监视 truststore 文件,因此如果您需要对 truststore 应用更改,则需要更新它,然后触及 keystore 以触发重新加载。

SolrJ 客户端

Http2SolrClient 构建器有一个方法 withKeyStoreReloadInterval(long interval, TimeUnit unit),用于初始化一个扫描器,该扫描器将监视并更新 keystore 和 truststore 中的更改。如果您使用的是 CloudHttp2SolrClient,则可以使用 withInternalClientBuilder(Http2SolrClient.Builder internalClientBuilder) 使用 keystore 重新加载间隔来配置内部 http 客户端。最短重新加载间隔为 1 秒。如果没有设置(或设置为 0 或负值),客户端中的 keystore/truststore 将不会更新。

客户端操作示例

OS X Mavericks (10.9) 上的 curl 降低了 SSL 支持。有关允许单向 SSL 的更多信息和解决方法,请参阅 https://curl.se/mail/archive-2013-10/0036.html。OS X Yosemite (10.10) 上的 curl 已得到改进 - 可以进行双向 SSL - 请参阅 https://curl.se/mail/archive-2014-10/0053.html

以下部分中的 curl 命令在 OS X Yosemite(10.10)系统上的 curl 中无法使用。相反,使用 -E 参数提供的证书必须采用 PKCS12 格式,并且使用 --cacert 参数提供的文件必须仅包含 CA 证书,而不能包含密钥(有关创建此文件的说明,请参阅上方

$ curl -E solr-ssl.keystore.p12:secret --cacert solr-ssl.cacert.pem ...
如果您的操作系统不包含 curl,您可以从此处下载二进制文件:https://curl.se/download.html

使用 bin/solr 创建 SolrCloud 集合

使用 _default configset 创建一个名为 mycollection 的 2 分片、replicationFactor=1 的集合

*nix 命令
bin/solr create -c mycollection -shards 2
Windows 命令
bin\solr.cmd create -c mycollection -shards 2

create 操作会将包含文件中设置的 SOLR_SSL_* 属性传递给用于创建集合的 SolrJ 代码。

使用 curl 检索 SolrCloud 集群状态

若要获取最终的集群状态(同样,如果您未启用客户端认证,请移除 -E solr-ssl.pem:secret 选项)

$ curl -E solr-ssl.pem:secret --cacert solr-ssl.pem "https://localhost:8984/solr/admin/collections?action=CLUSTERSTATUS&indent=on"

您应该会收到类似以下内容的响应

{
  "responseHeader":{
    "status":0,
    "QTime":2041},
  "cluster":{
    "collections":{
      "mycollection":{
        "shards":{
          "shard1":{
            "range":"80000000-ffffffff",
            "state":"active",
            "replicas":{"core_node1":{
                "state":"active",
                "base_url":"https://127.0.0.1:8984/solr",
                "core":"mycollection_shard1_replica1",
                "node_name":"127.0.0.1:8984_solr",
                "leader":"true"}}},
          "shard2":{
            "range":"0-7fffffff",
            "state":"active",
            "replicas":{"core_node2":{
                "state":"active",
                "base_url":"https://127.0.0.1:7574/solr",
                "core":"mycollection_shard2_replica1",
                "node_name":"127.0.0.1:7574_solr",
                "leader":"true"}}}},
        "router":{"name":"compositeId"},
        "replicationFactor":"1"}},
    "properties":{"urlScheme":"https"}}}

使用 post.jar 索引文档

使用 post.jar 将一些示例文档索引到上述创建的 SolrCloud 集合

$ cd example/exampledocs

$ java -Djavax.net.ssl.keyStorePassword=secret -Djavax.net.ssl.keyStore=../../server/etc/solr-ssl.keystore.p12 -Djavax.net.ssl.trustStore=../../server/etc/solr-ssl.keystore.p12 -Djavax.net.ssl.trustStorePassword=secret -Durl=https://localhost:8984/solr/mycollection/update -jar post.jar *.xml

使用 curl 查询

使用 curl 查询上述创建的 SolrCloud 集合,从包含上述创建的 PEM 格式证书和密钥的目录(例如,example/etc/)。如果您未启用客户端认证(系统属性 -Djetty.ssl.clientAuth=true),则可以移除 -E solr-ssl.pem:secret 选项

curl -E solr-ssl.pem:secret --cacert solr-ssl.pem "https://localhost:8984/solr/mycollection/select?q=*:*"

使用 CloudSolrClient 索引文档

从使用 SolrJ 的 java 客户端索引文档。在以下代码中,javax.net.ssl.* 系统属性以编程方式设置,但您也可以在 java 命令行中指定它们,如上述 post.jar 示例中所示

System.setProperty("javax.net.ssl.keyStore", "/path/to/solr-ssl.keystore.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "secret");
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
System.setProperty("javax.net.ssl.trustStore", "/path/to/solr-ssl.keystore.p12");
System.setProperty("javax.net.ssl.trustStorePassword", "secret");
System.setProperty("javax.net.ssl.trustStoreType", "pkcs12");
String zkHost = "127.0.0.1:2181";
CloudSolrClient client = new CloudSolrClient.Builder(Collections.singletonList(zkHost),Optional.empty()).withDefaultCollection("mycollection").build();
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", "1234");
doc.addField("name", "A lovely summer holiday");
client.add(doc);
client.commit();