ELK专题:Day9——从0开始在Elastic Stack中完成TLS加密
1. 前言
在本专题介绍到的Elastic Stack的各个场景中,一直都没有涉及到通信安全的内容。一则是因为我们这一套环境是建立在内网,相对来说比较安全;二则是不想在初期就引入太多复杂的内容。然而,在实际的生产环境中,通信安全仍然是一个很重要的议题。
在当前的这个实验环境中,这个ELK集群一直都处于一个不设防的状态,不仅是没有做任何的数据加密,连最简单的账号密码认证都没有。今天我们就来尝试一下,从0开始,一步一步地完善整个集群的安全设置。
2. 概念解释
2.1 TLS/SSL简介
很多时候,TLS和SSL都会被放到一起讨论,甚至会被当作是同一个东西。而事实上,SSL是一个已经过时的协议,而继任者就是TLS,其中TLS最新的是2018年发布的1.3版本。作为一个安全协议,TLS对服务端和客户端之间在认证和加密时候所使用的流程和算法进行了规范,而最常用的场景便是我们几乎每日都会使用的HTTPS了。
2.2 工作原理
TLS协议会要求参与通信的各个终端围绕X.509证书进行必要的认证和数据加密,证书里面包含一个公钥和与之关联的私钥。
而TLS连接是建立在TCP和应用层之间,所以在TLS连接之前,需要先完成TCP三次握手。当客户端向服务端发起连接请求的时候,先使用非对称加密的方法约定出一个session key,再使用session key对数据进行加密对称,大致的验证步骤如下:
- client向server发送
client hello
请求,包含协议版本号,可选的加密方法以及client random
- server回复
server hello
,选择一个client支持的加密算法,并返回一个数字证书CA和server random
,同时要求client提供client的数字证书(双向验证) - client校验CA是否有效,并返回自己的CA到server
- server校验client的CA
- client根据
client random
和server random
生成一个新的premaster scret
,使用server证书里面的公钥加密后发送给server - server用自己的私钥解密,得到
premaster secret
- 后续client和server就使用
premaster secret
进行对称加密去交换数据,完成整个对话过程
需要说明的是,如果只是TLS单向认证,则可以跳过校验client CA的步骤。而TLS单向认证的一个典型应用,则是HTTPS。
2.3 私有CA
在x.509体系下,数字证书都是由CA(Certificate Authority)去签发,而CA又分为公共CA和私有CA。在我们这个试验环境下,都是基于内网IP进行通信的,我们只能选择使用私有CA去进行签发数字证书。因此,在为Kibana和ES等各个服务签发证书之前,我们需要先成立一个私有CA。
Luckily,在我们安装elasticsearch的时候,会附带安装一个证书管理工具elasticsearch-certutil
,我们可以直接创建一个CA证书。
如下图所示,我们使用工具生成了一个证书文件elastic-stack-ca.p12
,这个文件在后面的步骤里面都会用到。
3. 配置过程
3.1 环境说明
我们依然使用这一套ELK系统,其中ES和Kibana都是单点部署:
3.2 为elasticsearch配置登录验证
3.2.1 elasticsearch.yml
配置变更
停止ES和Kibana服务
在
elasticsearch.yml
配置文件中添加内容:xpack.security.enabled:true
因为在这个试验环境下,ES是单点部署,所以还需要在
elasticsearch.yml
添加discovery.type: single-node
,这样就可以防止ES意外地和同一个局域网内的ES节点组成集群。维持kibana服务的关闭状态,启动elasticsearch服务。在本案例中,
elasticsearch.yml
的内容如下:1
2
3
4
5
6
7
8
9cluster.name: rc-application
node.name: node-rc-1
path.data: /data/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 192.168.0.212
http.port: 9200
xpack.security.enabled: true
discovery.type: single-node
3.2.2 为ES的内置用户创建密码
在$ES_HOME
目录下,自带密码工具./bin/elasticsearch-setup-passwords
,可以对内置用户进行密码初始化。在本环境(elasticsearch 7.13)中,内置用户包括: elastic,apm_system,kibana,kibana_system,logstash_system,beats_system,remote_monitoring_user.
使用过
elasticsearch-setup-passwords
命令后,想要再修改用户密码,只能通过Change Password API或者在Kibana进行修改.
elasticsearch设置了用户密码验证后,使用
curl
命令请求elasticsearch API时需要添加参数--user user:password
,示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 root@ES:~# curl -XGET --user elastic:123456 'http://192.168.0.212:9200/'
{
"name" : "node-rc-1",
"cluster_name" : "rc-application",
"cluster_uuid" : "y_q0vv9vQ3K7ukSdl0fO7g",
"version" : {
"number" : "7.13.4",
"build_flavor" : "default",
"build_type" : "deb",
"build_hash" : "c5f60e894ca0c61cdbae4f5a686d9f08bcefc942",
"build_date" : "2021-07-14T18:33:36.673943207Z",
"build_snapshot" : false,
"lucene_version" : "8.8.2",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
3.2.3 在Kibana使用基础验证接入Elasticsearch
ES的安全选项开启后,kibana作为用户连接到ES的时候也需要携带验证信息,根据官方文档的指引,kibna使用kibana_system
用户读取ES中的信息。而在登录kibana页面的时候,则是使用elastic
用户,也即是ES的管理员账号.
我们在前面的步骤已经停止了kibana服务
在配置文件
kibana.yml
中添加内容:elasticsearch.username: "kibana_system"
使用自带工具
kibana-keystore
输入kibana_system
的密码.启动kibana服务,使用用户
elastic
以及对应的密码登录使用
kibana.yml
配置文件修改后如下:1
2
3
4
5
6
7
8server.port: 5601
server.host: "192.168.0.213"
server.name: "rc-application-test-kibana"
elasticsearch.hosts: "http://192.168.0.212:9200"
logging.dest: /var/log/kibana/kibana.log
logging.verbose: false
elasticsearch.username: "kibana_system"
TIPS:
如果觉得配置keystore麻烦,也可以直接在
kibana.yml
使用明文配置elasticsearch.password
,但你都来这里学习配置TLS了,还会明文配置密码吗? ;-)
3.3 为elasticsearch集群配置TLS证书
需要提前说明的是,如果是ES是以集群的方式运行,则需要在每个节点都进行一次证书的创建和配置修改。在本实验环境中,因为ES只有一个节点,所以只需要进行一次。
3.3.1 创建ES的证书
在$ES_HOME
路径下,执行命令./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12
,在获得ES的证书elastic-certificates.p12
.
3.3.2 向elasticsearch.yml
添加ssl证书信息
在elasticsearch.yml
中添加xpack.security
配置项,完整配置项如下:
1 | cluster.name: rc-application |
注意:
如果在生成证书
elastic-certificates.p12
的时候有使用密码,则需要使用key-store保存密码,执行下面的两条命令后,会把证书的密码保存在/etc/elasticsearch/elasticsearch.keystore
1
2 ./bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
./bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password
重启elasticsearch,并确认服务状态。
3.4 在Elasticsearch和Kibana中使用HTTPS
3.4.1 为elasticsearch服务签发https证书
停止集群中的ES和Kibana服务
再一次使用certutil工具,生成一个https证书。在这个过程中,我们需要引用在步骤2.3中创建的证书文件
elastic-stack-ca.p12
,操作步骤如下:
使用过程中会弹出很多疑问,在本环境中,大致选择如下:
是否创建CSR→n
是否使用已存在的CA→Y
输入CA的绝对路径,在这里使用的是
/etc/elasticsearch/elastic-stack-ca.p12
输入CA的密码
设置证书有效时间,这里使用默认的5年
是否对每个节点创建证书→n,因为我只有一个ES节点
输入节点的hostname
输入节点的ip地址
校验信息准确性
选择http证书的存放路径
最后会生成一个压缩包
elasticsearch-ssl-http.zip
,包含如下文件:1
2
3
4
5
6
7
8
9
10
11
12
13Archive: ./elasticsearch-ssl-http.zip
Length Date Time Name
--------- ---------- ----- ----
0 2021-10-20 16:58 elasticsearch/
1365 2021-10-20 16:58 elasticsearch/README.txt
3588 2021-10-20 16:58 elasticsearch/http.p12
850 2021-10-20 16:58 elasticsearch/sample-elasticsearch.yml
0 2021-10-20 16:58 kibana/
1306 2021-10-20 16:58 kibana/README.txt
1200 2021-10-20 16:58 kibana/elasticsearch-ca.pem
1057 2021-10-20 16:58 kibana/sample-kibana.yml
--------- -------
9366 8 files把压缩包中的
elasticsearch/http.p12
移动到/etc/elasticsearch
向
elasticsearch.yml
添加如下内容:1
2xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: /etc/elasticsearch/http.p12(可选步骤)如果http证书有设置密码,则把密码添加到keystore中
1
/usr/share/elasticsearch/bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password
重启elasticsearch
3.4.2 加密Kibana和Elasticsearch之间的HTTP通信
把文件
elasticsearch-ca.pem
复制到Kibana节点中的$KBN_PATH_CONF
,在本实验环境中,即/etc/kibana
修改
kibana.yml
,增加或修改如下内容:1
2elasticsearch.hosts: "https://192.168.0.212:9200"
elasticsearch.ssl.certificateAuthorities: /etc/kibana/elasticsearch-ca.pem重启Kibana服务
3.4.3 加密Kibana和浏览器之间的HTTP通信
在上一个步骤的场景中,Kibana作为客户端向ES请求数据,而在这个步骤,Kibana转变为服务器的角色。
准备kibana的服务器证书
运行
elasticsearch-certutil
,创建Kibana服务的证书和私钥,默认会生成一个压缩包csr-bundle.zip
1
./bin/elasticsearch-certutil csr -name kibana-server -dns 192.168.0.213
解压缩压缩包
csr-bundle.zip
,得到kibana-server.csr
和kibana-server.key
1
2
3
4
5root@ES:/tmp# unzip csr-bundle.zip
Archive: csr-bundle.zip
creating: kibana-server/
inflating: kibana-server/kibana-server.csr
inflating: kibana-server/kibana-server.key使用之前创建的CA根证书
elastic-stack-ca.p12
对kibana-server.csr
进行签发,得到kibana-server.crt
提取CA根证书里面的私钥和证书信息
1
2
3
4
5# 提取私钥,保存为elastic-stack-ca.key
openssl pkcs12 -in ./elastic-stack-ca.p12 -out elastic-stack-ca.key -nodes -nocerts
# 提取证书,保存为elastic-stack-ca.crt
openssl pkcs12 -in ./elastic-stack-ca.p12 -out elastic-stack-ca.crt -nokeys使用CA根证书对kibana的证书进行签发,用专业术语来说,即是’Send the kibana-server.csr certificate signing request to internal CA’。
从原理来解释,就是使用机构的私钥对Kibana服务的公钥进行加密,得到Kibana的证书。当用户需要获得Kibana服务的公钥的时候,就用机构公钥对Kibana的证书进行解密。
1
openssl x509 -req -sha256 -CA elastic-stack-ca.crt -CAkey elastic-stack-ca.key -CAcreateserial -in kibana-server.csr -out kibana-server.crt
把
kibana-server.crt
和kibana-server.key
存放到$KBN_PATH_CONF
中修改
kibana.yml
,增加内容1
2
3server.ssl.enabled: true
server.ssl.certificate: /etc/kibana/kibana-server.crt
server.ssl.key: /etc/kibana/kibana-server.key重启kibana服务
现在可以使用HTTPS协议访问Kibana页面了,因为这是使用自己创建的CA签发的证书,所以浏览器会提示不安全。
3.5 完善Metricbeat的安全配置
留坑
3.6 加密Logstash和Elasticsearch之间的流量
3.6.1 在ES创建角色logstash_write_role
使用Kibana Roles UI创建
或使用Kibana Dev Tools创建
↓ 点击展开完整POST内容 ↓
POST /_security/role/logstash_write_role { "cluster": [ "monitor", "manage_index_templates" ], "indices": [ { "names": [ "logstash*" ], "privileges": [ "write", "create_index" ], "field_security": { "grant": [ "*" ] } } ], "run_as": [], "metadata": {}, "transient_metadata": { "enabled": true } }
3.6.2 在ES创建用户logstash_write
使用Kibana Roles UI创建
或使用Kibana Dev Tools创建
↓ 点击展开完整POST内容 ↓
POST /_security/user/logstash_writer { "username": "logstash_writer", "roles": [ "logstash_write_role" ], "full_name": null, "email": null, "password": "123456", "enabled": true }
3.6.3 准备用于连接ES的证书
在这个步骤,使用crt格式的CA的根证书,我们在步骤3.4.3里面已经把p12格式的证书转成crt格式了,我们可以照搬使用,把证书文件elastic-stack-ca.crt
放到/etc/kibana
目录下。
注意要允许运行logstash服务的用户读取证书文件。
3.6.4 修改pipeline配置文件
配置示例如下:
1 | input { ... } |
以上步骤完成后,就可以重启Logstash服务验收啦。
如果过程中出现任何问题,可以参考Day2的思路,结合logstash的运行日志,调试配置文件。
3.7 Kibana和Elasticsearch之间的双向TLS认证
过于先进,不便展示。
4. 心得
在完成了整个Elastic Stack集群的性能监控之后,我就开始研究在Kibana上配置告警消息的推送。但是发现告警推送功能的部分API需要依赖TLS协议,遂花了不少时间去补课。在直接下手配置之前,还专门拾起了在大学里没学好的信息安全课程,更是写了两篇小作文,以为已经做好了准备,但是在下手配置的过程还是走了很多弯路。甚至,因为难度过高不得不留坑(2021/10/21) 。
从实用的角度出发,一个运行在内网的Elastic Stack集群不进行数据加密,我能想到的最大的隐患就是,当内网的其中一台机器被入侵后,黑客可以通过端口嗅探找到ES。对一个不设防的ES,可以轻易完成拖库操作。但这种隐患也只是在内网被入侵之后才会发生,而且前提是数据具备一定的价值才会被盯上。
但我本来创建的这套实验环境本来就不是从实用的角度出发,不是吗?(笑)
不过是想要通过不断的折腾去固化知识罢了。
5. 参考文档
Set up minimal security for Elasticsearch
Set up basic security for the Elastic Stack
Set up basic security for the Elastic Stack plus secured HTTPS traffic
配置 SSL、TLS 以及 HTTPS 来确保 Elasticsearch、Kibana、Beats 和 Logstash 的安全