1.elasticsearch安装 (CentOS 7)
为了安装方便,我一般下载RPM 安装包。 我这里版本是 6.2.2
rpm -ivh elasticsearch-6.2.2.rpm
使用systemd
管理elasticsearch服务
systemctl daemon-reload ##重新载入systemd
systemctl enable elasticsearch ##设置自动启动
systemctl start elasticsearch ##启动服务
我们可以通过服务配置文件找到工作目录
cat /usr/lib/systemd/system/elasticsearch.service
这里工作目录为:/usr/share/elasticsearch
2.安装并配置searchguard
切到elasticsearch工作目录
bin/elasticsearch-plugin install -b com.floragunn:search-guard-6:6.2.2-21.0
切换到 elasticsearch/plugins/search-guard-6/tools 安装demo
./install_demo_configuration.sh
连续三个输入 y 接受
这个操作会初始化search-guard的一些配置,并把demo 证书安装到elasticsearch配置中
现在重启elasticsearch服务,利用curl命令测试 默认用户名密码都是 admin
curl -k -u admin:admin https://localhost:9200
接下来根据自己的需求,调整search-guard 和 elasticsearch配置,比如去掉一些不必要的权限角色,修改admin密码(利用tools目录下的hash.sh脚本生成密码),增加用户等。
首先创建自己的证书,可以使用工具包search-guard-tlstool,可在maven库中搜索并下载压缩包(https://search.maven.org)
解压后,在search-guard-tlstool 相关目录下的config文件中参考默认配置文件,配置自己的证书信息,然后在search-guard-tlstool
目录下 利用命令生成相关证书
tools/sgtlstool.sh -c config/tlsconfig.yml -ca -crt
此时在该目录下,有个out目录,生成的相关证书都在里面,将该目录拷贝到 /etc/elasticsearch下,参考out中 node_ elasticsearch_ config_snippet.yml内容修改elasticsearch.yml配置文件,为了方便可以直接复制,然后修改证书路径(此时证书都在out目录下)。
修改完成后,重启elasticsearch服务。
注意:
1.如果是生产环境,移除elasticsearch.yml中的以下两个配置,并删除之前安装demo 配置时生成的所有证书
searchguard.allow_unsafe_democertificates: true
searchguard.allow_default_init_sgindex: true
2.elasticsearch 访问的域名(hostname)必须和节点证书一致
3.java 访问elasticsearch服务
Elasticsearch官方推荐使用REST Client进行访问,后续版本会移除TransportClient,所以我使用 elasticsearch-rest-client 作为客户端,放弃了spring-data-elasticsearch,当然你也可以选择spring-data-jest
1)添加maven依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.2.2</version>
</dependency>
2)准备证书
因为安装了search-guard,所以访问需要使用 客户端证书访问 或者 基于HTTP Basic Authentication的用户名和密码访问。并且java访问https必须设置证书信任,否则会如下错误:
sun.security.validator.ValidatorException: PKIX path building failed
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
这里选择使用客户端证书进行访问,所以要为java调用准备两个证书:
客户端证书 和 供elasticsearch服务https访问的ssl证书。需要将之前out目录下的相关证书转为jks格式,以下是转换命令:
1.将key和证书导入到一个 PKCS12 文件,这里必须输入源key文件访问密码,以及新文件的新密码
openssl pkcs12 -export -in /opt/cloudera/security/pki/hostname.pem \
-inkey /opt/cloudera/security/pki/hostname.key -out /tmp/hostname.p12 \
-name hostname
2.将PKCS12 文件转为 java keystore文件(JKS)
keytool -importkeystore -srckeystore /tmp/hostname.p12 -srcstoretype PKCS12 \
-srcstorepass password -alias hostname -deststorepass password \
-destkeypass password -destkeystore /opt/cloudera/security/jks/hostname-keystore.jks
现在需要通过以上方式把客户端证书,https的ssl证书都转为jks文件。
如ssl证书转换:
openssl pkcs12 -export -in node1_http.pem -inkey node1_http.key -out node1_http.p12 -name node1_http
Enter pass phrase for node1_http.key:
Enter Export Password:
Verifying - Enter Export Password:
keytool -importkeystore -srckeystore node1_http.p12 -srcstoretype PKCS12 -srcstorepass node_pass -alias node1_http -deststorepass node_pass -destkeypass node_pass -destkeystore node1_http.jks
正在将密钥库 node1_http.p12 导入到 node1_http.jks...
同样的方式完成 客户端用户证书转换,比如我们会生成 client_user.jks文件
3)java客户端 访问初始化
现在将前面准备的client_user.jks 和 node1 _http.jks 导入项目的resources/cert目录下
#封装信任证书
KeyStore trustStore = KeyStore.getInstance("jks");
InputStream is = ElasticsearchClient.class.getResourceAsStream("/cert/node1_http.jks")
#"node_pass" 为设置的文件访问密码,可以设置为参数传入
trustStore.load(is, "node_pass".toCharArray());
#封装客户端证书
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(ElasticsearchClient.class.getResourceAsStream("/cert/client_user.jks"), "node_pass".toCharArray());
#生成SSLContext
SSLContextBuilder sslBuilder = SSLContexts.custom()
.loadTrustMaterial(trustStore, null)
.loadKeyMaterial(keyStore,"node_pass".toCharArray());
final SSLContext sslContext = sslBuilder.build();
#创建客户端builder
RestClientBuilder builder = RestClient.builder(new HttpHost("node1.example.com", 9200, "https"));
#设置连接失败监听
builder.setFailureListener(new RestClient.FailureListener() {
@Override
public void onFailure(HttpHost host) {
LOG.error("connect failed.the host:" + host.getHostName());
}
});
#设置SSLContext
builder.setHttpClientConfigCallback(httpClientBuilder ->
httpClientBuilder.setSSLContext(sslContext));
#设置相关时长
builder.setRequestConfigCallback(requestConfigBuilder ->
requestConfigBuilder.setConnectTimeout(5000)
.setSocketTimeout(60000));
builder.setMaxRetryTimeoutMillis(60000);
#生成 客户端
RestClient restClient = builder.build();
#进行访问测试
Response response = restClient.performRequest("GET", "/");
RequestLine requestLine = response.getRequestLine();
HttpHost host = response.getHost();
int statusCode = response.getStatusLine().getStatusCode();
Header[] headers = response.getHeaders();
String responseBody = EntityUtils.toString(response.getEntity());