сервер системних журналів

| щоденник, комп'ютери, linux, підказка

я не розумію, чому до цього часу не мав локального сервера журналів (syslog) у мережі… нема чого бідкатися й пригадувати — час просто зробити це. сервер крутитиметься на віртуальній машині proxmox: мініальна debian 10, 256-512 мб пам’яті (угу, я мінімаліст), системний диск 8 гб, окремий віртуальний диск (lvm) для /var/log/ на 32 гб (lvm, щоби можна було за потреби додати), — для трьох шлюзів, трьох фізичних серверів та кількох віртуальних машин має вистачити?

зміст

віртуальна машина 109… чи 106

з міркувань естетики хотів закріпити за цією віртуалкою id 109 (тому що log), але коли створював, думав про інше і наклацав 106. а маєш =/

ілюстрація: заготовка віртуальної машини

після встановлення системи доставляю «бантики»: sudo та qemu-guest-agent:

su root
apt-get update
apt-get install sudo
/usr/sbin/usermod -aG sudo <user>
apt-get install qemu-guest-agent
systemctl start qemu-guest-agent
systemctl enable qemu-guest-agent

зафіксувати адресу ip:

vi /etc/network/interfaces
# ---- >8 ----
iface ens18 inet static
  address 192.168.1.109/24
  gateway 192.168.1.1
# ---- 8< ----

віртуальний диск для /var/log

час налаштувати монтування другого віртуального диска як /var/log. по-перше, перевірка, що він є в системі (незмонтований накопичувач на 32 гб):

lsblk -o +fstype,uuid

в моєму випадку це /dev/sdb. віддаю ввесь під логічний ́розділ var-vg/log:

pvcreate /dev/sdb
vgcreate var-vg /dev/sdb
lvcreate -l 100%VG -n log var-vg
# форматування ext4
mkfs.ext4 /dev/var-vg/log

далі цікаве: перемістити /var/log на новий розділ, але це треба зробити в режимі init 1 без доступу до мережі (тобто не варто робити через ssh, льоль!):

init 1
mkdir /mnt/temp.varlog
mount /dev/mapper/var--vg-log /mnt/temp.varlog
cp -apx /var/log/* /mnt/temp.varlog
mv /var/log /var/log.backup
cp /etc/fstab /etc/fstab.backup.$(date +'%Y-%m-%d')
vi /etc/fstab
# ---- >8 ----
/dev/mapper/var--vg-log	/var/log	/ext4	errors=remount-ro	0	1
# ---- 8< ----
umount /mnt/temp.varlog
mount /var/log

перевірка (розділ var–vg-log повинен бути змонтований до /var/log і містити копію журналів зі старої теки, котру тепер збережено до /var/log.backup):

lsblk -o +fstype
ls /var/log/
ls /var/log.backup/

якщо все гаразд — перезавантаження як найпростіший спосіб переконатися, що налаштування в порядку (якщо ні — паніка, льоль):

systemctl reboot now

наостанок можна видалити стару копію (/var/log.backup).

ілюстрація: мінімальна віртуальна машина для сервера журналів

налаштування сервера rsyslog

вибір варіанту сервіса (syslog, syslog-ng, rsyslog) навіть не обговорюється, — rsyslog. на debian 10 має бути вже встановлений та запущений, перевірка:

sudo apt-cache policy rsyslog
systemctl status rsyslog

налаштування — в /etc/rsyslog.conf (не забути зберегти копію перед редагуванням); але з налаштуваннями плутанина:

коротше кажучи, доведеться експериментувати.

перший млинець нанівець

для початку — датована резервна копія оригінального файлу налаштувань:

sudo cp /etc/rsyslog.conf /etc/rsyslog.conf.backup.$(date +'%Y-%m-%d')

порядок опцій у файлі налаштувань rsyslog — важливий; розбивки на секції/станзи, насправді, немає, попри те, що коментарі створюють враження структури; класичний порядок приблизно такий:

  • модулі (modules)
  • глобальні директиви (global directives)
  • шаблони (templates)
  • правила (rules)

деякі вихідні думки:

  • upd чи tcp? традиційно журнали «ганяли» мережею по udp, щоби виграти трішки в швидкості, але в сучасних швидких локалках важливіші надійність та контроль потоку;
  • сервер має приймати журнали лише від пристроїв у локальній мережі;
  • людей, котрі досі використовують формат журналів bsd (rfc3164) треба піддавати примусовій корекції в спеціяльних виправних закладах, а найбільш буйних — ізолювати від суспільства, нмсд; найгірше — це «американський» формат дати; я не розумію, чому debian досі не використовує за замовчуванням новий формат syslog protocol 23(rfc5424);
  • у великих інфраструктурах з терабайтами журналів зручно, мабуть, їх структурувати не лише за пристроєм, але й за процесом, що генерує записи; але для домашньої мережі — чому не один загальний файл .log на кожен пристрій?

отже, перший «млинець» буде такий (деякі рядки треба лише розкоментувати, інші — додати; загальний порядок має зберегтися):

sudo vi /etc/rsyslog.conf
# ---- >8 ----
…
module(load="imtcp")			# приймати журнали syslog з мережі по TCP
input(type="imtcp" port="514")		# порт 514
…
$AllowedSender TCP, 192.168.1.0/24	# дозволити лише TCP, з локальної мережі
…
# $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat	# старий формат фсад!
$ActionFileDefaultTemplate RSYSLOG_SyslogProtocol23Format	# формат rfc5424 (aka syslog protocol 23)
…
$template Template_RemoteLogs,"/var/log/remote/%HOSTNAME%.log"  # шаблон: один файл на пристрій
…
*.*     ?Template_RemoteLogs					# застосувати шаблон до всього
…
# ---- 8< ----

можна перезавантажити сервіс rsyslog і перевірити, чи він не лається на помилки в файлі налаштувань:

sudo systemctl restart rsyslog
systemctl status rsyslog

якщо на позір все гаразд, — час сказати рутеру й точці доступу (обидва — linksys ea8300 з openwrt), що можна слати журнал на 192.168.1.109…

ілюстрація: переадресація журналу на рутері з openwrt

щоби випробувати налаштування, треба також налаштувати надсилання журналів на сервер (192.168.1.109) з якоїсь іншої машини linux, — в моєму випадку це буде інша малесенька віртуалка debian з локальним vpn’ом; на ній треба розкоментувати/додати декілька рядків до /etc/rsyslog.conf і перезапустити сервіс:

sudo cp /etc/rsyslog.conf /etc/rsyslog.conf.backup.$(date +'%Y-%m-%d')
sudo vi /etc/rsyslog.conf
# ---- >8 ----
...
# $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$ActionFileDefaultTemplate RSYSLOG_SyslogProtocol23Format
...
*.*	@@192.168.1.109:514	# Send all via TCP to IP:Port
...
# ---- 8< ----
sudo systemctl restart rsyslog
systemctl status rsyslog

тепер, якщо зазирнути до /var/log/remote на сервері журналів, можна побачити щось таке (tree немає «з коробки» в мінімальній debian, довстановлюється)́:

tree -sh /var/log/remote/
/var/log/
...
|-- [4.0K]  apt
|   |-- [ 13K]  history.log
|   `-- [ 76K]  term.log
|-- [ 35K]  auth.log
|-- [ 12M]  daemon.log
|-- [ 42K]  debug
|-- [193K]  dpkg.log
...
|-- [4.0K]  remote
|   |-- [ 83K]  ap2.log
|   |-- [ 13M]  router.log
|   |-- [160K]  log.log
|   `-- [1.2K]  vpn.log
...
|-- [ 13M]  syslog
...

на позір наче все працює? — тож чому я кажу про «перший млинець нанівець», що не так?

кляті ці питання

метод «наукового тику» працює, але краще добряче «покурити мануал» і зрозуміти, як правильно налаштовується rsyslog. a питань, насправді, багато.

звідки взявся log.log в теці remote, — адже це локальна машина?

додане правило для зберігання журналів до файлів за хостом (у класичному форматі) застосовує шаблон Template_RemoteLogs до подій, отриманих від усіх вхідних модулів однаково, в т.ч. imtcp (мережевий, tcp) і imuxsock (локальний systemd):

*.*     ?Template_RemoteLogs

щоби цього уникнути, можна «загорнути» правило в умовний блок if … then:

if $inputname == 'imtcp' or $inputname == 'impudp' then {
*.* 	?Template_RemoteLogs
}

чому все з віддалених машин дублюється також в локальний syslog?

до кожного повідомлення застосовуються всі правила по черзі, згори додолу (якщо не зустрінеться явна директива зупинити обробку: ~ або stop); тож всі правила, що йдуть після застосування шаблону Template_RemoteLogs також продовжували застосовуватися до всіх повідомлень, включно з отриманими з мережі:

*.*     ?Template_RemoteLogs
…
*.*;auth,authpriv.none          -/var/log/syslog
…

де журнали openvpn, чому вони не потрапляють до remote/vpn.log?

файл конфігурації сервера openvpn /etc/openvpn/server.conf містить такий рядок:

log-append /var/log/openvpn.log

якщо його прибрати, openvpn зберігає свій журнал через системний виклик (systemd), звідки той потрапляє до syslog. цей рядок я потяг, мабуть, з якоїсь не вельми якісної підказки в тенетах. прибрав, перезавантажив сервіс — і можна переглядати логи vpn на сервері журналів.

так само щодо apt та інших додатків: не потрапляють на сервер журналів, та ще й мають різні формати

питання не має простої відповіді; деякі програми просто написані без урахування журналювання через системні виклики; більш винахідливі й завзяті дослідники питання пропонують різні способи обійти це обмеження зокрема для dpkg/apt, але я не бачу сенсу заморочуватися на своїх малесеньких віртуалках.

що означає мінус перед іменем файлу в прикладах з тенет, і чому його тут нема?

приклад плутанини в старому форматі налаштувань rsyslog: мінус примусово виключає синхронізацію (запис буфера на диск) після кожної операції запису, ставиться перед шляхом файлу чи назвою шаблону в правилі:

*.*     -?Template_RemoteLogs
…
*.*;auth,authpriv.none          -/var/log/syslog

але! відкладена синхронізація і так є стандартною поведінкою rsyslog, тож навіщо? мабуть, тому, що немає директиви зі зворотньою дією, — якогось плюсика, який би вмикав примусову синхронізацію для окремих правил: увімкнути її можна, якщо я не помиляють, лише глобально (принаймні в класичному форматі):

$ActionFileEnableSync on

це надійніше, проте сильно, сильно вповільнює запис на диск. в домашній мережі, а ще й на віртуальній машині, навіть якщо якась непередбачувана халепа трапиться і система не встигне скинути буфери на диск — в мене будуть «цікавіші» проблеми, аніж відсутність кількох рядків у журналах; мінусів можна наставити, але оскільки я не використовуватиму опцію примусової синхронізації, то вони ролі не гратимуть (хоча зі старшими версіми rsyslog виникали питання).

що буде, якщо сервер журналів тимчасово недоступний (перезавантажується тощо)?

без налаштування черг(и) rsyslog на стороні клієнтів, всі події, згенеровані там, на сервер журналів не потраплять! вони, втім, збережуться локально (хіба що локальне журналювання вимкнене, але ж який бовдур таке втне?) щоби цього уникнути, можна додати декілька глобальних налаштувань черг (на клієнтських машинах!) після $WorkDirectory (черги непогано пояснені в документації); тоді клієнт зберігатиме події в локальній черзі, продовжуючи спроби надіслати їх (із затримкою):

$WorkDirectory /var/spool/rsyslog	# тека черг (стандартна опція, швидше за все вже є в конфігу)
# --- важливі налаштування ---
$ActionQueueType LinkedList		# режим черги: в оперативній пам'яті, з динамічним розміром
$ActionQueueFileName actionQueue	# зберігати чергу на диск за потреби; префікс імені для файлів
$ActionQueueMaxDiskSpace 512M		# розмір черги на диску (K/M/G), автоматично обмежує чергу в пам'яті
$ActionQueueSaveOnShutdown on		# зберігати чергу під час вимикання/перезавантаження
$ActionResumeRetryCount -1		# пробувати нескінченно
# --- опційні налаштування ---́
$ActionQueueDiscardSeverity 6		# якщо черга повна, відкидати повідомлення рівня info (6), debug (7)

як контролювати заповнення диска?

в теорії, можна налаштувати «тригери» на розмір журналів просто в конфігурації rsyslog; на практиці — ці тригери запускають зовнішні скрипти, які доведеться самому писати, а не якусь ротацію журналів самим сервісом rsyslog… тому зручніше, нмсд, скористатися вже готовим інструментом — logrotate, додавши файл якийсь такий файл до теки /etc/logrotate.d (якщо її нема, треба доставити logrotate):

sudo vi /etc/logrotate.d/remote
# ---- >8 ----
/var/log/hosts/* /var/log/hosts/*/* {
  size 50M
  rotate 3
  notifempty
  missingok
}
# ---- 8< ----

з цим налаштуванням, logrotate «обрізатиме» будь-який файл в теці /var/log/hosts/ та підтеках, до розміру 50 мб, зберігаючи три старіших «обрізки», ігноруючи порожні файли, і не генеруючи зайвих помилок, якщо вручну видалити якийсь журнал.

як перевірити конфіг, не (пере)запускаючи сервіс?

ось так, з опцією -N1 (повний шлях до rsyslogd потрібен тому, що debian не включає /usr/sbin до PATH, — баг? фіча? хз):

sudo /usr/sbin/rsyslogd -N1 -f /etc/rsyslog.conf

якщо ви натрапили на цю публікацію, але не знайшли відповідь на своє питання — залишайте коментар, з’ясовуватимемо разом. тим часом, я вже забагато часу пацькаюся з цим дописом, час виводити до фіналу й публікувати.

tl;dr

мінімальний конфіг для сервера rsyslog

отже, вимоги до мінімального правильного конфігу на моєму сервері журналів:

  • журнали всіх хостів (включно з самим сервером журналів) мають бути в теках /var/log/hosts/<hostname>/, основний журнал — у файлі .log, але…
  • …журнали ключових сервісів (dns на рутері, openvpn на сервері vpn) — в окремих файлах за назвою сервісу (ovpn-server.log тощо);
  • локальні журнали, від яких залежить робота окремих сервісів, мають дублюватися до відповідних файлів (наприклад, fail2ban дивиться до /var/log/auth.log)
  • формат журналів — syslog protocol 23 (rfc5424).

сам файл налаштувань сервера (/etc/rsyslog.conf) у «класичному» форматі:

# /etc/rsyslog.conf configuration file for rsyslog
# -------
# MODULES
# -------
module(load="imuxsock")         # provides support for local system logging
module(load="imklog")           # provides kernel logging support
module(load="imtcp")            # Listens to TCP over network
input(type="imtcp" port="514")  # ...on port 514
# -----------------
# GLOBAL DIRECTIVES
# -----------------
# Restrict allowed log senders to TCP on the LAN
$AllowedSender TCP, 192.168.1.0/24
# Use Syslog protocol 23 (RFC5424)
$ActionFileDefaultTemplate RSYSLOG_SyslogProtocol23Format
# Set the default permissions for all log files.
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022
# Where to place spool and state files
$WorkDirectory /var/spool/rsyslog
# Include all config files in /etc/rsyslog.d/
$IncludeConfig /etc/rsyslog.d/*.conf
# ---------
# TEMPLATES
# ---------
$template Template_ByHostSysLogs,"/var/log/hosts/%HOSTNAME%/%HOSTNAME%.log"
$template Template_ByHostAppLogs,"/var/log/hosts/%HOSTNAME%/%PROGRAMNAME%.log"
$template Template_ByHostDebugLogs,"/var/log/hosts/%HOSTNAME%/debug.log"
# -----
# RULES
# -----
# Capture some app logs (DNSMasq, OpenVPN) to separate files by host
if ($programname == 'dnsmasq'
  or $programname == 'ovpn-server') then {
*.*             -?Template_ByHostAppLogs
} else {
# Use basic template for everything (info and above),
# store debug messages in a separate file per host
*.info          -?Template_ByHostSysLogs
*.=debug        -?Template_ByHostDebugLogs
}
# Only apply this to local logs, special cases
if ($inputname == 'imuxsock') then {
# Fail2ban depends on auth.log by default
auth,authpriv.*                 /var/log/auth.log
#
# Emergencies are sent to everybody logged in.
*.emerg                         :omusrmsg:*
}

мінімальний конфіг для клієнтів

на клієнтських машинах потрібно таке:

  • копіювати (!) журнали на сервер журналів
  • якщо сервер «впав» — зберігати в черзі й надіслати накопичене, коли з’явиться;
  • формат журналів — syslog protocol 23 (rfc5424).

файл налаштувань для клієнта (/etc/rsyslog.conf):

# /etc/rsyslog.conf configuration file for rsyslog
# -------
# MODULES
# -------
module(load="imuxsock") # provides support for local system logging
module(load="imklog")   # provides kernel logging support
# ------
# GLOBAL
# ------
# Use syslog protocol 23 (RFC5424) event format
$ActionFileDefaultTemplate RSYSLOG_SyslogProtocol23Format
# Set the default permissions for all log files.
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022
# Where to place spool and state files
$WorkDirectory /var/spool/rsyslog
# Setup message queue for when syslog server is offline
$ActionQueueType LinkedList
$ActionQueueFileName actionQueue
$ActionQueueMaxDiskSpace 512M
$ActionQueueSaveOnShutdown on
$ActionResumeRetryCount -1              
$ActionQueueDiscardSeverity 6 
# Include all config files in /etc/rsyslog.d/
$IncludeConfig /etc/rsyslog.d/*.conf
# -----
# RULES
# ----- 
# Send all (info and above) to the syslog server
*.*     @@192.168.1.29:514
# -----
# On client hosts, keep most of the default rules
auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv.none          -/var/log/syslog
#cron.*                         /var/log/cron.log
daemon.*                        -/var/log/daemon.log
kern.*                          -/var/log/kern.log
lpr.*                           -/var/log/lpr.log
mail.*                          -/var/log/mail.log
user.*                          -/var/log/user.log
mail.info                       -/var/log/mail.info
mail.warn                       -/var/log/mail.warn
mail.err                        /var/log/mail.err
*.=debug;\
        auth,authpriv.none;\
        news.none;mail.none     -/var/log/debug
*.=info;*.=notice;*.=warn;\
        auth,authpriv.none;\
        cron,daemon.none;\
        mail,news.none          -/var/log/messages
*.emerg                         :omusrmsg:*

мабуть, це ще далеко від ідеалу, але такі налаштування працюють приблизно так, як я хочу.