把 Elasticsearch 直接暴露在公网且没有开启任何鉴权,相当于把数据库的 root 密码写在门牌上。很多团队在搭建 ELK 栈时,为了方便调试,先关掉安全功能,结果上线后忘了开启,导致数据泄露的案例比比皆是。安全配置不是可选项,而是 Elasticsearch 集群上线前的最后一道必须完成的工序。
X-Pack 安全功能的正确开启方式从 Elasticsearch 6.8 和 7.1 版本开始,基础安全功能已经纳入免费授权范畴。你不再需要购买商业许可证就能使用传输层加密、用户认证和基于角色的访问控制。开启安全功能的第一步,是在 elasticsearch.yml 配置文件中添加一行关键配置:
xpack.security.enabled: true
仅仅加上这行还不够。如果你同时启用了传输层 SSL,还需要配置证书。单节点环境下,最简单的做法是让 Elasticsearch 自动生成自签名证书,在配置文件中加入:
xpack.security.transport.ssl.enabled: true xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.keystore.path: elastic-certificates.p12 xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
证书文件可以通过 elasticsearch-certutil 工具生成。执行 bin/elasticsearch-certutil cert -out config/elastic-certificates.p12 -pass "" 就能得到一个无密码保护的 PKCS12 证书文件。生产环境强烈建议使用正规 CA 签发的证书,并且设置强密码保护密钥库。
内置用户密码的设置与重置陷阱安全功能开启后,Elasticsearch 默认启用了一组内置用户,包括 elastic、kibana、logstash_system 等。这些用户的密码需要通过命令行工具手动设置。很多运维人员在这里犯过一个错误:只设置了 elastic 用户的密码,却忘了设置 kibana 和 logstash_system 用户的密码,导致 Kibana 无法连接 Elasticsearch,Logstash 管道也无法正常工作。
正确的做法是依次执行以下命令,为所有需要使用的内置用户设置密码:
bin/elasticsearch-setup-passwords interactive
这个交互式命令会依次提示你输入 elastic、kibana、logstash_system、beats_system、apm_system 和 remote_monitoring_user 的密码。如果你希望自动化部署,可以使用 auto 参数让系统自动生成随机密码:
bin/elasticsearch-setup-passwords auto
自动生成的密码会打印在控制台上,务必将它们安全地保存到密码管理器中。一旦丢失,只能通过重置密码流程恢复,这个过程需要先暂停集群的安全功能,操作风险较大。
基于角色的访问控制核心设计Elasticsearch 的权限模型建立在“用户-角色-权限”三层结构之上。角色定义了可以对哪些索引执行哪些操作,用户则被分配一个或多个角色。这套机制的精妙之处在于,你可以精确控制到单个索引、单个字段甚至单个文档的访问权限。
创建一个角色最直接的方式是使用 Kibana 的“堆栈管理”界面,但通过 API 创建更加灵活可控。以下是一个典型的只读角色定义:
POST /_security/role/logs_reader
{
"cluster": ["monitor"],
"indices": [
{
"names": ["logs-*"],
"privileges": ["read", "view_index_metadata"],
"allow_restricted_indices": false
}
]
}
这个角色拥有集群级别的监控权限,以及对所有以 logs- 开头的索引的读取和元数据查看权限。注意 privileges 数组中并没有 write 或 delete,这意味着持有该角色的用户无法修改或删除任何数据。集群权限和索引权限是分开定义的,这种设计让你能够实现最小权限原则。
索引级别的精细化权限控制索引权限的粒度远不止读写两种。Elasticsearch 提供了二十多种索引级权限,包括 create_index、delete_index、manage、manage_ilm 等。一个常见的需求是,让应用只能向特定索引写入数据,但不能修改已有文档。这可以通过组合 create 和 write 权限来实现,但需要注意,write 权限本身包含了更新和删除文档的能力。如果你只想允许新增文档,应该使用 create_doc 权限:
POST /_security/role/app_ingest_only
{
"indices": [
{
"names": ["app-logs-*"],
"privileges": ["create_doc"],
"field_security": {
"grant": ["timestamp", "message", "level", "service"]
}
}
]
}
这个角色还引入了字段级别的安全控制。field_security 中的 grant 列表指定了用户只能看到这四个字段,索引中的其他字段对用户完全透明。反过来,你也可以用 except 来排除敏感字段,比如排除包含个人身份信息的字段。
文档级别安全性的实际应用比字段级别更细的是文档级别安全控制。通过 Elasticsearch 的查询模板,你可以限制用户只能搜索到符合特定条件的文档。这在多租户场景下特别有用,比如每个部门只能看到自己的数据。实现方式是在角色定义中加入 query 字段:
POST /_security/role/department_engineering
{
"indices": [
{
"names": ["corporate-*"],
"privileges": ["read"],
"query": {
"template": {
"source": "{\"term\": {\"department.keyword\": \"engineering\"}}"
}
}
}
]
}
这个角色在每次查询时都会自动注入过滤条件,确保用户只能检索到 department 字段值为 engineering 的文档。即使用户在查询体中明确写入了 match_all,Elasticsearch 也会在底层叠加这个限制条件。需要注意的是,文档级别安全会影响搜索性能,因为每个查询都要附加额外的过滤逻辑。
API 密钥与服务账户管理对于程序化访问场景,直接使用用户密码并不是最佳实践。Elasticsearch 提供了 API 密钥机制,你可以为特定角色生成有时间限制的密钥,程序使用密钥而非密码进行认证。创建 API 密钥的请求如下:
POST /_security/api_key
{
"name": "my-application-key",
"role_descriptors": {
"app-role": {
"cluster": ["monitor"],
"indices": [
{
"names": ["app-data-*"],
"privileges": ["read", "write"]
}
]
}
},
"expiration": "30d"
}
返回结果中的 id 和 api_key 需要妥善保管,api_key 值只在创建时显示一次。程序在请求头中使用 Base64 编码的 "id:api_key" 作为 Authorization 头的值。API 密钥的优势在于可以随时吊销,不影响其他密钥和用户,而且可以设置过期时间,降低密钥泄露的风险。
传输层与 HTTP 层加密的双重保障安全配置不能只停留在认证层面,数据传输过程中的加密同样关键。Elasticsearch 的通信分为两层:节点间通信的传输层和客户端访问的 HTTP 层。传输层加密是必须开启的,它防止集群内部通信被窃听。HTTP 层加密则是保护客户端与集群之间的数据安全。
启用 HTTP 层 SSL 需要在 elasticsearch.yml 中添加:
xpack.security.http.ssl.enabled: true xpack.security.http.ssl.keystore.path: elastic-certificates.p12 xpack.security.http.ssl.truststore.path: elastic-certificates.p12
配置完成后,所有对 Elasticsearch 的访问都必须使用 HTTPS 协议。这意味着 Logstash、Filebeat、Kibana 等组件的连接配置也需要同步更新,将 http:// 改为 https://,并配置相应的证书或信任策略。
审计日志的开启与关键事件追踪安全配置的最后一道防线是审计日志。它记录谁在什么时间执行了什么操作,结果如何。在 elasticsearch.yml 中启用审计功能:
xpack.security.audit.enabled: true
默认情况下,审计日志输出到 Elasticsearch 的日志文件中。对于生产环境,建议将审计事件输出到独立的索引中,方便集中管理和分析。可以配置审计输出目标:
xpack.security.audit.outputs: [ index, logfile ]
审计日志会记录认证失败、权限拒绝、索引创建删除等关键事件。定期审查审计日志,能够及时发现异常的访问模式,比如某用户短时间内大量尝试访问无权限的索引,这往往是攻击的前兆。
常见安全配置误区与排查思路配置完安全功能后,连接失败是最常遇到的问题。排查时先确认 elasticsearch.yml 中 xpack.security.enabled 是否设置为 true,然后检查所有客户端是否已更新为使用认证信息。Kibana 连接失败的典型错误是“Authentication required”,这意味着 kibana.yml 中的 elasticsearch.username 和 elasticsearch.password 配置缺失或错误。
另一个容易被忽视的细节是,当启用 HTTPS 后,Kibana 默认仍尝试通过 HTTP 连接 Elasticsearch。需要在 kibana.yml 中明确指定 elasticsearch.hosts 使用 https:// 前缀,并配置 elasticsearch.ssl.verificationMode 为 certificate 或 full。如果使用的是自签名证书,还需要将 CA 证书导入到 Kibana 的信任库中。
索引权限配置中有一个常见的过度授权问题:使用 names 通配符时过于宽泛。比如将索引模式设置为 * 或 _all,这会让角色获得对所有索引的操作权限,违背了最小权限原则。建议始终使用具体的前缀模式,如 app-logs-*,并定期审查角色定义中的索引匹配范围。
最后提醒一点,Elasticsearch 的节点间通信密钥和 HTTP 层密钥可以共用同一个证书,但从安全最佳实践角度,建议分开管理。节点间通信使用内部 CA 签发的证书,HTTP 层使用公共 CA 签发的证书,这样外部客户端访问时不会遇到证书信任问题。
