前言
- es在 6.8 和 7.1 版本后,核心安全功能(例如 TLS、文件和原生 Realm 身份验证,以及基于角色的访问控制)免费提供,如果使用的是高版本es则是开箱即用的,对于低版本的es安全功能是收费的,这里使用第三方的安全框架searchguard来加固低版本的es.但本次用es7.1.1来演示。
网上容器化安装的资料很少,这里 记录一下使用docker来安装。 - 所有操作均在考虑无外部网情况下离线安装(除了依赖的操作系统镜像)。
准备
-
数据卷目录映射
- 方便配置修改
- 数据需要持久化到宿主机。
-
材料清单
es_guard_variable
├── Dockerfile
├── elasticsearch-7.1.1-linux-x86_64.tar.gz
├── search-guard-7-7.1.1-35.0.0.zip
└── start.sh
search-guard-ssl-es-7.0.0.zip
编写dockerfile和启动脚本
- dockerfile
FROM nimmis/java-centos:oracle-8-jdk
ENV ES_VERSION=7.1.1 \
SG_PREFIX=7 \
SG_VERSION=7.1.1-35.0.0
#添加es并解压到目录
ADD ./elasticsearch-$ES_VERSION-linux-x86_64.tar.gz /data/es
#RUN mv elasticsearch-$ES_VERSION /data/es/elasticsearch
#使用COPY避免解压,方便后续使用isntall安装zip包
COPY ./search-guard-$SG_PREFIX-$SG_VERSION.zip /data/es
COPY ./start.sh /data/es
#由于es不能使用root启动,创建一个elasticsearch用户
RUN chmod +x /data/es/start.sh \
&& groupadd -g 1003 elasticsearch \
&& adduser -u 1003 -g 1003 -s /sbin/nologin elasticsearch \
&& chown -R elasticsearch:elasticsearch /data/es
EXPOSE 9200 9300
ENTRYPOINT ["/data/es/start.sh"]
- start.sh脚本
#!/bin/bash
ES_HOME=/data/es/elasticsearch-$ES_VERSION
SG_ZIP_PATH=/data/es/search-guard-$SG_PREFIX-$SG_VERSION.zip
#es和searchguard插件的配置目录
ES_CONFIG=$ES_HOME/config
SG_CONFIG=$ES_HOME/plugins/search-guard-$SG_PREFIX/sgconfig
#替换变量(运行时替换没有必要了,由于有数据卷,改的都在宿主机上了)
#sed -i "s/Xms_var/${Xms_size:-200m}/g" $ES_CONFIG/jvm.options
#sed -i "s/Xmx_var/${Xmx_size:-200m}/g" $ES_CONFIG/jvm.options
#判断是否已经安装过sg
if [ -d "$ES_HOME/plugins/search-guard-$SG_PREFIX" ]; then
rm -rf $ES_HOME/plugins/search-guard-$SG_PREFIX
fi
rm -rf $SG_CONFIG
#使用elasticsearch用户 安装,安装时需要手动输入 y并回车,这里用脚本代替
su elasticsearch -s /bin/bash -c "/bin/echo -e 'y\n' | $ES_HOME/bin/elasticsearch-plugin install file://$SG_ZIP_PATH"
#将客户端证书和信任证书移动到plugins/search-guard-$SG_PREFIX/sgconfig目录下
#由于后续可能会修改增加权限,改为映射数据卷,数据卷也不得行,容器被删除后,宿主机文件也没了
cp $ES_CONFIG/searchguard/* $SG_CONFIG
cp $ES_CONFIG/truststore.jks $SG_CONFIG
#如果直接映射SG_HOME,则会在创建容器时就创建目录,采用映射一个临时目录,然后在脚本中拷贝sg配置
#cp -rf $ES_HOME/temp_sgconfig/* $SG_CONFIG
#给sgadmin授权,es运行起来后需要用这个脚本来插入配置。
chown -R elasticsearch:elasticsearch $ES_HOME
chmod -R 777 $ES_HOME
echo "es配置目录:"
ls $ES_CONFIG
echo "=========================="
echo "sg插件目录:"
ls $SG_CONFIG
#运行es
su elasticsearch -s /bin/bash -c "$ES_HOME/bin/elasticsearch"
配置searchguard证书
- 解压ssl配置文件,修改脚本:search-guard-ssl-es-7.0.0/example-pki-scripts/example.sh
- 脚本文件介绍
- CA密码:根证书密码
- TS密码:信任证书密码
- Ks密码:keystore密码
文件名 | 含义 | 参数 |
---|---|---|
gen_client_node_cert.sh | 客户端证书 | 客户端节点名称,ks_pass,ca_pass |
gen_root_ca.sh | 根证书 | ca_pass,ts_pass |
gen_node_cert.sh | 节点证书 | 节点编号,ks_pass,capass |
- 如果分不清,可以全部设置成一样的,如下:
-
宿主机外部配置
-
我设置了log4j2日志级别为debug,方便安装过程中排查问题。
-
ssl中执行example.sh生成的3个脚本:
- hyq_cluster2-keystore.jks
- node-0-keystore.jks
- truststore.jks
-
将生成文件复制到宿主机路径:/data/volumn/es/config,目录结构如下:
├── config ==============》 es的配置目录
│ ├── data
│ ├── elasticsearch.keystore
│ ├── elasticsearch.yml
│ ├── jvm.options
│ ├── log4j2.properties
│ ├── logs
│ ├── node-0-keystore.jks
│ ├── scripts
│ └── truststore.jks
└── searchguard ==============》searchguard的配置目录
├── hyq_cluster2-keystore.jks
├── sg_action_groups.yml
├── sg_config.yml
├── sg_internal_users.yml
├── sg_roles_mapping.yml
├── sg_roles.yml
├── sg_tenants.yml
└── truststore.jks
- elasticsearch.yml中配置
#transport层
searchguard.ssl.transport.enabled: true
searchguard.ssl.transport.keystore_filepath: node-0-keystore.jks
searchguard.ssl.transport.keystore_password: 12345678
searchguard.ssl.transport.truststore_filepath: truststore.jks
searchguard.ssl.transport.truststore_password: 12345678
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.transport.resolve_hostname: false
#http层
searchguard.ssl.http.enabled: false
searchguard.ssl.http.keystore_filepath: node-0-keystore.jks
searchguard.ssl.http.keystore_password: 12345678
searchguard.ssl.http.truststore_filepath: truststore.jks
searchguard.ssl.http.truststore_password: 12345678
searchguard.authcz.admin_dn:
- CN=hyq_cluster2, OU=client, O=client, L=Test, C=DE
构建运行
- 构建镜像,运行容器
docker rm es_with_sg1
docker rmi es_with_sg:1.0
docker build -t es_with_sg:1.0 .
docker run -h es_with_sg1 -it \
--name es_with_sg1 \
--network=host \
-p 9200:9200 -p 9300:9300 \
-e client_node_cert_name=hyq_cluster2 \
-v /data/volumn/es/config:/data/es/elasticsearch-7.1.1/config \
es_with_sg:1.0
- 将配置写入运行中的es
docker exec -it es_with_sg1 /bin/bash
./plugins/search-guard-7/tools/sgadmin.sh -cn hyq_cluster -h 0.0.0.0 -cd plugins/search-guard-7/sgconfig -ks plugins/search-guard-7/sgconfig/hyq_cluster2-keystore.jks -kspass 12345678 -ts plugins/search-guard-7/sgconfig/truststore.jks -tspass 12345678 -nhnv
-
修改密码
- 使用plugins/search-guard-7/tools/hash.sh,生成密码。
- 如:hbash -p huangyq@123
-
修改内置用户密码(search-guard-7/sgconfig/sg_internal_users.yml)
客户端连接(不启用https)
-
The TransportClient is deprecated in favour of the Java High Level REST Client and will be removed in Elasticsearch 8.0. The migration guide describes all the steps needed to migrate
- 官方文档显示将在8.0以后的版本移除transport连接方式,所以我们连接es使用Rest的方式。
-
elasticsearch.yml中配置searchguard.ssl.http.enabled: false
-
使用logstash的generator生成测试数据,入es
input {
generator {
count => 100
message => '{"a":"1","b":"huangyunquan"}'
codec => json
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "hyq-%{+YYYY.MM.dd}"
user => "admin"
password => "huangyq@123"
}
}
bin/logstash -f config/test_es.conf
-
java客户端
- 没有开启https,只需要认证用户名密码即可。
- 开启https,需要添加信任证书。
public static void init_with_https_auth() throws Exception {
Path keyStorePath = Paths.get(Rest.class.getClass().getResource("/truststore.jks").toURI());
String keyStorePass = "12345678";
KeyStore truststore = KeyStore.getInstance("jks");
try (InputStream is = Files.newInputStream(keyStorePath)) {
truststore.load(is, keyStorePass.toCharArray());
}
SSLContextBuilder sslBuilder = SSLContexts.custom()
.loadTrustMaterial(truststore, null);
final SSLContext sslContext = sslBuilder.build();
HttpHost[] htps = new HttpHost[]{
new HttpHost(host,port,"https")};
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
restClient = RestClient.builder(htps)
.setHttpClientConfigCallback(httpClientBuilder ->{
httpClientBuilder.setSSLContext(sslContext);
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
return httpClientBuilder;
} ).build();
}
疑难解答
Q: java.nio.file.AccessDeniedException,unable to create temporary keystore at ..elasticsearch.keystore.tmp], please check filesystem permissions?
A: 由于在容器中创建了一个用户,同时又映射了数据卷,所以在config目录下需要给目录授权。容器内的用户和宿主机用户,是通过uid和gid来验证
Q: Keystore was tampered with, or password was incorrect?
A:使用example生成的密码一定要和elasticsearch.yml配置的一样,还有就是truststore_password、keystore_password配置项不能少,否则也会报这个错,笔者被这个问题坑惨了。
Q: ERR
Seems you use a client certificate but this one is not registered as admin_dn
Make sure elasticsearch.yml on all nodes contains:
searchguard.authcz.admin_dn?
A: gen_client_node_cert的第一个参数一定要和elasticsearch.yml中配置的searchguard.authcz.admin_dn配置项下的 CN相同。
Q: searchguard index does not exist yet,
so no need to load config on node startup. Use sgadmin to initialize cluster?
A: 容器运行起来后,使用sgadmin.sh 写入配置。
Q: the default discovery settings are unsuitable for production use;
at least one of [discovery.seed_hosts,
discovery.seed_providers, cluster.initial_master_nodes] must be configured?
A: 三个属性必须在elasticsearch.yml中配置一个。
Q:Host name 'xxx.ip' does not match the certificate subject provided by the peer (CN=node-0.example.com, OU=SSL, O=Test, L=Test, C=DE)?
A: 本地host配置 xxx.ip node-0.example.com。
Q: Search Guard not initialized (SG11). See https://docs.search-guard.com/latest/sgadmin?
A: 进入容器内部es根目录下,执行sgadmin脚本写入配置。