Wednesday, February 19, 2020

ELK: установка и запуск Elastalert оффлайн

Как мне показалось, что данное занятие совсем не тривиальное, решил создать небольшую заметку, как установить и запустить Elastalert. Сам делал по мануалу. Ну и плюс мои заметки.
Установка под RedHat 7.7
Итак, сохраняем все файлы с машины, где есть доступ к интернетам:
yum install --downloadonly --downloaddir=/elasta epel-release python36 python36-setuptools
 python36-devel python36-pip gcc
Затем устанавливаем все
yum install -y ...
Качаем последнюю версию elastalert'a и находим там файлик с зависимостями.
Далее сохраняем установочные файлы с помощью pip'a:
pip3 download -r /pathto/elastalert/requirements.txt
Устанавливаем по мануалу, или вкратце так:
Переносим все это добро в /tmp/elasta
Разорхивируем Elastalert в /opt/elastalert
Редактируем setup.py
Коментируем:
#'aws-requests-auth>=0.3.0',
 #'boto3>=1.4.4',
#'jira>=1.0.10,<1.0.15'
#'stomp.py>=4.1.17',
 #'twilio>=6.0.0,<6.1'
Изменяем версию jsonschema, чтобы подходила под требования.
'jsonschema>=2.6.0,<3.3.0'
Запускаем установку через Pip
python3 -m pip install . --find-links file:/tmp/elasta --no-index
Готово - установка завершена!
Создаем файл конфига:
cp config.yaml.example config.yaml
Редактируем настройки: время выполнения, хост-порт, авторизация и т.д.

После установки хочу запустить Elastalert(а именно сделать индекс под него elastalert-create-index), а получаю ошибку:
ModuleNotFoundError:
Все банальное просто - нужно добавить в env новый путь: /usr/local/bin
Ну или куда вы указали установить Elastalert.
export PATH="$PATH:/usr/local/bin/"
source ~/.bashrc
Также после запуска была такая ошибка:
File "/usr/local/lib/python3.6/site-packages/elastalert/auth.py", line 3, in <module>
    import boto3
ModuleNotFoundError: No module named 'boto3'

Т.к. в мануале я выключал установку boto3 то необходимо поправить скрипты запуска, закоментить вызовы бото и другого ПО, которое вы не установили.
vi /usr/local/lib/python3.6/site-packages/elastalert/auth.py

Создаем индекс для алертов:
elastalert-create-index --config /elastalert/config.yaml
 
Протестировать правило:
elastalert-test-rule --config config.yaml example_rules/example_frequency.yaml
Само правило => проверяем работоспособность апача, если ошибок более 500, отправляем уведомление:
# Rule name, must be unique
name: Example frequency rule

# Type of alert.
# the frequency rule type alerts when num_events events occur with timeframe time
type: frequency

# (Required)
# Index to search, wildcard supported
index: 87*

# (Required, frequency specific)
# Alert when this many documents matching the query occur within a timeframe
num_events: 500

# (Required, frequency specific)
# num_events must occur within this amount of time to trigger an alert
timeframe:
  hours: 4

# A list of Elasticsearch filters used for find events
# These filters are joined with AND and nested in a filtered query
# For more info: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html
filter:
- term:
    service.type: "apache"

# The alert is use when a match is found
alert:
- "email"

# a list of email addresses to send alerts to
email:
- "email@hst.ru"

smtp_host: "10.1.2.5"

Создаем службу для запуска Elastalert
vi /lib/systemd/system/elastalert.service
[Unit]
Description=elastalert
After=multi-user.target

[Service]
Type=simple
WorkingDirectory=/elastalert
ExecStart=/usr/local/bin/elastalert --verbose --rule example_rules/example_frequency.yaml

[Install]
WantedBy=multi-user.target


systemctl daemon-reload

В случае ошибки(или статуса работы) - мониторить:
tail  /var/log/messages | grep elasta

Успехов!

Tuesday, February 18, 2020

Kibana 7.5: ошибка отображения данных

Всем привет.
Столкнулся с проблемой построения данных в кибане при отображении дашборда за 7 дней и более. При том, что возникает не во всех дашбордах.
Ошибка звучит так:
Error in visualization
[esaggs] > Request to Elasticsearch failed: {"error":{}}         


Предположение: очевидное, но тем не менее - esaggs – это агрегации. Значит какие-то агрегации строятся и вызывают данную ошибку. При уменьшение интервала наблюдения до 5 дней, такой проблемы нет. Кроме того, график, который в рамках дашборда не отображается индивидуально открывается без проблем.

Начинаю анализировать на предмет "может есть какие-то логи в кибане, которые можно проанализировать на счет данной ошибки"?

Открываю логи эластика в режиме tail -f, логи Kibana:
tail /var/log/messages -f | grep kibana

Открываю дашборд на 10 дней. Запускаю обновление, смотрю сообщения о том, что происходит.Ошибок как таковых нет, все сообщения с ответом 200, все гут. Но не тут то было:
"res":{"statusCode":200,"responseTime":29929,"contentLength":9},"message":"POST /elasticsearch/apache*/_search?rest_total_hits_as_int=true&ignore_unavailable=true&ignore_throttled=true&preference=1581061538688&timeout=30000ms 200 29929ms - 9.0B"}
Есть такая тема как лимит ожидания, вот он то и виноват в этих сообщения. Есть визуализации, с двойными разрезами(split series) и фильтрами(filters), вот она и тормозит.
Нахожу в настройках эластика таймаут, увеличиваю:

# Time in milliseconds to wait for responses from the back end or Elasticsearch. This value
# must be a positive integer.
elasticsearch.requestTimeout: 40000

Сначала до 40 секунд, затем до 50. Зато теперь всплывают сообщения, что данные могут быть не полные, т.к. превышен лимит. Странно, что дефолтное значение мне про это не сказало.

В случае использования nginx'a, как прокси добавьте данные параметры:
proxy_connect_timeout       300;
proxy_send_timeout          300;
proxy_read_timeout          90m;
send_timeout                300;
 
client_max_body_size        1000m;


Успехов!

Monday, February 3, 2020

Logstash: конфигурируем сбор логов

В данной статье рассмотрим варианты конфигураций логстеша(опции filter{}).
Для начала сделаем авто рестарт конфигурации, чтобы постоянно не перезапускать службу логстеша. Добавляем к параметрам запуска параметр config.reload.automatic
ExecStart=/usr/share/logstash/bin/logstash  ...  "--config.reload.automatic"
Далее => systemctl daemon-reload и перезапуск самого логстеша.

filter{ ...}
#пример форматирования даты-времени
 if "json" in [tags] { #находим в тегах json и применяем данный паттерн
    date {
      match => ["[json][@timestamp]", "yyyy-MM-dd HH:mm:ss"]
      timezone => "Europe/Moscow" #применяем временные настройки
      target => "[json][@timestamp]"
    }
  }

#пример поиска текста по полю [json][message], который не равен тексту ERROR
if [json][message] !~ "ERROR"{
        mutate {
            remove_field => ["input"]} #удаляем поле из вывода
           rename => { "FName" => "Firstname"} #переименование
   gsub => [ "EmailId", "\.", "_" ] #замена . в поле EmailId на _
           strip => ["Firstname", "Lastname"]
           uppercase => [ "Gender" ]

}
mutate позволяет выполнять различные изменения данных в полях. Вы можете переименовать, конвертировать, извлекать и модифицировать поля в событиях.
Параметр gsub используется для сопоставления регулярного выражения и значения поля, а также для замены всех соответствий замещающей строкой.
Параметр strip используется для извлечения пробелов.
Параметр uppercase предназначен для преобразования строки в верхний регистр.

Фильтр Grok

Это мощный и популярный плагин для преобразования неструктурированных данных в структурированные, для упрощения запросов и фильтрации этих данных. В общих чертах Grok позволяет сопоставить строку и шаблон (который основан на регулярном выражении) и отобразить определенные части строки на свои поля. Общий синтаксис шаблона Grok выглядит следующим образом:
%{PATTERN:FIELDNAME}
PATTERN — имя шаблона, который соответствует тексту. FIELDNAME — идентификатор для соответствующего фрагмента текста.

#пример для Apache, двойной грок, т.к. не всегда апач заполняет все поля. В этом случае вывод не формируется. В примере указано, что если поле msg заполнено, то его нужно отфильтровать.
if "apache_access" in [tags] {
    grok {
                match => { "message" => "%{IPORHOST:[remote_ip]} %{IPORHOST:[next_ip]} %{IPORHOST:[remote_ip1]} - \[%{HTTPDATE:[timestamp]}\] \"%{WORD:[method]} %{DATA:[url]} HTTP/%{NUMBER:[http_version]}\" %{NUMBER:response_code:int} %{NUMBER:bytes:int} \"-\"\s*%{GREEDYDATA:msg}"}
                remove_field => "message"
    }
    grok {
                match => [ "msg", "\s*\*\*%{NUMBER:referrer:int}/%{NUMBER:referrer2:int}\*\*\s*%{GREEDYDATA:user}" ]
    }
    mutate {
        remove_field => ["input", "ecs", "@version", "agent", "next_ip", "http_version", "remote_ip1"]
    }
  }

Вот так выглядит строка из лога, которую нужно пройти двойным гроком.
Jan 31, 2020 @ 11:09:58.304     -     111.222.233.119 10.218.188.117 123.222.2.119 - [31/Jan/2020:11:09:58 +0300] "POST /url/somemethod HTTP/1.1" 200 457 "-" **0/54046** user_some

С помощбю Kibana вы можете отфильтровать свой лог. Указываете формат, в котором поступают данные и далее с помощью фильтров настраиваете формат лога.

Успехов!