(Darmowe) Alerty w Elasticsearch

Elasticsearch najczęściej wykorzystywany jest do agregowania logów i monitorowania elementów systemu. Umożliwia również alertowanie, ale jest to funkcjonalność dostępna od wersji Gold, czyli trzeba za nią zapłacić ?. Są jednak darmowe rozwiązania. W tym przypadku przyjrzymy się rozwiązaniu Praeco (z łac. obwoływacz, herold) opartym o ElastAlert.

Praeco

ElastAlert jest to rozwiązanie do powiadamiania o anomaliach, skokach lub innych wzorcach w Elasticsearch. Samo w sobie nie posiada GUI.

Praeco jest to nakładka graficzna na ElastAlert, wykorzystująca jego API. Pozwala w prosty sposób wyklikać reguły i kierunki (Slack, Email, Http, Telegram, JIRA), na które ma być wysłane powiadomienie.

Środowisko

Tym razem będę opierał się na “stacjonarnym” zabezpieczonym klastrze Elasticsearch w wersji 7.6, ale jeśli potrzebujesz szybko postawić ES na komputerze, skorzystaj z Dockera.

W przypadku Praeco użyjemy ichniego repozytorium z docker-compose.yml. Do sprawdzenia, czy alertowanie faktycznie działa użyjemy Logstasha i powiadomień HTTP.

git clone https://github.com/ServerCentral/praeco.git

Konfiguracja

Praeco & ElastAlert

W sklonowanym repo mamy docker-compose.yml i configi. Oto zmiany które wprowadziłem.

version: '3'

services:
  elastalert:
    image: 'servercentral/elastalert'

    ports:
      - '3030:3030'
      - '3333:3333'

    volumes:
      - ./config/elastalert.yaml:/opt/elastalert/config.yaml
      - ./config/api.config.json:/opt/elastalert-server/config/config.json
      - ./rules:/opt/elastalert/rules
      - ./rule_templates:/opt/elastalert/rule_templates
      - /jakas/sciezka/ca.pem:/ca.pem

    extra_hosts:
      - 'hadoop01:10.7.35.110'
#      - 'elasticsearch:${PRAECO_ELASTICSEARCH}'

  webapp:
    image: 'servercentral/praeco'

    ports:
      - '5602:8080'

    volumes:
      - ./public/praeco.config.json:/var/www/html/praeco.config.json
      - ./nginx_config/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx_config/default.conf:/etc/nginx/conf.d/default.conf

docker-compose.yml – kolejno:
– 16- CA, by elastalert ufał że mój ES jest moim ES
– 19 – mój cooridination node znajduje się na pod adresem hadoop01 i odpowiednim IP.
– 26 – Port 8080 zajęty był przez Ambari, więc użyłem 5602.

{
  "appName": "elastalert-server",
  "port": 3030,
  "wsport": 3333,
  "elastalertPath": "/opt/elastalert",
  "verbose": false,
  "es_debug": false,
  "debug": false,
  "rulesPath": {
    "relative": true,
    "path": "/rules"
  },
  "templatesPath": {
    "relative": true,
    "path": "/rule_templates"
  },
  "es_host": "hadoop01",
  "es_port": 9200,
  "es_username": "elastic",
  "es_password": "Asdf1!",
  "es_ssl": true,
  "writeback_index": "praeco_elastalert_status"
}

config/api.config.json – 17-21 – namiary na ES

es_host: hadoop01

es_port: 9200

rules_folder: rules

run_every:
  seconds: 60

buffer_time:
  minutes: 1

use_ssl: True
ca_certs: "/ca.pem"

es_username: elastic
es_password: Asdf1!

writeback_index: praeco_elastalert_status
alert_time_limit:
  days: 2

skip_invalid: True

config/elastalert.json – kolejno:
– 1 – namiary na ES
– 14-17 – wskazanie zaufanego CA, użytkownik i hasło (na produkcji utworzyłbym osobne konto z odpowiednimi uprawnieniami)

Logstash

Pipeline do wrzucania logów z HTTP do Elasticsearch

input {
  http {
    host => "hadoop01"
    port => 7070
  }
}

output {
  stdout{}

  elasticsearch {
      hosts => ["hadoop01"]
      index => "logstash-test-%{+YYYY.MM.dd}"
      ssl => true    
      user => logstash_internal
      password => "Asdf1!"
      cacert => "/jakas/sciezka/ca.pem"
  }
}

Pipeline do odebrania notyfikacji HTTP z Praeco/ElastAlert

input {
  http {
    host => "hadoop01"
    port => 7077
  }
}

output {
  stdout{}
}

Aby odpalić dwa pipeline jednocześnie, trzeba utworzyć plik YAML który je wskaże. Jeśli nazwiesz go pipelines.yml, wystarczy wskazać folder.

    - pipeline.id: ingest-http
      path.config: "config/pipelines/pipeline.conf"
    - pipeline.id: output-http
      path.config: "config/pipelines/pipeline2.conf"
bin/logstash --path.settings sciezka/do/folderu/

Reguła w Praeco

Celem jest sprawdzenie ” czy to działa”, więc reguła będzie prosta. Jeśli w ciągu ostatnich 5 minut będzie więcej niż 40 dokumentów, strzelaj z HTTP.

Możemy wykrywać skoki/spadki

Akcja

Strzelając POST-em pod hadoop01:7070 na konsoli widzimy log

{                                                                     
      "@version" => "1",                                              
       "message" => "Wiaderko :-)",                                   
          "host" => "10.100.64.21",                                   
    "@timestamp" => 2020-03-08T19:04:29.389Z,                         
       "headers" => {                                                 
             "connection" => "keep-alive",                            
           "content_type" => "application/json",                      
           "http_version" => "HTTP/1.1",                              
           "request_path" => "/",                                     
          "postman_token" => "3416b074-ecf9-4de2-a441-5b7a38bada46",  
            "http_accept" => "*/*",                                   
        "accept_encoding" => "gzip, deflate, br",                     
         "request_method" => "POST",                                  
          "cache_control" => "no-cache",                              
              "http_host" => "hadoop01:7070",                         
         "content_length" => "29",                                    
        "http_user_agent" => "PostmanRuntime/7.22.0"                  
    }                                                                 
}                                                                     

Reakcja

po N-tym strzale widać na konsoli

{
        "message" => "Wiaderko :-)",
           "host" => "172.18.0.2",
        "headers" => {
        "http_user_agent" => "python-requests/2.22.0",
            "http_accept" => "application/json;charset=utf-8",
        "accept_encoding" => "gzip, deflate",
             "connection" => "keep-alive",
         "request_method" => "POST",
              "http_host" => "hadoop01:7077",
           "content_type" => "application/json",
           "http_version" => "HTTP/1.1",
         "content_length" => "628",
           "request_path" => "/"
    },
     "@timestamp" => 2020-03-08T19:06:57.251Z,
            "_id" => "5oyLu3ABCzENcYtTDZXS",
       "@version" => "1",
    "num_matches" => 1,
       "num_hits" => 72,
         "_index" => "logstash-test-2020.03.08",
          "_type" => "_doc"
}

Po http_user_agent, widać że dostaliśmy POST od ElastAlert (napisany jest w pythonie). num_hits pokrwa nam się z tym co widać w GUI. Niestety w body nie ma nazwy reguły.

Podsumowanie

Obraz może zawierać: mem i tekst

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *