Использование rsyslog для хранения log-сообщений сетевого оборудования, и loganalyzer для их отображения, обозначило необходимость поиска, соответствующей современным требованиям, альтернативы. В результате анализа различных решений был сделан выбор в пользу open-source компонентов стека ELK. Был ли этот выбор полностью осознанным - скорее нет, ибо популярность ELK стека бьет все рекорды. Поэтому не пощупать его своими руками было бы неразумно. Тем более у меня была давняя задача разобраться с IDS SELKS изнутри, где ELK, как вы заметили, является основой.
Итак, основными элементами ELK являются: Elasticsearch (search engine – для хранения и быстрого поиска структурированных данных), Logstash (collector – для приема в различном формате данных, их фильтрации и преобразования, и последующей отправки в различные базы данных) и Kibana (инструмент для визуализации), которые и составляют акроним ELK. Это в классическом варианте исходя из названия, но в последнее время сюда активно подмешивают Filebeat, который идет как в в паре с Logstash, так и вместо него.
Подробное описание работы этих компонентов не планировалось в рамках данной статьи. Интересующая информация по стеку очень хорошо представлена на официальном сайте, в т.ч. в виде подробной документации, а также в огромном количестве статей и публикаций. Именно по ним я поднимал весь стек пошагово. За основу была взята подробная инструкция здесь, ему помагал материал отсюда и отсюда. Каждый автор решал свою практичечкую задачу поэтому мне пришлось компилировать нужное по ходу. Обычно ELK разворачивают на одном сервере (как с SELKS), но я решил что это будет слишком просто, поэтому в моем полигоне Elasticsearch один хост, Kibana второй хост, и Logstash+FileBeat третий. До кластера руки не дошли, но я уверен, что это будет создать не так уж и трудно.
В ходе работ было проведено:
- установка Elasticsearch
- установка Kibana
- установка Logstash
- установка Filebeat для отправки логов в Logstash
- установка и настройка Winlogbeat
- установка плагина Filebeat для отправки netflow Cisco
- настройка безопасности и авторизация в Kibana (несколько вариантов)
- проксирование подключений к Kibana через Nginx
- автоматическая очистка индексов в elasticsearch.
А теперь мои шаги:
1) Проверить для всех хостов стека с Ubuntu
sudo timedatectl set-timezone Europe/Kiev
sudo apt-get install --reinstall systemd
2) Установить для всех хостов ELK стека
sudo apt-get install apt-transport-https
sudo wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
# Также ставим JDK for Elasticsearch (Host0) & Logstash (Host1)
sudo apt install default-jdk -y
java -version
3) Настройка Elasticsearch (Host0, IP 192.168.1.11, port 9200,9300)
- /etc/elasticsearch/elasticsearch.yml:
network.host: 0.0.0.0 (or 192.168.1.11)
http.port: 9200
transport.host: localhost
transport.tcp.port: 9300
# проверка статуса сервиса
sudo service elasticsearch status
# проверка web-отклика elasticsearch:
curl localhost:9200
Список актуальных индексов можно получить при помощи запроса:
curl 'localhost:9200/_cat/indices?v'
Для постоянной чистки индексов лучше использовать elasticsearch-curator:
wget https://packages.elastic.co/curator/5/debian/pool/main/e/elasticsearch-curator/elasticsearch-curator_5.7.5_amd64.deb
sudo dpkg -i elasticsearch-curator_5.7.5_amd64.deb
# /etc/curator/action.yml
actions:
1:
action: close
description: >-
Close indices older than 60 days (based on index name).
options:
ignore_empty_list: True
delete_aliases: False
disable_action: False
filters:
- filtertype: pattern
kind: prefix
value: nginx-
- filtertype: age
source: name
direction: older
timestring: '%Y.%m.%d'
unit: days
unit_count: 60
2:
action: delete_indices
description: >-
Delete indices older than 90 days (based on index name).
options:
ignore_empty_list: True
disable_action: False
filters:
- filtertype: pattern
kind: prefix
value: nginx-
- filtertype: age
source: name
direction: older
timestring: '%Y.%m.%d'
unit: days
unit_count: 90
# Test dry-run:
sudo curator --config /etc/curator/config.yml --dry-run /etc/curator/action.yml
# /etc/curator/delete_indices.yml
actions:
1:
action: delete_indices
description: >-
Delete indices older than 90 days (based on index name), for logstash
and filebeat prefixed indices.
options:
ignore_empty_list: True
timeout_override:
continue_if_exception: False
disable_action: False
filters:
- filtertype: pattern
kind: regex
value: '^(logstash-|filebeat-|nginx-).*$'
exclude:
- filtertype: age
source: name
direction: older
timestring: '%Y.%m.%d'
unit: days
unit_count: 90
exclude:
# Test dry-run:
sudo curator --config /etc/curator/config.yml --dry-run /etc/curator/delete_indices.yml
Очистка индексов будет выполняться каждый день в 4 утра:
crontab -e 0 4 * * * /usr/bin/curator --config /etc/curator/config.yml /etc/curator/action.yml
Хотя в последних версиях Elastic есть настройка автоматической чистки индекса штатными средствами, без curator-а.
4) Настройка Filebeat (Host1, IP 192.168.1.12, port 5044)
- /etc/filebeat/filebeat.yml:
# что именно мониторим:
filebeats.inputs:
- type: filestream
enabled: true
paths:
- /var/log/nginx/*.log
- /var/log/*.log
# Можно настроить передачу напрямую в Elasticsearch или Logstash.
# Можно настроить передачу напрямую в Kibana через API. Нам это понадобится для отрисовывания графиков netflow (п.12).
setup.kibana:
host: "192.168.1.12:5601"
# Мы передаем данные локально в logstash:
output.logstash:
hosts: ['localhost:5044']
# Проверяем корректность конфига:
sudo filebeat test config -e
# Если сервис filebeat не запускается нужно проверить файл:
- /etc/systemd/system/filebeat.service:
[Unit]
Description=Filebeat sends log files to Logstash or directly to Elasticsearch.
Documentation=https://www.elastic.co/products/beats/filebeat
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/usr/share/filebeat/bin/filebeat --path.config "/etc/filebeat"
Restart=always
[Install]
WantedBy=multi-user.target
У меня тут что-то не сошлось и мне его пришлось создавать руками.
:проверка статуса
sudo systemctl status filebeat
:проверка журнала
sudo tail -f /usr/share/filebeat/bin/logs/filebeat
Модули filebeat работают только в том случае, если вы отправляете данные напрямую в Elasticsearch. На него вы тоже ставите соответствующий плагин и получаете отформатированные данные с помощью elastic ingest. Но у нас работает промежуточное звено Logstash, который принимает данные. С ним плагины filebeat не работают, поэтому приходится отдельно в logstash парсить данные. Это не очень сложно, но тем не менее. Как мне обьяснили это плата за удобства, которые дает logstash. Если у вас много разрозненных данных, то отправлять их напрямую в Elasticsearch не так удобно, как с использованием предобработки в Logstash.
5) Настройка Logstash (Host1, IP 192.168.1.12, port 1514)
- /etc/logstash/logstash.yml
All params have been commented.
# Прием логов с Filebeat:
/etc/logstash/conf.d/input.conf
input {
beats {
port => 5044
client_inactivity_timeout => "1200"
# SSL отключен потому как Logstash и Filebeat общаются на одном Host1
ssl => false
ssl_certificate => "/etc/ssl/logstash/logstash.crt"
ssl_key => "/etc/ssl/logstash/logstash.key"
}
file {
path => "/var/log/nginx/*.log"
}
}
# Фильтрация логов c nginx (его мы будет мониторить для теста всего стека):
/etc/logstash/conf.d/nginx-error.conf
filter {
if [type] == "nginx_error" {
grok {
match => { "message" => "(?<timestamp>%{YEAR}[./] %{MONTHNUM}[./]%{MONTHDAY} %{TIME}) \[%{LOGLEVEL:severity}\] %{POSINT:pid}#%{NUMBER}: %{GREEDYDATA:errormessage},
\ client: %{IP:client}, server: \$domain, request: \"%{WORD:method} %{URIPATH:path}\"" }
}
}
else if [type] == "nginx_access" {
grok {
match => { "message" => "%{IPORHOST:remote_ip} - %{DATA:user} \[%{HTTPDATE:access_time}\] \"%{WORD:http_method} %{DATA:url} HTTP/%{NUMBER:http_version}\" %{NUMBER:response_code} %{NUMBER:body_sent_bytes} \"%{DATA:referrer}\" \"%{DATA:agent}\"" }
}
}
date {
match => [ "timestamp" , "dd/MMM/YYYY:HH:mm:ss Z" ]
}
geoip {
source => "remote_ip"
target => "geoip"
add_tag => [ "nginx-geoip" ]
}
}
# Передача логов на Elasticsearch:
/etc/logstash/conf.d/output.conf
output {
if [type] == "nginx_access" {
elasticsearch {
hosts => "192.168.1.11:9200"
index => "nginx-%{+YYYY.MM.dd}"
}
}
else if [type] == "nginx_error" {
elasticsearch {
hosts => "192.168.1.11:9200"
index => "nginx-%{+YYYY.MM.dd}"
}
}
else if "winsrv" in [tags] {
elasticsearch {
hosts => "192.168.1.11:9200"
index => "winsrv-%{+YYYY.MM.dd}"
}
}
else {
elasticsearch {
hosts => "192.168.1.11:9200"
index => "logstash_msg"
}
}
#stdout { codec => rubydebug }
}
:проверка статуса
sudo systemctl status logstash.service
:проверка журнала
sudo tail -f /var/log/logstash/logstash-plain.log
6) Настройка NGINX (Host1, IP 192.168.1.11, port 80,443) для теста
sudo apt install nginx -y
sudo nginx -t
7) Настройка Kibana (Host2, IP 192.168.1.10, port 5601)
- /etc/kibana/kibana.yml
server.host: 192.168.1.10
server.port: 5601
...
Пс: создание SSL-сертификатов в п.10.
# включаем доступ к frontend Kibana по https:
server.ssl.enabled: true
server.ssl.certificate: /home/vagrant/Kibana.crt
server.ssl.key: /home/vagrant/rootCA.key
# включаем доступ к frontend Kibana через Nginx:
Создаем файл для пользователя и генерируем пароль:
# htpasswd -c /etc/nginx/htpasswd.users kibanauser
-OR-
# echo "kibanauser:`openssl passwd -apr1`" | sudo tee -a /etc/nginx/htpasswd.users
# Создаем файл с виртуальным сайтом для веб-сервера Nginx:
sudo nano /etc/nginx/sites-available/elk
# Проверяем в kibana.yml:
server.host: localhost
# доступ по http Nginx:
- /etc/nginx/sites-available/elk
server {
listen 80;
server_name 192.168.1.10;
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;
}
}
-OR-
# досту по https Nginx:
server {
listen 443 ssl;
server_name 192.168.1.10;
# by password
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/htpasswd.users;
# by IP
allow 192.168.1.0/24;
deny all;
# by SSL
ssl_certificate /home/vagrant/Kibana.crt;
ssl_certificate_key /home/vagrant/rootCA.key;
ssl_ciphers EECDH:+AES256:-3DES:RSA+AES:RSA+3DES:!NULL:!RC4:!RSA+3DES;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.1 TLSv1.2;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options nosniff;
location / {
proxy_pass https://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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
sudo ln -s /etc/nginx/sites-available/elk /etc/nginx/sites-enabled/
:start
sudo service kibana start
:проверка статуса
sudo systemctl status kibana
sudo service kibana status
:проверка журнала
sudo tail -f /var/log/kibana/kibana.log
Тоже самое сделать и для Nginx.
8) Включаем Elastic security.
По умолчанию ELK беззащитен, поэтому добавим базовую защиту.
Закрываем в /etc/nginx/sites-available/elk две строки закомментируем иначе будет масло масленное:
# auth_basic "Restricted Access";
# auth_basic_user_file /etc/nginx/htpasswd.users;
Генерируем пароли от Elastic-a:
# /usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto
Changed password for user apm_system
PASSWORD apm_system = iBRUvfTvOWOrxCrVd2K5
Changed password for user kibana_system
PASSWORD kibana_system = 0eRyH6kzsmyC7tvc5PBK
Changed password for user kibana
PASSWORD kibana = 0eRyH6kzsmyC7tvc5PBK
Changed password for user logstash_system
PASSWORD logstash_system = K1k6Vuh9zqxzkb4YILW5
Changed password for user beats_system
PASSWORD beats_system = gM0AUnS062SA71VQjlyb
Changed password for user remote_monitoring_user
PASSWORD remote_monitoring_user = GPnQJnrhKUpEmVlqJoXA
Changed password for user elastic (Web Kibana)
PASSWORD elastic = VouGayh9oNHrjtthnI9k
Эти пароли надо запомнить, ибо в явном виде они более нигде не видны.
Некоторые из них можно будет позже изменить в фронтенде Kibana.
Далее в Kibana заходим пользователем elastic!
9) Elastic security update - выполним необходимые изменения ибо теперь Elastic без пароля не пускает никого.
# для Kibana в kibana.yml добавляем:
xpack.security.enabled: true
elasticsearch.username: "kibana_system"
elasticsearch.password: "0eRyH6kzsmyC7tvc5PBK"
Для приема данных из Logstash не стоит использовать встроенного logstash_system, а лучше создать нового Logstash_index.
# для Logstash в output.yml в каждую секцию добавляем:
user => "Logstash_index"
password => "zkb4YILW5"
Для входа в фронтенд Kibana также следует вместо встроенного elastic-а создать нового типа kibana_admin:
{
"password" : "123456",
"roles" : [ "kibana_admin" ],
"full_name" : "Kibana Administrator",
"email" : "kibana.administrator@example.local"
}
и после добавить ему необходимые роли, чтобы он видел индексы в Discovery и пользоваться далее уже им.
Также настраиваем параметры пользовательских сессий Kibana:
- закрываем неактивные сессии:
xpack.security.session.idleTimeout: "30m"
- устанавливаем максимальную продолжительность одной сессии:
xpack.security.session.lifespan: "1d"
- настраиваем интервал принудительной очистки данных о неактивных или просроченных сессиях из сессионного индекса:
xpack.security.session.cleanupInterval: "8h"
Для всех параметров формат времени может быть следующим: ms | s | m | h | d | w | M | Y
Данные о сессии удаляются после того, как пользователь осуществляет закрытие сессии. Если не настроить закрытие неактивных сессий или не ограничить максимальную длительность сессии, то информация об этих сессиях будет накапливаться в сессионном индексе, и Kibana не сможет автоматически удалить данные.
10) SSL - то что надо было сделать с самого начала.
Классификация SSL-файлов:
.pem, .crt, .cer - готовый, подписанный центром сертификации сертификат, расширения разные, но означают одно и то же. Если совсем просто, то сертификат, это подписанный открытый ключ, плюс немного информации о вашей организаци;
.key - закрытый или открытый ключ;
.csr - запрос на подпись сертификата, в этом файле хранится ваш открытый ключ плюс информация, об организации и домене, которую вы указали.
Для генерации мы используем OpenSSL на примере Host1.
1. Создаем закрытый "корневой" ключ:
openssl genrsa -out LogstashCA.key
2. Создаем корневой сертификат с использованием сгенерированого ключа:
openssl req -x509 -new -nodes -key LogstashCA.key -sha256 -days 1024 -out Logstash.pem
3. Создаем запрос на сертификат (CSR):
CSR - обычно это та информация, которая отправляется в УЦ, но в нашем случае мы подписываем сертификат самостоятельно.
openssl req -new -key LogstashCA.key -out Logstash.csr
4. Выпускаем сертификат:
openssl x509 -req -in Logstash.csr -CA Logstash.pem -CAkey LogstashCA.key -CAcreateserial -out Logstash.crt -days 365 -sha256
Копируем файлы в соот папки:
ssl_certificate => "/etc/ssl/logstash/logstash.crt"
ssl_key => "/etc/ssl/logstash/logstash.key"
11) Подключаем плагин Netflow для filebeat.
За подробностями идете сюда.
filebeat modules enable netflow
# cat /etc/filebeat/modules.d/netflow.yml
- module: netflow
log:
enabled: true
var:
netflow_host: 192.168.100.1
netflow_port: 9996
systemctl stop filebeat
systemctl start filebeat
# и для Cisco router включаем netflow на передачу:
router(conf-if)#ip route-cache flow
router(conf-if)#exit
router(config)#ip flow-export destination 192.168.1.12 9996
router(config)#ip flow-export version 5
Вот на этом вроде бы все. На самом деле это только начало, впереди еще изучение всего фронтенда Kibana, и также фильтрации сообщений через Grok. Плюс ко всему надо будет вернуться к SELKS. Скучно точно не будет!
No comments:
Post a Comment
А что вы думаете по этому поводу?