EQL简介和数据准备
EQL(Event Query Language) 是 Elasticsearch 专为事件型时序数据 (日志、指标、追踪数据)设计的查询语言,主打安全威胁狩猎场景,也可用于通用事件分析。
因为在使用eql进行查询时,数据最好支持Elastic Common Schema (ECS)风格,所以使用官网的数据为大家进行演示,数据的导入方式参照官网:Example: Detect threats with EQL | Elasticsearch Guide [8.17] | Elastic
或者是大家在查看eql的文章时,可以看到他的实例数据的位置

EQL的基本使用
最基本的使用:
//规定了事件类型的查询
//es推荐中,eql的查询数据最好是符合ECS规范,event.category是规范中的字段,他就是事件类型
GET eql_test/_eql/search
{
"query":"""
process where process.pid == 2012
"""
}
//最基本的查询
GET eql_test/_eql/search
{
"query":"""
any where process.pid == 2012
"""
}
针对下面的例子,为大家带来和es的DSL的同义查询语句:
GET eql_test/_eql/search
{
"query":"""
process where process.pid == 2012
"""
}
#结合上面的解释,DSL语句可以写为
GET eql_test/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"event.category": "process"
}
},
{
"term": {
"process.pid": {
"value": "2012"
}
}
}
]
}
}
}
使用any 进行查询时相当于的DSL是:
//最基本的查询
GET eql_test/_eql/search
{
"query":"""
any where process.pid == 2012
"""
}
GET eql_test/_search
{
"query":{
"bool": {
"must": [
{
"term": {
"process.pid": {
"value": "2012"
}
}
}
]
}
}
}
自定义事件(查询条件字段):
在上面的内容中我们可以发现,在ecs的规范下,直接使用event.category作为事件的类型进行查询,但是在实际开发中我们可能在处理历史数据或者是在数据的字段设置上没有使用ecs的规则,这里我们可以使用参数event_category_field进行指定哪个字段作为检索的条件,来取代字段event.category..
具体的使用方式如下:
通过配置修改了事件的类型,使用事件type作为查询的条件
GET eql_test/_eql/search
{
"event_category_field":"event.type",
"query": """
creation where user.full_name == "bob"
"""
}
使用属性timestamp_field指定时间字段:
GET eql_test/_eql/search
{
"event_category_field":"event.type",
"timestamp_field":"@timestamp",
"query": """
creation where user.full_name == "bob"
"""
}
使用size指定返回数据数量:
GET eql_test/_eql/search
{
"event_category_field":"event.type",
"timestamp_field":"@timestamp",
"size":100,
"query": """
creation where user.full_name == "bob"
"""
}
filter_path指定返回的字段:
GET eql_test/_eql/search?filter_path=hits.total
{
"event_category_field":"event.type",
"timestamp_field":"@timestamp",
"size":100,
"query": """
creation where user.full_name == "bob"
"""
}
fields进行字段控制:
GET eql_test/_eql/search
{
"event_category_field": "event.type",
"timestamp_field": "@timestamp",
"size": 100,
"query": """
creation where user.full_name == "bob"
""",
"fields": [
"system.*",
{
"field": "@timestamp",
"format": "epoch_millis"
}
]
}
eql的高级使用:
runtime_mappin gs结合eql:
runtime_mappings是 ES 7.11+ 提供的查询时动态字段 能力:不修改索引 Mapping、不重索引,就在本次搜索里临时算出新字段,用于过滤 / 聚合 / 排序 / 返回。
注意点:使用脚本是需要使用emit()执行,不使用fields指明字段,这个字段可以用于计算和查询,但是不可以显示出来
GET eql_test/_eql/search
{
"runtime_mappings": {
"logon_id_@timestamp": {
"type": "keyword",
"script": {
"source": """
if (doc['logon_id'].size() == 0) {
return;
}
emit(doc['logon_id'].value + '_' + doc['@timestamp'].value.toString());
"""
}
}
},
"event_category_field": "event.type",
"query": """
creation where user.full_name == "bob"
""",
"fields": ["logon_id_@timestamp"]
}
Sequence序列查询
sequence = 按时间先后顺序发生的一连串事件。它不是查 "有没有这些事件",而是查:
事件 A 先发生 → 然后 事件 B 发生 → 然后 事件 C 发生必须严格按时间顺序!
GET eql_test/_eql/search
{
"wait_for_completion_timeout":"10ms",
"query":"""
sequence with maxspan = 1h
[ process where user.full_name == "bob"]
[ any where user.full_name == "bob"]
"""
}
eql进行异步查询:
GET eql_test/_eql/search
{
"wait_for_completion_timeout":"10ms",
"query":"""
sequence with maxspan = 1h
[ process where user.full_name == "bob"]
[ any where user.full_name == "bob"]
"""
}
GET _eql/search/FkhjLVVPdmQyUkZPbWkwZHdoYVoxb2cdbmZWM1YwaEJSUVNSenVIeUxyazBGUTo2MDg0NjA
pipe管道:
在写eql语句的时候我们可以通过管道获取头或者是尾巴的数据
获取尾部数据的前两条
GET eql_test/_eql/search
{
"query":"""
any where event.category=="process" | tail 2
"""
}
获取头部数据的前两条
GET eql_test/_eql/search
{
"query":"""
any where event.category=="process" | head 2
"""
}