Fork me on GitHub
Fork me on GitHub

Elasticsearch安全问题

背景

Elasticsearch设计之初就定位在纯私网环境而不做权限和安全控制,虽然有个叫Security Manager的配置,但是显然是不够的。但是后来专门出了个收费的shield来保护Elasticsearch,可是毕竟是收费的。当然我们也有替代品:search-guard。下面介绍下 Elasticsearch 围绕安全方面的的几点使用事项:

修改默认的 Elasticsearch 集群名称

Elasticsearch 默认的集群名称是 elasticsearch,请在生成环境上一定要修改成其他的名称,并且不同的环境和不同的集群要保证不相同,监控集群节点情况,如果有未知节点加入,一定要及时预警。

不要暴露 Elasticsearch 在公网上

Elasticsearch默认的http.port是9200,集群各节点间的通信端口transport.tcp.port是9300。建议修改这两个端口。

所以强烈建议替换掉Elasticsearch的监控端口,就像是给你家金库做了个“暗门”,骇客想要进入金库至少先得找到门路才行。

不要以 root 身份运行 Elasticsearch

一定不要以 root 身份来运行 Elasticsearch,另外,要不和其他的服务公用相同的用户,然后还要保证该用户的权限要最小化。

定期对 Elasticsearch 进行备份

使用 Elasticsearch 提供的备份还原机制,定期对 Elasticsearch 的数据进行快照备份,以备不时之需。官网的备份介绍:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html

安装Elasticsearch的权限系统插件-SearchGuard

search-guard是elastcisearch的一款插件,提供加密,身份验证和授权,基于search guard SSL,另外提供可插入的身份验证/授权模块,search-guard是shield的替代品,可免费提供所有的基本安全功能,其功能特性:

安装插件

注意:插件版本需要和你使用的Elasticsearch版本对应。

$ bin/plugin install -b com.floragunn/search-guard-2/2.3.3.10

$ bin/plugin install -b com.floragunn/search-guard-ssl/2.3.3.19

注意:以上两步在集群每个节点都要执行。

证书

根据自身情况修改官方脚本生成admin证书、node证书、根证书,将 node 证书和根证书放在 elasticsearch 配置文件目录下,同时将admin证书和根证书放到search-guard 配置文件目录下。
1.集群中任意一台机器下载 searchguard-ssl 的包,里面包含自动创建证书的脚本:

[es@log1 elasticsearch]$ wget https://github.com/floragunncom/search-guard-ssl/archive/v2.3.3.19.zip  
[es@log1 elasticsearch]$ unzip -oq v2.3.3.19.zip
[es@log1 elasticsearch]$ cd search-guard-ssl-2.3.3.19/example-pki-scripts/

有三个脚本:

  • gen_client_node_cert.sh 创建客户端证书
  • gen_node_cert.sh 创建节点证书
  • gen_root_ca.sh 创建根证书

2.生成证书

#生成文件:
./example.sh
#管理员的证书:
./gen_client_node_cert.sh admin changeit capass

命令会生成一个admin-keystore.jks的文件,把truststore.jks、admin-keystore.jks拷贝到${ES_HOME}/plugins/search-guard-2/sgconfig目录下

给plugins/search-guard-2/tools/sgadmin.sh执行权限:

$ chmod +x plugins/search-guard-2/tools/sgadmin.sh

将example-pki-scripts下生成的truststore.jks文件复制到ES集群中各个节点的config目录下,且把生成的node--keystore.jks文件复制到各个节点的config目录下。*注意: The keystore files are specific per node. Copy node-0-keystore.jks to the config directory of your first ES node, node-1-keystore.jks to the second and so forth.

[es@log1 example-pki-scripts]$ cp truststore.jks node-0-keystore.jks /usr/local/elasticsearch/config/
[es@log1 example-pki-scripts]$ scp -p truststore.jks node-1-keystore.jks es@log2:/usr/local/elasticsearch/config/
[es@log1 example-pki-scripts]$ scp -p truststore.jks node-2-keystore.jks es@log3:/usr/local/elasticsearch/config/

3.在Elasticsearch中添加search-guard和search-guard-ssl的配置项
找到config/elasticsearch.yml文件,添加以下配置项:

##########################################################
# SEARCH GUARD SSL                                                                             
# Configuration
##########################################################
################## Transport layer SSL ###################                        
####节点下放的是node-*,这里就写哪个
searchguard.ssl.transport.enabled: true
searchguard.ssl.transport.keystore_filepath: node-0-keystore.jks
searchguard.ssl.transport.keystore_password: changeit
searchguard.ssl.transport.truststore_filepath: truststore.jks
searchguard.ssl.transport.truststore_password: changeit
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.transport.resolve_hostname: false
searchguard.ssl.transport.enabled_protocols:
 - "TLSv1"
 - "TLSv1.1"
 - "TLSv1.2"

################# HTTP/REST layer SSL ####################
searchguard.ssl.http.enabled: true
searchguard.ssl.http.keystore_filepath: node-0-keystore.jks
searchguard.ssl.http.truststore_filepath: truststore.jks
searchguard.ssl.http.truststore_password: changeit
searchguard.ssl.http.enabled_protocols:
 - "TLSv1"
 - "TLSv1.1"
 - "TLSv1.2"

##### 管理员账号配置
searchguard.authcz.admin_dn:
  - "CN=admin, OU=client, O=client, L=Test, C=DE"

注意:配置文件的node-x-keystore.jks对应每台config目录下放置的文件。

4.重启集群中的各台Elasticsearch然后初始化search-guard的配置项

$ bin/elasticsearch -d

3台集群中的节点都要重启。重启后,elasticsearch 之间的连接已经是加密的了。

在log1上初始化searchguard索引:

$ cd /usr/local/elasticsearch
$ plugins/search-guard-2/tools/sgadmin.sh -cd plugins/search-guard-2/sgconfig -ts plugins/search-guard-2/sgconfig/truststore.jks -ks  plugins/search-guard-2/sgconfig/admin-keystore.jks -kspass changeit -tspass changeit  -icl -nhnv -h 114.55.253.15 
Will connect to 114.55.253.15:9300 ... done
Contacting elasticsearch cluster 'elasticsearch' and wait for YELLOW clusterstate ...
Clustername: wisedu
Clusterstate: GREEN
Number of nodes: 3
Number of data nodes: 3
searchguard index does not exists, attempt to create it ... done (with 2 replicas, auto expand replicas is off)
Populate config from /usr/local/elasticsearch/plugins/search-guard-2/sgconfig
Will update 'config' with plugins/search-guard-2/sgconfig/sg_config.yml
   SUCC: Configuration for 'config' created or updated
Will update 'roles' with plugins/search-guard-2/sgconfig/sg_roles.yml
   SUCC: Configuration for 'roles' created or updated
Will update 'rolesmapping' with plugins/search-guard-2/sgconfig/sg_roles_mapping.yml
   SUCC: Configuration for 'rolesmapping' created or updated
Will update 'internalusers' with plugins/search-guard-2/sgconfig/sg_internal_users.yml
   SUCC: Configuration for 'internalusers' created or updated
Will update 'actiongroups' with plugins/search-guard-2/sgconfig/sg_action_groups.yml
   SUCC: Configuration for 'actiongroups' created or updated
Done with success 

这里的-icl是忽略集群的名称,不加会报错。
注意1:如果修改了searchguard,则需要重新加载配置执行。
注意2:search-guard配置的相关改动不需要重启elasticsearch,相关的配置实际上存储在searchguard 的indice下了。

其中 sg_internal_users.yml 保存着默认的用户和密码:

[es@log1 elasticsearch]$ cd plugins/search-guard-2/sgconfig/
[es@log1 sgconfig]$ head -n 5  sg_internal_users.yml
# This is the internal user database
# The hash value is a bcrypt hash and can be generated with plugin/tools/hash.sh
admin:
  hash: $2a$12$VcCDgh2NDk07JGN0rjGbM.Ad41qVR/YFJcgHp0UGns5JDymv..TOG
  #password is: admin

浏览器输入https://114.55.253.15:9200/,输入用户名和密码admin/admin

HTTP和Java Api方式访问ElasticSearch

HTTP方式访问Elasticsearch

1.在浏览器上访问Elasticsearch,会直接出弹窗,输入用户名密码即可。
2.在服务器上使用curl的话需要加上参数-u adminName,类似如下:

curl -u adminName:adminname -XGET "http://114.55.253.15:9200/blog/article/1?pretty"

Java API中使用search-guard

1.加入jar包
进到/usr/local/elasticsearch/plugins/search-guard-ssl目录下拷贝以下jar包加到CLASSPATH中。

search-guard-ssl-2.3.4.14.jar
netty-buffer-4.0.37.Final.jar
netty-codec-4.0.37.Final.jar
netty-common-4.0.37.Final.jar
netty-handler-4.0.37.Final.jar
netty-transport-4.0.37.Final.jar

2.修改setting
以下部分需要从ES节点的这个目录下复制出来放到工程中,并且修改为你实际的路径。
目录:/usr/local/elasticsearch/plugins/search-guard-2/sgconfig中。

import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import com.floragunn.searchguard.ssl.SearchGuardSSLPlugin;

Settings settings = Settings.settingsBuilder()
        .put("path.home", ".")
        .put("cluster.name", "wisedu")
        .put("searchguard.ssl.transport.enabled", true)
        .put("searchguard.ssl.transport.keystore_filepath", "I:/Work/WorkSpace/ultrasearch/plugins/search-guard-2/sgconfig/admin-keystore.jks")
        .put("searchguard.ssl.transport.truststore_filepath", "I:/Work/WorkSpace/ultrasearch/plugins/search-guard-2/sgconfig/truststore.jks")
        .put("searchguard.ssl.transport.enforce_hostname_verification", false)              
        .build();

3.修改client
以下为你想要连接的ES节点的ip和port,请修改为你实际的。

TransportClient client = TransportClient.builder().settings(settings).addPlugin(SearchGuardSSLPlugin.class).build();
TransportClient addTransportAddress = client.addTransportAddress(new InetSocketTransportAddress(new InetSocketAddress("114.55.253.15", 9300)));
//do something with tc
NodesInfoRequest nodesInfoRequest= new NodesInfoRequest();
nodesInfoRequest.putHeader("sg.impersonate.as", "worf");
client.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet();
client.admin().cluster().nodesInfo(nodesInfoRequest).actionGet();

search-guard中的用户权限管理介绍

searchguard 主要有5个配置文件在/ultra/ES/elasticsearch-2.3.4/plugins/search-guard-2/sgconfig 下:
1.sg_config.yml:主配置文件不需要做改动。

2.sg_internal_users.yml:本地用户文件,定义用户密码以及对应的权限。例如:对于 ELK 我们需要一个 kibana 登录用户和一个 logstash 用户,如下所示:

kibana4:
  hash: $2a$12$xZOcnwYPYQ3zIadnlQIJ0eNhX1ngwMkTN.oMwkKxoGvDVPn4/6XtO
  #password is: kirk
  roles:
    - kibana4
logstash:
  hash: $2a$12$xZOcnwYPYQ3zIadnlQIJ0eNhX1ngwMkTN.oMwkKxoGvDVPn4/6XtO
  roles:
    - logstash

注意:用户的密码可用plugins/search-guard-2/tools/hash.sh生成。比如修改admin用户的默认密码为wisedu123:

[es@log1 tools]$ ./hash.sh -p wisedu123
$2a$12$AmrZnl1wYGLGNODLDMY5/O86wmYE9eBcXtVa6AQjfzsF1gcKhkXqe

3.sg_roles.yml:权限配置文件,以下为kibana4 和 logstash 的权限样例:

#<sg_role_name>:
#  cluster:
#    - '<permission>'
#  indices:
#    '<indexname or alias>':
#      '<type>':  
#        - '<permission>'
#      _dls_: '<querydsl query>'
#      _fls_:
#        - '<field>'
#        - '<field>'
sg_kibana4:
  cluster:
      - cluster:monitor/nodes/info
      - cluster:monitor/health
  indices:
    '*':
      '*':
        - indices:admin/mappings/fields/get
        - indices:admin/validate/query
        - indices:data/read/search
        - indices:data/read/msearch
        - indices:admin/get
        - indices:data/read/field_stats
    '?kibana':
      '*':
        - indices:admin/exists
        - indices:admin/mapping/put
        - indices:admin/mappings/fields/get
        - indices:admin/refresh
        - indices:admin/validate/query
        - indices:data/read/get
sg_logstash:
  cluster:
    - indices:admin/template/get
    - indices:admin/template/put
  indices:
    'logstash-*':
      '*':
        - WRITE
        - indices:data/write/bulk
        - indices:data/write/delete
        - indices:data/write/update
        - indices:data/read/search
        - indices:data/read/scroll
        - CREATE_INDEX

4.sg_roles_mapping.yml:定义用户的映射关系,添加 kibana 及 logstash 用户对应的映射如下:

sg_logstash:
  users:
    - logstash
sg_kibana4:
  backendroles:
    - kibana
  users:
    - kibana4

5.sg_action_groups.yml:定义权限。

补充一点:Search Guard可以实现和Logstash、Kibana的完美结合,对于使用ELK的用户大可不必担心,修改集成很容易的。
并且,Elasticsearch在5.x之后,对Search Guard、Search Guard SSL (当然还有Logstash 、Kibana)等插件的版本号都做了统一,变得更加的简单直观了。

利用操作系统防火墙设置规避9200端口开放问题

对于search-guard插件配置繁琐,也可以使用操作系统防火墙对访问源IP进行隔离控制。
架设Nginx反向代理服务器,ES主机防火墙设置仅允许Nginx所在主机访问ES主机的9200端口。

安装防火墙

在centos7上停止firewalld,启用iptables。
停止firewalld:

# systemctl stop firewalld.service   #停止firewall
# systemctl disable firewalld.service    #禁止firewall开机启动

安装iptables防火墙:

# yum install -y iptables-services

配置防火墙

# vim /etc/sysconfig/iptables     #修改默认的配置文件
*filter
:INPUT ACCEPT [1837:149118]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1656:224717]
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -s 114.55.248.157/32 -p tcp -m tcp --dport 9200 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 9200 -j DROP
COMMIT


其实也就是加了两条规则:

iptables -A INPUT -s 114.55.248.157 -p TCP --dport 9200 -j ACCEPT
iptables -A INPUT -p TCP --dport 9200 -j DROP

启动防火墙和设置开机启动:

# systemctl start iptables.service      
# systemctl enable iptables.service    

配置Nginx

Nginx主要配置:

upstream elasticsearch_servers {
        server 114.55.253.15:9200;
        server 114.55.132.143:9200;
        server 114.55.252.185:9200;
}

server {
        listen  8080;
        access_log logs/es_access.log main;

        location = /* {
            deny all;
        }

        location / {
            proxy_pass http://elasticsearch_servers;
        }

}