Встановлення та налаштування Elastic Stack на Ubuntu

Комплекс Elastic Stack (колишня назва – комплекс ELK) є набір програмного забезпечення Elastic з відкритим вихідним кодом, що забезпечує можливості пошуку, аналізу та візуалізації журналів, згенерованих будь-яким джерелом у будь-якому форматі (централізоване ведення журналу). Централізоване ведення журналу дуже корисне для виявлення проблем із серверами або програмами, оскільки забезпечує можливості пошуку всіх журнальних записів в одному місці. Також ця можливість дозволяє виявляти проблеми, які поширюються кілька серверів, у вигляді зіставлення їх журналів за певний період.

Комплекс Elastic Stack має чотири основні компоненти:

  • Elasticsearch: розподілена пошукова система RESTful, яка зберігає всі зібрані дані.
  • Logstash: елемент обробки даних комплексу Elastic, що відправляє вхідні дані до Elasticsearch.
  • Kibana: веб-інтерфейс для пошуку та візуалізації журналів.
  • Beats: компактні елементи перенесення даних одиночного призначення, які можуть надсилати дані із сотень або тисяч комп’ютерів у Logstash або Elasticsearch.

Встановлення та налаштування Elasticsearch

Спочатку запустіть наступну команду для імпорту відкритого ключа Elasticsearch GPG в APT:

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -

Потім додайте список джерел Elastic до каталогу sources.list.d, де APT шукатиме нові джерела:

echo "deb https://artifacts.elastic.co/packages/6.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-6.x.list

Потім оновіть списки пакетів, щоб APT могло прочитати нове джерело Elastic:

sudo apt update

Встановіть Elasticsearch за допомогою наступної команди:

sudo apt install elasticsearch

Після завершення інсталяції Elasticsearch використовуйте текстовий редактор для редагування головного файлу конфігурації Elasticsearch з ім’ям elasticsearch.yml. Ми будемо використовувати nano:

sudo nano /etc/elasticsearch/elasticsearch.yml

Elasticsearch прослуховує весь трафік порту 9200. Ви можете захотіти обмежити зовнішній доступ до вашого екземпляра Elasticsearch, щоб сторонні не могли читати ваші дані або відключати ваш кластер Elasticsearch через REST API. Знайдіть рядок із зазначенням network.host, приберіть з нього значок коментаря та замініть значення на localhost, щоб він виглядав так:

/etc/elasticsearch/elasticsearch.yml

network.host: localhost

Збережіть та закрийте файл elasticsearch.yml, натиснувши CTRL+X, а потім Y та ENTER, якщо ви використовуєте nano. Потім запустіть службу Elasticsearch за допомогою systemctl:

sudo systemctl start elasticsearch

Потім запустіть наступну команду, щоб активувати Elasticsearch при кожному завантаженні сервера:

sudo systemctl enable elasticsearch

Ви можете протестувати роботу служби Elasticsearch, надіславши запит HTTP:

curl -X GET "localhost:9200"

Ви отримаєте відповідь, яка містить базову інформацію про локальний сайт:

Output
{
"name" : "ubuntu-vm",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "edirIS6tRACwasu9nG2kdw",
  "version" : {
    "number" : "8.5.2",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "a846182fa16b4ebfcc89aa3c11a11fd5adf3de04",
    "build_date" : "2023-11-17T18:56:17.538630285Z",
    "build_snapshot" : false,
    "lucene_version" : "9.4.1",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

Ми налаштували та запустили Elasticsearch і тепер можемо перейти до встановлення Kibana, наступного компонента комплексу Elastic.

Встановлення та налаштування інформаційної панелі Kibana

Оскільки ви вже додали джерело пакетів Elastic на попередньому кроці, ви можете просто встановити решту компонентів комплексу Elastic за допомогою apt:

sudo apt install kibana

Потім активуйте та запустіть службу Kibana:

sudo systemctl enable kibana
sudo systemctl start kibana

Оскільки згідно параметрів Kibana прослуховує тільки localhost, ми повинні задати зворотний проксі, щоб дозволити зовнішній доступ. Для цього ми використовуємо Nginx, який має бути вже встановлений на вашому сервері.

Спочатку потрібно використовувати команду openssl для створення адміністративного користувача Kibana, якого ви використовуватимете для доступу до веб-інтерфейсу Kibana. Для прикладу ми назвемо цей обліковий запис kibanaadmin, проте для більшої безпеки рекомендуємо вибрати нестандартне ім’я користувача, яке буде складно вгадати.

Наступна команда створить адміністративного користувача Kibana та пароль та збереже їх у файлі htpasswd.users. Ви налаштуєте Nginx для використання цього імені користувача та пароля і миттєво прочитаєте цей файл:

echo "kibanaadmin:`openssl passwd -apr1`" | sudo tee -a /etc/nginx/htpasswd.users

Введіть та підтвердьте пароль у діалоговому вікні. Запам’ятайте або запишіть ці облікові дані, оскільки вони потрібні для доступу до веб-інтерфейсу Kibana.

Тепер ми створимо файл серверного блоку Nginx. Як приклад ми надамо цьому файлу ім’я example.com, хоча ви можете дати йому більш описове ім’я. Наприклад, якщо ви налаштували записи FQDN і DNS для цього сервера, ви можете присвоїти цьому файлу ім’я FQDN:

sudo nano /etc/nginx/sites-available/example.com

Додайте до файлу наступний блок коду, замінивши example.com для відповідності FQDN або публічної IP-адреси вашого сервера. Цей код налаштовує Nginx для перенаправлення трафіку HTTP вашого сервера до Kibana, який прослуховує порт localhost:5601. Також він налаштовує Nginx для читання файлу htpasswd.users та вимагає використання базової автентифікації.

/etc/nginx/sites-available/example.com

server {
    listen 80;

    server_name example.com;

    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/htpasswd.users;

    location / {
        proxy_pass http://localhost:5601;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Завершивши редагування, збережіть та закрийте файл.

Потім активуйте нову конфігурацію, створивши символічне посилання каталогу sites-enabled. Якщо ви вже створили файл серверного блоку з тим же ім’ям, що і в навчальному модулі Nginx, вам не потрібно виконувати цю команду:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com

Потім перевірте конфігурацію на синтаксичні помилки:

sudo nginx -t

Якщо в результатах будуть показані будь-які помилки, поверніться і перевірте правильність змін у файлі конфігурації. Коли ви побачите на екрані результатів повідомлення syntax is ok, перезапустіть службу Nginx:

sudo systemctl restart nginx

Якщо ви дотримувалися вказівок модуля з початкового настроювання сервера, у вас повинен бути включений брандмауер UFW. Щоб дозволити з’єднання з Nginx, ми можемо змінити правила за допомогою наступної команди:

sudo ufw allow 'Nginx Full'

Тепер програма Kibana доступна через FQDN або публічну IP-адресу вашого сервера комплексу Elastic. Ви можете переглянути сторінку стану сервера Kibana, відкривши наступну адресу та ввівши свої облікові дані в діалозі:

http://your_server_ip/status

На цій сторінці стану відображається інформація про використання ресурсів сервера, а також відображається список встановлених плагінів.

Тепер інформаційна панель Kibana налаштована, і ми перейдемо до встановлення наступного компонента: Logstash.

Встановлення та налаштування Logstash

Хоча Beats може надсилати дані безпосередньо до бази даних Elasticsearch, рекомендовано використовувати для обробки даних Logstash. Це дозволить вам збирати дані з різних джерел, перетворювати їх на загальний формат і експортувати в іншу базу даних.

Встановіть Logstash за допомогою наступної команди:

sudo apt install logstash

Після встановлення Logstash можна перейти до налаштування. Файли конфгурації Logstash мають JSON і знаходяться в каталозі /etc/logstash/conf.d. При налаштуванні корисно представляти Logstash як конвеєр, який приймає дані з одного боку, обробляє їх та відправляє до пункту призначення (в даному випадку в Elasticsearch). Конвеєр Logstash має два обов’язкові елементи, input та output, а також необов’язковий елемент filter. Плагіни введення споживають дані джерела, плагіни фільтра обробляють дані, а плагіни виводу записують дані до пункту призначення.

Створіть файл конфігурації з ім’ям input.conf, де ви налаштуєте введення даних Filebeat:

sudo nano /etc/logstash/conf.d/input.conf

Вставте наступну конфігурацію input. У ній задається введення beats, який прослуховує порт TCP 5044.

/etc/logstash/conf.d/input.conf

input {
  beats {
    port => 5044
  }
}

Збережіть та закрийте файл. Потім створіть файл конфігурації з ім’ям filter.conf, куди ми додамо фільтр для системних журналів або syslogs:

sudo nano /etc/logstash/conf.d/filter.conf

Вставте наступну конфігурацію фільтра syslog. У цьому прикладі конфігурація системних журналів взята з офіційної документації щодо Elastic. Цей фільтр використовується для синтаксичного аналізу вхідних системних журналів, їх структуризації та перетворення на зручний для використання вид за допомогою панелей Kibana:

/etc/logstash/conf.d/filter.conf

filter {
  if [fileset][module] == "system" {
    if [fileset][name] == "auth" {
      grok {
        match => { "message" => ["%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: %{DATA:[system][auth][ssh][event]} %{DATA:[system][auth][ssh][method]} for (invalid user )?%{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]} port %{NUMBER:[system][auth][ssh][port]} ssh2(: %{GREEDYDATA:[system][auth][ssh][signature]})?",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: %{DATA:[system][auth][ssh][event]} user %{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: Did not receive identification string from %{IPORHOST:[system][auth][ssh][dropped_ip]}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sudo(?:\[%{POSINT:[system][auth][pid]}\])?: \s*%{DATA:[system][auth][user]} :( %{DATA:[system][auth][sudo][error]} ;)? TTY=%{DATA:[system][auth][sudo][tty]} ; PWD=%{DATA:[system][auth][sudo][pwd]} ; USER=%{DATA:[system][auth][sudo][user]} ; COMMAND=%{GREEDYDATA:[system][auth][sudo][command]}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} groupadd(?:\[%{POSINT:[system][auth][pid]}\])?: new group: name=%{DATA:system.auth.groupadd.name}, GID=%{NUMBER:system.auth.groupadd.gid}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} useradd(?:\[%{POSINT:[system][auth][pid]}\])?: new user: name=%{DATA:[system][auth][user][add][name]}, UID=%{NUMBER:[system][auth][user][add][uid]}, GID=%{NUMBER:[system][auth][user][add][gid]}, home=%{DATA:[system][auth][user][add][home]}, shell=%{DATA:[system][auth][user][add][shell]}$",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} %{DATA:[system][auth][program]}(?:\[%{POSINT:[system][auth][pid]}\])?: %{GREEDYMULTILINE:[system][auth][message]}"] }
        pattern_definitions => {
          "GREEDYMULTILINE"=> "(.|\n)*"
        }
        remove_field => "message"
      }
      date {
        match => [ "[system][auth][timestamp]", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
      }
      geoip {
        source => "[system][auth][ssh][ip]"
        target => "[system][auth][ssh][geoip]"
      }
    }
    else if [fileset][name] == "syslog" {
      grok {
        match => { "message" => ["%{SYSLOGTIMESTAMP:[system][syslog][timestamp]} %{SYSLOGHOST:[system][syslog][hostname]} %{DATA:[system][syslog][program]}(?:\[%{POSINT:[system][syslog][pid]}\])?: %{GREEDYMULTILINE:[system][syslog][message]}"] }
        pattern_definitions => { "GREEDYMULTILINE" => "(.|\n)*" }
        remove_field => "message"
      }
      date {
        match => [ "[system][syslog][timestamp]", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
      }
    }
  }
}

Збережіть та закрийте файл після завершення.

Нарешті, створіть конфігураційний файл output.conf:

sudo nano /etc/logstash/conf.d/output.conf

Вставте наступну конфігурацію output. Цей висновок налаштовує Logstash для зберігання даних Beats в Elasticsearch, запущеному на порту localhost:9200, в індексі під назвою використовуваного компонента Beat. Ми будемо використовувати компоненту Beat під назвою Winlogbeat:

/etc/logstash/conf.d/output.conf

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    manage_template => false
    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
  }
}

Збережіть та закрийте файл.

Протестуйте свою конфігурацію Logstash за допомогою наступної команди:

sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash -t

Якщо помилок синтаксису немає, ви побачите повідомлення Configuration OK через кілька секунд. Якщо ви не побачите цього повідомлення, перевірте помилки виводу та оновіть конфігурацію для їх виправлення.

Якщо тестування конфігурації виконано успішно, запустіть та активуйте Logstash, щоб зміни конфігурації набрали чинності:

sudo systemctl start logstash
sudo systemctl enable logstash

Тепер Logstash працює нормально та повністю налаштований, і ми можемо перейти до встановлення Winlogbeat.

Встановлення та налаштування Winlogbeat для збирання логів Windows Server

Спочатку скачаємо останню версію Winlogbeat.

Встановимо його на сервер та налаштуємо файл конфігу winlogbeat.yml

C:\ProgramData\Elastic\Beats\winlogbeat\winlogbeat.yml

winlogbeat.event_logs:
  - name: Application
    ignore_older: 72h
  - name: System
tags: ["winsrv"]
setup.template.settings:
  index.number_of_shards: 1
output.logstash:
  hosts: ["ip серверу:5044"]
logging.level: info
logging.to_files: true
logging.files:
  path: C:/ProgramData/Elastic/Beats/winlogbeat/Logs
keepfiles: 7

Тепер налаштовує logstash на прийом цих логів.

/etc/logstash/conf.d/filter.conf

filter {
  if [fileset][module] == "system" {
    if [fileset][name] == "auth" {
      grok {
        match => { "message" => ["%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: %{DATA:[system][auth][ssh][event]} %{DATA:[system][auth][ssh][method]} for (invalid user )?%{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]} port %{NUMBER:[system][auth][ssh][port]} ssh2(: %{GREEDYDATA:[system][auth][ssh][signature]})?",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: %{DATA:[system][auth][ssh][event]} user %{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:\[%{POSINT:[system][auth][pid]}\])?: Did not receive identification string from %{IPORHOST:[system][auth][ssh][dropped_ip]}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sudo(?:\[%{POSINT:[system][auth][pid]}\])?: \s*%{DATA:[system][auth][user]} :( %{DATA:[system][auth][sudo][error]} ;)? TTY=%{DATA:[system][auth][sudo][tty]} ; PWD=%{DATA:[system][auth][sudo][pwd]} ; USER=%{DATA:[system][auth][sudo][user]} ; COMMAND=%{GREEDYDATA:[system][auth][sudo][command]}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} groupadd(?:\[%{POSINT:[system][auth][pid]}\])?: new group: name=%{DATA:system.auth.groupadd.name}, GID=%{NUMBER:system.auth.groupadd.gid}",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} useradd(?:\[%{POSINT:[system][auth][pid]}\])?: new user: name=%{DATA:[system][auth][user][add][name]}, UID=%{NUMBER:[system][auth][user][add][uid]}, GID=%{NUMBER:[system][auth][user][add][gid]}, home=%{DATA:[system][auth][user][add][home]}, shell=%{DATA:[system][auth][user][add][shell]}$",
                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} %{DATA:[system][auth][program]}(?:\[%{POSINT:[system][auth][pid]}\])?: %{GREEDYMULTILINE:[system][auth][message]}"] }
        pattern_definitions => {
          "GREEDYMULTILINE"=> "(.|\n)*"
        }
        remove_field => "message"
      }
      date {
        match => [ "[system][auth][timestamp]", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
      }
      geoip {
        source => "[system][auth][ssh][ip]"
        target => "[system][auth][ssh][geoip]"
      }
    }
    else if [fileset][name] == "syslog" {
      grok {
        match => { "message" => ["%{SYSLOGTIMESTAMP:[system][syslog][timestamp]} %{SYSLOGHOST:[system][syslog][hostname]} %{DATA:[system][syslog][program]}(?:\[%{POSINT:[system][syslog][pid]}\])?: %{GREEDYMULTILINE:[system][syslog][message]}"] }
        pattern_definitions => { "GREEDYMULTILINE" => "(.|\n)*" }
        remove_field => "message"
      }
      date {
        match => [ "[system][syslog][timestamp]", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
      }
    }
  }
}

/etc/logstash/conf.d/output.conf

output {
 if "winsrv" in [tags] {
  elasticsearch {
            hosts    => ["http://localhost:9200"]
            index    => "winsrv-%{+YYYY.MM}"
    }
  }

Я формую місячні індекси з логами windows серверів. Якщо у вас дуже багато логів або хочете більш гнучке управління об’ємом, що займається, то робіть індекси денні, вказавши winsrv-%{+YYYY.MM.dd}.

Перезапускайте служби на серверах і чекайте надходження даних в elasticsearch

sudo systemctl restart elasticsearch

Далі переходимо до Stack Management та Index patterns де натискаємо кнопку Create index pattern:

Далі вводимо ім’я індексу winsrv та обираймо у полі Timestamp field @timestamp:

Потім можем подивитись на усі наші індекси які поступили у Index Management:

Потім створимо Dashboard

Треба обрати патерни:

А далі налаштовуємо під себе.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *