背景
近期,我们的开发系统在一次客户漏洞扫描中被检测出存在高危漏洞,其中一项便是Elasticsearch(ES)未配置用户名密码访问。尽管此前我们的ES集群主要作为基础设施在内网运行,并未直接对外暴露,但此次扫描结果明确指出了潜在的安全风险。为了消除这些隐患,并进一步提升系统的整体安全性,我们决定对ELK Stack进行全面的安全加固。
注意,本篇不会介绍elk相关的部署操作,而是基于已经部署好的elk服务,进行安全配置,关于elk的部署,可以参考官方文档或者其他博客,笔者也曾出过一篇相关的博客,地址:xie.infoq.cn/article/809...
ElasticSearch相关
配置证书
生成证书
使用es自带的cert工具生成证书
bash
# 创建ca
./bin/elasticsearch-certutil ca
执行此命令后,系统会提示您输入一个密码,请按需输入并牢记。如果忘记密码,将无法使用该CA证书。
如果按默认保存,您将获得一个p12格式的CA证书文件(elastic-stack-ca.p12)。您可以通过openssl查看其包含的信息:

可以通过openssl查看其包含的信息,此命令将显示p12证书文件的详细信息,包括证书链和私钥。请注意,输出内容可能较多。
arduino
openssl pkcs12 -info -nodes -in elastic-stack-ca.p12

您还可以查看CA证书的过期时间:
arduino
openssl pkcs12 -in elastic-stack-ca.p12 -nodes -nokeys -clcerts | openssl x509 -enddate -noout

接下来,利用已创建的CA证书生成ES服务所需的加密证书:
arduino
bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12
执行此命令后,同样会提示您输入密码。完成后,您将获得ES服务所需的证书文件(elastic-certificates.p12)。

同样的,可以使用刚才查看证书内容和过期时间的方法查看一下这个证书的信息,该文件就是我们下面需要放到es的配置文件里,进行传输层加密的证书。
提取CA证书
p12证书是一个类似加密文件的文件类型,不能直接再kibana,logstash等客户端使用,需要将其提取成crt文件
arduino
openssl pkcs12 -in config/certs/elastic-certificates.p12 -cacerts -nokeys -out config/certs/elastic-ca.crt
注意,关于证书的格式大家可以自行了解一下,p12格式在多数场景下是不能直接用的,需要解压转换成crt或者pem格式。
生成提取证书的操作只执行一次就行,然后将生成的证书复制到集群内的各个节点
授权
完成证书的生成和提取操作后,需要将证书文件复制到集群各个节点,然后进行授权操作,一般是对证书所在路径和文件进行授权就可以,基本就是下面这几个语句
注意,我这里的路径写的是相对路径,操作时要确保你在证书所在目录的主路径里,比如/usr/elasticsearch等。
bash
sudo chown -R elsearch:elsearch /config/certs/
chmod 600 /home/elastic/elasticsearch-7.14.1/config/certs/
sudo chown -R elsearch:elsearch /config
chmod 750 /config
同步证书
将准备好的证书文件同步到其他服务器,注意,要尽量确保每个节点的es服务存储路径规则一致,这主要是为了运维方便,如果不一致,配置证书的时候要小心一点,别弄错了。
ruby
# 注意生产环境如果有安全要求,可以使用更安全可靠的方式进行同步
scp -r ./config/certs 192.168.0.188:/opt/elastic/config/certs
scp -r ./config/certs 192.168.0.189:/opt/elastic/config/certs
至此,准备工作完成
修改配置
修改每个节点的配置文件,在elasticsearch.yml文件中添加以下安全配置:
makefile
# ------------------------ X-Pack Security Settings ------------------------
#
# 启用安全功能(必须)
# 启用传输层(节点间通信)SSL/TLS
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: config/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: config/elastic-certificates.p12
# (可选)启用 HTTP 层(客户端访问)SSL/TLS 加密
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.verification_mode: certificate
xpack.security.http.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.http.ssl.truststore.path: certs/elastic-certificates.p12
# (可选)如果没有使用keystore,这里需要显示声明p12证书的密码
xpack.security.transport.ssl.keystore.password: "{如果没有使用keystore,这里需要显示声明p12证书的密码}"
xpack.security.transport.ssl.truststore.password: "{如果没有使用keystore,这里需要显示声明p12证书的密码}"
xpack.security.http.ssl.keystore.password: "{如果没有使用keystore,这里需要显示声明p12证书的密码}"
xpack.security.http.ssl.truststore.password: "{如果没有使用keystore,这里需要显示声明p12证书的密码}"
重启服务
上述配置完成后,服务节点需要重启生效,重启后,如果原来没有开启安全认证服务,直接访问ip:9200是可以获取到数据的,开启之后,直接获取将提示未授权,同时可以检查节点日志,看有没有安全相关标识。
bash
tail -f ./logs/magicloud-cluster.log | grep -i security
类似这样的输出
css
[INFO ][o.e.x.s.Security ] [node-1] Security is enabled
[INFO ][o.e.x.s.t.SslTransportInterceptor] [node-1] SSL enabled for transport layer
[INFO ][o.e.x.s.h.SecurityHttpServerTransport] [node-1] SSL enabled for http layer
说明安全配置生效
设置用户密码
和生成证书时的命令类似,再es的运行目录下,运行
arduino
bin/elasticsearch-setup-passwords interactive
然后按照要求,输入各个内置用户的账号的密码
- elastic:超级用户(相当于root)
- kibana_system:Kibana服务账号
- logstash_system:Logstash服务账号
- beats_system:Beats服务账号
- apm_system:APM服务账号
- remote_monitoring_user:监控用户

或者直接使用自动模式
arduino
./bin/elasticsearch-setup-passwords auto
到这差不多es的配置就结束了,可以到浏览器看一下访问https://ip:port/_cat/nodes

或者可以通过一些浏览器插件来验证

也可以直接curl,这里使用curl验证的时候,如果我们es的配置开通了http的ssl配置,使用curl的时候要带上证书参数。
通过认证之后,就可以获取到结果了,和之前没开启安全认证之前的效果一样。
需要说明的时,这里虽然时https,但浏览器仍然给出了一个"不安全"的标识,这里的不安全是因为我们的证书是使用es的工具生成的,不像常见的ov,ev,dv权威证书,浏览器会给一个安全标识。
当然,平时我们和es的交互,大多数还是基于logstash这些同步工具将日志数据导入es,并不会用到浏览器。而其他的业务场景也是,都是服务端的操作,所以安全性不会降低。
Kibana配置
es的集群配置好并正常运行以后,可以按需调整kibana的配置,将前面提取的crt证书,放到kibana的config目录下(或者其他路径),然后修改配置文件,关键的修改点在于
makefile
# 原来设置的es节点要修改为https协议头
elasticsearch.hosts: ["https://xx.xx.xx.xx:9200"]
# 配置认证信息
elasticsearch.username: "kibana_system"
elasticsearch.password: "{实际生成的密码}"
# 配置证书
elasticsearch.ssl.certificateAuthorities: ["{证书路径}/elastic-certificates.crt"]
# 根据条件可以取消san条目认证
elasticsearch.ssl.verificationMode: none
配置完成后重启kibana,再次访问,就会出现认证窗口。

Logstash配置
logstash的配置,主要是写入es的参数要配置一下,增加证书路径即可。
ini
output {
elasticsearch {
# https协议
hosts => ["https://ip:9200"]
index=>"cloudlog-%{+YYYY.MM.dd}"
# 用户名
user => "{user}"
# 密码
password => "{password}"
# 开通ssl
ssl => true
# 证书路径,注意,如果是在windows节点运行logstash,这里斜杠要写/不是win里的\,和powershell的显示保持一致就好
cacert => "/certs/elastic-certificates.crt"
# 忽略主机名验证(按需)
ssl_certificate_verification => false
}
}
然后正常启动即可

可以看一下kibana里有没有最新同步的日志

至此,elk的安全加固任务,就基本完成了。
这里还要注意几点
- 我在使用es自带的cert工具生成证书时没有指定san条目,所以在后面kibana和logstash做配置的时候都增加了忽略san的参数,如果需要配置这些,那就需要重新生成证书,整个流程重来一遍,看实际场景。
- es生成的证书都是有有效期的,不改的话默认3年,所以要记得定期维护更新,另外,证书的生成除了使用es自带的工具,使用一些其他常见的证书生成工具或者Let's Encrypt生成的证书也是可以的,但操作性可能会麻烦一点,这个我没试。
*业务代码修改
除了elk的配置,我们的业务系统里,有的也会直接和es通信,进行一些大数据的读写操作,这时,如果之前没有配置安全参数,在修改es配置后,代码里也要做一些调整
以nest库在依赖注入场景的使用为例,大体的修改流程如下,
csharp
// 定义es配置类
public class EsConfig : IOptions<EsConfig>
{
public List<string> Urls { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string CertificatePath { get; set; }
public EsConfig Value => this;
}
// 注册
services.Configure<EsConfig>(options =>
{
// es集群地址,注意https
options.Urls = configuration.GetSection("EsConfig:ConnectionStrings").GetChildren().ToList().Select(p => p.Value).ToList();
//用户名密码,可以考虑放到系统环境变量里,避免配置文件泄露造成信息丢失,看实际情况吧
options.Username = configuration.GetSection("EsConfig:Username").Value;
options.Password = configuration.GetSection("EsConfig:Password").Value;
// 证书路径
options.CertificatePath = configuration.GetSection("EsConfig:CertificatePath").Value;
});
配置完成后,写个测试接口,获取下日志文件列表
scss
// 接口调用,测试
public async Task<IActionResult> TestEs([FromServices] INestHelper _nestHelper)
{
var records = _nestHelper.getClient().Cat.Indices().Records.Where(u => u.Index.Contains("cloudlog")).Take(50).Select(u => u.Index).ToArray();
return Json(resp.ret(records));
}

结语
至此,我们介绍了如何在ELK Stack中开启安全策略,特别是Elasticsearch的证书配置、Kibana和Logstash的安全集成。在当前数据安全日益重要的背景下,为ELK集群配置完善的安全措施已成为不可或缺的一环。
这不仅能够有效保护敏感数据,防止未经授权的访问,还能确保日志数据的完整性和可用性。虽然安全配置可能涉及一系列复杂的操作,但其带来的安全效益远超投入,起码客户不会扫不出漏洞,就不会找你麻烦O(∩_∩)O~
希望本文能为您的ELK安全实践提供有价值的参考,助您构建一个更加安全、可靠的日志管理平台。在实际部署中,请务必根据您的具体业务需求和安全合规要求,进行适当的调整和优化。
其他的,可以关注Elastic Stack的官方文档和最佳实践,不断演进和优化本地环境。