Contents

一次 Elasticsearch 被清库的复盘

  这件事发生得很突然,也很典型。

  我有一套 Elasticsearch,用来存设备日志和监控数据,部署很简单:Docker 单节点,数据目录挂到宿主机。本来只是测试环境,就没太在意安全,9200 端口直接对外开放,也没有开认证。

  运行一直很正常,直到某天发现数据不对劲。


现象

  最开始不是“全没了”,而是更隐蔽的变化:

  • 有些索引的数据明显变少
  • 有些索引直接查不到
  • ES 服务还在正常运行,甚至还在持续写入

  这种状态很容易让人误判成查询问题。于是先做了最基础的确认:

curl http://localhost:9200/_cat/indices?v

  可以看到索引还在,但文档数量明显不对,而且有些索引像是刚创建的,数据量很小。

  这时候可以确定:

不是查询条件问题


第一反应:是不是持久化丢了

  Docker 跑 ES,最常见的坑就是没做持久化。先看配置:

- /usr/local/data/elasticsearch/data:/usr/share/elasticsearch/data

  确认数据目录已经挂载到宿主机。

  然后直接去宿主机看数据文件:

find /usr/local/data/elasticsearch/data/nodes/0/indices | head

  能看到类似这些文件:

_index/_0.cfs
segments_3
translog-*.tlog
state-*.st

  这里简单解释一下这些文件是什么:

  • Lucene segment 文件(.cfs / segments_*) ES 底层用 Lucene 存数据,这些文件就是“真正的数据”
  • translog(事务日志) 用来保证数据写入不丢失,类似数据库的 redo log
  • state 文件 记录索引和分片的元信息

  这些文件都在,说明一件事:

数据目录是正常的,不是容器重建导致的数据丢失


怀疑 ILM(生命周期管理)

  因为配置过 ILM,于是查了一下策略:

curl http://127.0.0.1:9200/_ilm/policy?pretty

  关键策略大致是:

  • device_log_policy:3650 天后删除
  • system_log_policy:180 天后删除

  而当前索引是:

device_log_xxx_2026-4

  也就是当月数据。

  很明显,这些索引不可能满足删除条件。

  于是可以排除:

不是 ILM 自动删除


真正的突破:日志

  接下来去看 ES 日志,直接搜关键字:

grep "deleting index" elasticsearch.log

  很快看到大量记录:

MetadataDeleteIndexService ... deleting index

  而且删的全是业务索引,比如:

  • access_logger_2026-4
  • device_log_xxx_2026-4
  • system_logger_2026-4

  更关键的是时间:

  • 下午删一批
  • 晚上再删
  • 第二天继续

  这个节奏已经很明显:

索引是被“主动删除”的


更诡异的一点:删完又出现

  继续看日志,还能看到另一类记录:

creating index, cause [auto(bulk api)]

  这说明:

  • 索引被删后
  • 应用还在往这个索引写数据
  • ES 自动重新创建索引

  整个过程是:

删除索引 → 应用写入 → 自动创建 → 再被删除

  这也是为什么一开始看到的是“数据变少”,而不是直接全没。


最终确认:read_me 勒索信息

  在索引列表里发现一个异常索引:

curl http://localhost:9200/_cat/indices?v

  里面多了一个:

read_me

  打开之后是一段勒索内容,大致意思是:

数据已经被删除,想恢复需要支付 BTC

  到这里,原因就完全明确了:

Elasticsearch 被扫端口后执行了清库攻击

*** 这里需要注意一下,你的数据已经确认被删除了,接受这个事实,不要打钱,对方不可能还你数据。勒索内容里面的链接也不要点! ***


发生了什么

  这类攻击流程非常简单,而且是自动化的:

  1. 扫描全网 9200 端口

  2. 判断是否无认证

  3. 执行删除:

    DELETE /*
    
  4. 写入勒索信息

  5. 等待用户上钩

  重点是:

对方并没有真的备份你的数据

只是删除后“骗你打钱”。


为什么会中招

  回头看环境,其实问题很直接:

  • 9200 端口对公网开放
  • 没有认证
  • 没有 IP 限制

  换句话说:

等于把数据库的读写删除权限直接暴露在公网

  而这些扫描都是机器人在跑,并不是针对某个人。


处理方式

  处理其实很简单,先把入口关掉。

  第一步是通过安全组限制访问,只允许自己的 IP:

只允许指定 IP 访问 9200

  第二步是开启认证:

xpack.security.enabled: true

  至少做到:

不是谁都能连进来执行 DELETE


后续打算

  这次之后,会把这一层补完整:

  • ES 不再直接暴露公网,前面加网关
  • 做 IP 白名单
  • 增加快照备份
  • 保留访问日志

  这些平时看起来“用不到”,但一旦出事就是刚需。


总结

  这件事本身不复杂,但很有代表性。

  它不是配置写错,也不是组件问题,而是一个很基础的安全问题:

基础设施暴露在公网且没有认证

  可以简单总结一句话:

Elasticsearch 只要裸露在公网,就迟早会被清库。

  踩过一次,这个问题基本就不会再忽视了。