Wazuh Indexer API - запросы и работа с данными
Wazuh Indexer построен на базе OpenSearch и предоставляет REST API для поиска, анализа и управления данными безопасности. Через API можно выполнять DSL-запросы к алертам, строить агрегации для аналитических отчетов, использовать PPL и SQL для интерактивного анализа, а также управлять шаблонами индексов и маппингами полей. Понимание работы с Indexer API необходимо для построения кастомных дашбордов, автоматизации и интеграции Wazuh с внешними системами.
Индексные паттерны Wazuh
Wazuh Indexer хранит данные в нескольких типах индексов, каждый из которых имеет свою функцию и период ротации.
Основные индексы
| Индекс | Назначение | Ротация |
|---|---|---|
wazuh-alerts-* | Алерты, сгенерированные при срабатывании правил | Ежедневно |
wazuh-archives-* | Все события, включая не вызвавшие алертов | Ежедневно |
wazuh-monitoring-* | Статусы подключения агентов | Еженедельно |
wazuh-statistics-* | Метрики производительности сервера Wazuh | Еженедельно |
Индексы состояния (State indices)
Начиная с Wazuh 4.14, данные инвентаризации и уязвимостей хранятся в отдельных индексах состояния:
| Индекс | Содержимое |
|---|---|
wazuh-states-vulnerabilities-* | Обнаруженные уязвимости и их критичность |
wazuh-states-inventory-packages-* | Установленное программное обеспечение |
wazuh-states-inventory-processes-* | Запущенные процессы |
wazuh-states-inventory-ports-* | Открытые сетевые порты |
wazuh-states-inventory-hardware-* | CPU, память, оборудование |
wazuh-states-inventory-system-* | ОС, архитектура, hostname |
wazuh-states-inventory-networks-* | Сетевые адреса IPv4/IPv6 |
Просмотр индексов
Список всех индексов Wazuh:
curl -sk -u admin:$PASSWORD \
"https://localhost:9200/_cat/indices/wazuh-*?v&s=index"Размер конкретного индекса:
curl -sk -u admin:$PASSWORD \
"https://localhost:9200/_cat/indices/wazuh-alerts-*?v&h=index,docs.count,store.size&s=index"Поиск алертов с помощью DSL-запросов
OpenSearch Query DSL (Domain Specific Language) - основной язык запросов для поиска данных в Wazuh Indexer.
Базовый поиск (match)
Поиск алертов по описанию правила:
GET wazuh-alerts-*/_search
{
"size": 10,
"query": {
"match": {
"rule.description": "authentication failure"
}
},
"sort": [
{ "timestamp": { "order": "desc" } }
]
}Точное совпадение (term)
Поиск алертов определенного уровня:
GET wazuh-alerts-*/_search
{
"query": {
"term": {
"rule.level": 12
}
}
}Составной запрос (bool)
Комбинирование условий с помощью must, should, must_not и filter:
GET wazuh-alerts-*/_search
{
"query": {
"bool": {
"must": [
{ "match": { "rule.groups": "authentication_failed" } }
],
"filter": [
{ "range": { "timestamp": { "gte": "now-24h" } } },
{ "term": { "agent.name": "web-server-01" } }
],
"must_not": [
{ "term": { "rule.level": 3 } }
]
}
},
"sort": [{ "timestamp": "desc" }],
"size": 50
}Диапазонный запрос (range)
Поиск алертов за определенный период:
GET wazuh-alerts-*/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"timestamp": {
"gte": "2025-01-01T00:00:00",
"lte": "2025-01-31T23:59:59",
"format": "yyyy-MM-dd'T'HH:mm:ss"
}
}
},
{
"range": {
"rule.level": { "gte": 10 }
}
}
]
}
}
}Поиск по вложенным полям
Wazuh хранит данные MITRE ATT&CK в структурированных полях:
GET wazuh-alerts-*/_search
{
"query": {
"bool": {
"must": [
{ "term": { "rule.mitre.id": "T1110" } },
{ "term": { "rule.mitre.tactic": "Credential Access" } }
]
}
},
"_source": ["timestamp", "rule.description", "rule.level", "agent.name"]
}Wildcard и regex
Поиск с использованием подстановочных символов:
GET wazuh-alerts-*/_search
{
"query": {
"wildcard": {
"data.srcip": "192.168.1.*"
}
}
}Поиск с регулярным выражением:
GET wazuh-alerts-*/_search
{
"query": {
"regexp": {
"data.url": ".*\\.(php|asp|jsp)\\?.*id=.*"
}
}
}Агрегации
Агрегации позволяют получать статистику и аналитические отчеты по данным Wazuh без необходимости выгружать все документы.
Terms - топ значений
Топ-10 правил, которые срабатывали чаще всего:
GET wazuh-alerts-*/_search
{
"size": 0,
"query": {
"range": { "timestamp": { "gte": "now-7d" } }
},
"aggs": {
"top_rules": {
"terms": {
"field": "rule.id",
"size": 10,
"order": { "_count": "desc" }
},
"aggs": {
"rule_description": {
"terms": { "field": "rule.description.keyword", "size": 1 }
}
}
}
}
}Date histogram - временная шкала
Количество алертов по часам за последние сутки:
GET wazuh-alerts-*/_search
{
"size": 0,
"query": {
"range": { "timestamp": { "gte": "now-24h" } }
},
"aggs": {
"alerts_over_time": {
"date_histogram": {
"field": "timestamp",
"fixed_interval": "1h"
},
"aggs": {
"by_level": {
"range": {
"field": "rule.level",
"ranges": [
{ "key": "low", "from": 0, "to": 7 },
{ "key": "medium", "from": 7, "to": 12 },
{ "key": "critical", "from": 12, "to": 16 }
]
}
}
}
}
}
}Cardinality - уникальные значения
Количество уникальных агентов, IP-адресов и правил:
GET wazuh-alerts-*/_search
{
"size": 0,
"query": {
"range": { "timestamp": { "gte": "now-24h" } }
},
"aggs": {
"unique_agents": {
"cardinality": { "field": "agent.id" }
},
"unique_source_ips": {
"cardinality": { "field": "data.srcip" }
},
"unique_rules": {
"cardinality": { "field": "rule.id" }
}
}
}Вложенные агрегации
Топ-5 агентов с разбивкой по тактикам MITRE ATT&CK:
GET wazuh-alerts-*/_search
{
"size": 0,
"aggs": {
"by_agent": {
"terms": { "field": "agent.name", "size": 5 },
"aggs": {
"by_tactic": {
"terms": { "field": "rule.mitre.tactic", "size": 5 }
},
"max_level": {
"max": { "field": "rule.level" }
}
}
}
}
}Шаблоны индексов и маппинги полей
Просмотр текущего шаблона
curl -sk -u admin:$PASSWORD \
"https://localhost:9200/_template/wazuh?pretty"Основные поля Wazuh-алертов
| Поле | Тип | Описание |
|---|---|---|
timestamp | date | Время события |
rule.id | keyword | Идентификатор правила |
rule.level | integer | Уровень критичности (0-15) |
rule.description | text/keyword | Описание правила |
rule.groups | keyword | Группы правила |
rule.mitre.id | keyword | MITRE ATT&CK technique ID |
rule.mitre.tactic | keyword | MITRE ATT&CK тактика |
agent.id | keyword | Идентификатор агента |
agent.name | keyword | Имя агента |
agent.ip | ip | IP-адрес агента |
data.srcip | ip | IP-адрес источника |
data.dstip | ip | IP-адрес назначения |
data.srcport | integer | Порт источника |
data.dstport | integer | Порт назначения |
location | keyword | Источник лога |
full_log | text | Полный текст лог-записи |
Обновление шаблона
Для добавления кастомного индексного паттерна:
# Скачать текущий шаблон
curl -so template.json \
"https://raw.githubusercontent.com/wazuh/wazuh/v4.14.4/extensions/elasticsearch/7.x/wazuh-template.json"
# Добавить кастомный паттерн в index_patterns
# Загрузить обновленный шаблон
curl -sk -u admin:$PASSWORD \
-XPUT "https://localhost:9200/_template/wazuh-custom" \
-H "Content-Type: application/json" \
-d @template.jsonКонфликты маппингов
Если поле имеет разные типы в разных индексах, возникает конфликт маппинга. Проверка:
curl -sk -u admin:$PASSWORD \
"https://localhost:9200/wazuh-alerts-*/_mapping?pretty" | \
jq '.. | .type? // empty' | sort | uniq -c | sort -rnDev Tools - консоль в Dashboard
Wazuh Dashboard включает консоль Dev Tools (унаследованную от OpenSearch Dashboards), которая позволяет выполнять API-запросы без использования curl.
Доступ к Dev Tools
- Откройте Wazuh Dashboard
- Перейдите в меню OpenSearch Dashboards - Dev Tools
- Или используйте URL:
https://<dashboard>:443/app/dev_tools#/console
Примеры использования
В консоли Dev Tools не нужно указывать URL и аутентификацию:
# Проверить состояние кластера
GET _cluster/health
# Поиск последних критических алертов
GET wazuh-alerts-*/_search
{
"size": 5,
"query": {
"bool": {
"filter": [
{ "range": { "rule.level": { "gte": 12 } } },
{ "range": { "timestamp": { "gte": "now-1h" } } }
]
}
},
"sort": [{ "timestamp": "desc" }]
}
# Статистика по агентам
GET wazuh-alerts-*/_search
{
"size": 0,
"aggs": {
"agents": {
"terms": { "field": "agent.name", "size": 20 }
}
}
}Автодополнение
Dev Tools поддерживает автодополнение имен индексов, полей и ключевых слов DSL. Используйте Ctrl+Space для вызова подсказок.
PPL - Piped Processing Language
PPL предоставляет синтаксис, аналогичный Unix-пайпам, для запросов к данным. Удобен для аналитиков, знакомых с Splunk SPL.
Базовый синтаксис
source = wazuh-alerts-* | where rule.level >= 10 | sort - timestamp | head 20Фильтрация и агрегация
source = wazuh-alerts-*
| where timestamp > '2025-01-01 00:00:00'
| where rule.level >= 7
| stats count() as alert_count by rule.id, rule.description
| sort - alert_count
| head 10Выполнение PPL через API
curl -sk -u admin:$PASSWORD \
-XPOST "https://localhost:9200/_plugins/_ppl" \
-H "Content-Type: application/json" \
-d '{
"query": "source = wazuh-alerts-* | where rule.level >= 12 | stats count() by agent.name | sort - count()"
}'Временные фильтры в PPL
source = wazuh-alerts-*
| where timestamp > DATE_SUB(NOW(), INTERVAL 24 HOUR)
| stats count() as alerts by span(timestamp, 1h) as hour
| sort hourГруппировка с несколькими метриками
source = wazuh-alerts-*
| where timestamp > DATE_SUB(NOW(), INTERVAL 7 DAY)
| stats count() as total, max(rule.level) as max_level, dc(agent.id) as agents
by rule.mitre.tactic
| sort - totalSQL Plugin
OpenSearch SQL plugin позволяет использовать привычный SQL-синтаксис для запросов к данным Wazuh.
Базовые запросы
SELECT timestamp, rule.id, rule.level, rule.description, agent.name
FROM wazuh-alerts-*
WHERE rule.level >= 10
AND timestamp > NOW() - INTERVAL 24 HOUR
ORDER BY timestamp DESC
LIMIT 50Агрегации в SQL
SELECT rule.id, rule.description, COUNT(*) as count
FROM wazuh-alerts-*
WHERE timestamp > NOW() - INTERVAL 7 DAY
GROUP BY rule.id, rule.description
ORDER BY count DESC
LIMIT 10Выполнение SQL через API
curl -sk -u admin:$PASSWORD \
-XPOST "https://localhost:9200/_plugins/_sql" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT agent.name, COUNT(*) as alerts FROM wazuh-alerts-* WHERE rule.level >= 7 GROUP BY agent.name ORDER BY alerts DESC"
}'Перевод SQL в DSL
Полезно для отладки - преобразование SQL в эквивалентный DSL-запрос:
curl -sk -u admin:$PASSWORD \
-XPOST "https://localhost:9200/_plugins/_sql/_explain" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT * FROM wazuh-alerts-* WHERE rule.level >= 12 LIMIT 10"
}'Bulk-операции
Массовые операции полезны для управления данными и автоматизации.
Bulk-поиск (msearch)
Выполнение нескольких запросов за один вызов:
curl -sk -u admin:$PASSWORD \
-XPOST "https://localhost:9200/_msearch" \
-H "Content-Type: application/x-ndjson" \
-d '
{"index":"wazuh-alerts-*"}
{"size":0,"query":{"range":{"rule.level":{"gte":12}}},"aggs":{"count":{"value_count":{"field":"_id"}}}}
{"index":"wazuh-alerts-*"}
{"size":0,"query":{"range":{"timestamp":{"gte":"now-1h"}}},"aggs":{"count":{"value_count":{"field":"_id"}}}}
'Scroll API для больших выборок
При необходимости получить более 10 000 документов используйте Scroll API:
# Инициализация scroll
curl -sk -u admin:$PASSWORD \
-XPOST "https://localhost:9200/wazuh-alerts-*/_search?scroll=5m" \
-H "Content-Type: application/json" \
-d '{
"size": 1000,
"query": { "range": { "timestamp": { "gte": "now-30d" } } },
"sort": [{ "timestamp": "asc" }]
}'
# Продолжение scroll (использовать _scroll_id из ответа)
curl -sk -u admin:$PASSWORD \
-XPOST "https://localhost:9200/_search/scroll" \
-H "Content-Type: application/json" \
-d '{
"scroll": "5m",
"scroll_id": "<SCROLL_ID>"
}'Удаление по запросу (delete by query)
Удаление старых алертов низкого уровня:
curl -sk -u admin:$PASSWORD \
-XPOST "https://localhost:9200/wazuh-alerts-*/_delete_by_query" \
-H "Content-Type: application/json" \
-d '{
"query": {
"bool": {
"filter": [
{ "range": { "timestamp": { "lte": "now-90d" } } },
{ "range": { "rule.level": { "lte": 3 } } }
]
}
}
}'Сравнение с другими SIEM-системами
Elasticsearch Query DSL
Wazuh Indexer (OpenSearch) использует синтаксис, полностью совместимый с Elasticsearch 7.x Query DSL. Основные отличия:
| Функция | Wazuh Indexer (OpenSearch) | Elasticsearch |
|---|---|---|
| Базовый DSL | Идентичный синтаксис | Идентичный синтаксис |
| SQL Plugin | _plugins/_sql | _sql (X-Pack) |
| PPL | _plugins/_ppl | Отсутствует |
| Alerting | _plugins/_alerting | X-Pack Watcher |
| Безопасность | Security Plugin (встроено) | X-Pack Security (платно) |
Миграция запросов из Elasticsearch в Wazuh Indexer не требует изменений в DSL-синтаксисе.
Splunk SPL
| Задача | Wazuh PPL | Splunk SPL |
|---|---|---|
| Поиск | source = index | where field = 'value' | index=main field=value |
| Агрегация | stats count() by field | stats count by field |
| Сортировка | sort - field | sort - field |
| Лимит | head N | head N |
| Временной фильтр | where timestamp > ... | earliest=-24h |
PPL в OpenSearch наиболее близок к SPL по синтаксису, что упрощает миграцию для аналитиков из Splunk.
QRadar AQL
| Задача | Wazuh SQL | QRadar AQL |
|---|---|---|
| Поиск событий | SELECT * FROM wazuh-alerts-* | SELECT * FROM events |
| Фильтрация | WHERE rule.level >= 10 | WHERE severity >= 7 |
| Агрегация | GROUP BY rule.id | GROUP BY qid |
| Временной фильтр | WHERE timestamp > NOW() - INTERVAL 1 HOUR | WHERE starttime > NOW - 1 HOURS |
SQL-синтаксис в OpenSearch близок к стандартному SQL, что упрощает адаптацию для пользователей QRadar.
Устранение неполадок
Медленные запросы
Симптом: запросы выполняются дольше 10 секунд.
Диагностика:
# Проверка нагрузки на кластер
curl -sk -u admin:$PASSWORD "https://localhost:9200/_nodes/stats/os,jvm?pretty"
# Проверка медленных запросов (включить slow log)
curl -sk -u admin:$PASSWORD \
-XPUT "https://localhost:9200/wazuh-alerts-*/_settings" \
-H "Content-Type: application/json" \
-d '{
"index.search.slowlog.threshold.query.warn": "5s",
"index.search.slowlog.threshold.query.info": "2s"
}'
# Просмотр slow log
curl -sk -u admin:$PASSWORD \
"https://localhost:9200/_cat/indices/.opendistro-slow-log-*?v"Решения:
- Используйте
filterвместоmustдля условий, не требующих релевантности - Ограничивайте временной диапазон запроса - не запрашивайте данные за все время
- Добавьте
"size": 0если нужны только агрегации - Избегайте
wildcardиregexpна полях без keyword-маппинга - Увеличьте JVM heap, если сборщик мусора работает слишком часто
Конфликты маппингов полей
Симптом: ошибка illegal_argument_exception при запросе.
# Проверка маппинга конкретного поля
curl -sk -u admin:$PASSWORD \
"https://localhost:9200/wazuh-alerts-*/_mapping/field/data.srcip?pretty"Решение: поле определено с разными типами в разных индексах. Необходимо обновить шаблон и переиндексировать данные или использовать keyword суффикс:
{ "term": { "rule.description.keyword": "Authentication failure" } }Индекс не найден (index_not_found_exception)
Симптом: ошибка no such index [wazuh-alerts-*].
Диагностика:
# Проверить существующие индексы
curl -sk -u admin:$PASSWORD "https://localhost:9200/_cat/indices/wazuh-*?v"
# Проверить алиасы
curl -sk -u admin:$PASSWORD "https://localhost:9200/_cat/aliases/wazuh-*?v"
# Проверить, что Filebeat отправляет данные
curl -sk -u admin:$PASSWORD \
"https://localhost:9200/_cat/indices/wazuh-alerts-*?v&s=index:desc&h=index,docs.count,store.size"Решения:
- Убедитесь, что Filebeat запущен и подключен к Indexer
- Проверьте конфигурацию Filebeat:
filebeat.ymlдолжен содержать корректныйoutput.elasticsearch.hosts - Проверьте шаблон индекса:
_template/wazuh - Для архивных данных убедитесь, что
logall_jsonвключен вossec.conf
Превышение лимита результатов
Симптом: ошибка Result window is too large при запросе с "from": 10000.
OpenSearch по умолчанию ограничивает from + size значением 10 000. Решения:
- Используйте Scroll API для полной выгрузки данных
- Используйте
search_afterдля пагинации - Для аналитики используйте агрегации вместо выгрузки документов
GET wazuh-alerts-*/_search
{
"size": 100,
"query": { "match_all": {} },
"sort": [{ "timestamp": "desc" }, { "_id": "asc" }],
"search_after": ["2025-01-15T10:30:00.000Z", "abc123"]
}Дополнительные материалы
- Установка Wazuh Indexer - развертывание и настройка
- Настройка Wazuh Dashboard - визуализация и анализ данных
- Архитектура Wazuh - обзор компонентов платформы
- Сбор логов - настройка источников данных