Przesyłanie i szyfrowanie logów systemowych routera

Przesył logów przez sieć to jedna sprawa, a zabezpieczenie komunikacji by te logi nie szły po kablach w formie niezaszyfrowanej, to całkiem inna bajka. W OpenWRT mamy co prawda do dyspozycji konfigurację w pliku /etc/config/system, która pozwala zdefiniować zdalny adres serwera logów ale ten mechanizm nie obsługuje szyfrowania. W sieci domowej raczej nie powinno nam to przysparzać zmartwień, niemniej jednak dobrze jest się przygotować również na ewentualność przesyłania logów systemowych do zdalnych serwerów zlokalizowanych poza zaufaną siecią. Do tego celu możemy zainstalować syslog-ng i jest on kompatybilny w pełni z innymi linuxowymi daemonami logowania. Dodatkowo, będzie nam potrzebnych szereg narzędzi by wygenerować odpowiednie certyfikaty. Jeśli mamy mało miejsca na flashu routera, generowanie certów i przygotowywanie ich do użycia możemy przeprowadzić spod innego systemu operacyjnego, np. jakiejś płytki/pena live z dowolną dystrybucją linuxa. Być może i na windowsach idzie to osiągnąć ale ja za bardzo się na windowsach nie znam, zatem nie podpowiem zbytnio jak wygenerować certy na tym systemie operacyjnym.

Poniższa konfiguracja routera zakłada, że dysponujemy już zewnętrznym serwerem logów, do którego zamierzamy przesłać komunikaty z routera. Instalujemy zatem potrzebne pakiety:

# opkg update
# opkg install syslog-ng3

Przykład generowanie certyfikatów z wykorzystaniem narzędzi easy-rsa oraz certtool został dokładnie opisany w tym wątku. Jedyne co musimy jeszcze zrobić w przypadku syslog-ng to przepisać nazwę certyfikatu CA -- musi zawierać jego hash. Przy pomocy narzędzia openssl możemy wygenerować taki hash certyfikatu:

# openssl x509 -noout -hash -in ca_192.168.1.150.crt 
f31e2e50

Mają już w ręku potrzebne certyfikaty, kopiujemy je przy pomocy scp na router:

# scp ca_192.168.1.150.crt client_192.168.1.1.crt client_192.168.1.1.key root@192.168.1.1:/etc/syslog-ng.cert/

Logujemy się na router, przechodzimy do katalogu /etc/syslog-ng.cert/ i tworzymy dowiązanie symboliczne do certyfikatu CA dopisując do wygenerowanego wyżej hasha .0 :

# ssh root@192.168.1.1 
# cd /etc/syslog-ng.cert/
# ln -s ./ca_192.168.1.150.crt f31e2e50.0

Katalog z certyfikatami syslog-ng powinien się prezentować następująco:

# ls -al
drwxr-xr-x    2 root     root          4096 Oct 10 20:03 .
drwxr-xr-x    1 root     root          4096 Oct 10 15:27 ..
-rw-r--r--    1 root     root          1525 Oct 10 19:36 ca_192.168.1.150.crt
-rw-r--r--    1 root     root          1643 Oct 10 19:36 client_192.168.1.1.crt
-rw-------    1 root     root          8394 Oct 10 19:36 client_192.168.1.1.key
lrwxrwxrwx    1 root     root            22 Oct 10 20:03 f31e2e50.0 -> ./ca_192.168.1.150.crt

Przechodzimy teraz do konfiguracji syslog-ng . Poniżej znajduje się mój plik konfiguracyjny:

@version:3.0
options {
	# disable the chained hostname format in logs
	chain_hostnames(off);
	
	# the time to wait before a died connection is re-established
	time_reopen (600);
	
	# the time to wait before an idle destination file is closed
	time_reap(0);
	
	# the number of lines buffered before written to file
	# you might want to increase this if your disk isn't catching with
	# all the log messages you get or if you want less disk activity
	# (say on a laptop)
	flush_lines(0);
	
	# the number of lines fitting in the output queue
	log_fifo_size(256);
	
	# enable or disable directory creation for destination files
	create_dirs(no);
	
	# default owner, group, and permissions for log files
	owner(root);
	perm(0600);
	#group("log");
	
	# default owner, group, and permissions for created directories
	#dir_owner(root);
	#dir_group(root);
	#dir_perm(0755);
	
	# enable or disable DNS usage
	# syslog-ng blocks on DNS queries, so enabling DNS may lead to
	# a Denial of Service attack
	use_dns(no);
	# maximum length of message in bytes
	# this is only limited by the program listening on the /dev/log Unix
	# socket, glibc can handle arbitrary length log messages, but -- for
	# example -- syslogd accepts only 1024 bytes
	log_msg_size(1024);
	# Disable statistic log messages.
	stats_freq(0);
	
	# "--MARK--" entries in the log
	mark_freq (1800);
	
	keep_hostname(yes);
	use_fqdn(no);
	long_hostnames(on);
#	ts_format(iso);      #make ISO-8601 timestamps
};

source s_all {
	# message generated by Syslog-NG
	internal();
	# standard Linux log source (this is the default place for the syslog() function to send logs to)
	unix-stream("/dev/log");
	# messages from the kernel
	file("/proc/kmsg" program_override("kernel"));	
};
source s_localhost {
	tcp(ip(127.0.0.1) port(514));
	udp(ip(127.0.0.1) port(514));
};
destination d_messages {
	file("/var/log/messages");
};
destination d_network {
#	tcp( "192.168.1.150" port(514) );
	tcp( "192.168.1.150" port(514)
		tls( ca_dir("/etc/syslog-ng.cert")
			key_file("/etc/syslog-ng.cert/client_192.168.1.1.key") 
			cert_file("/etc/syslog-ng.cert/client_192.168.1.1.crt")
#			peer_verify(optional-untrusted)
			peer_verify(required-trusted)
			)
		);
};

log {
	source(s_all);
	source(s_localhost);
	destination(d_messages);
	destination(d_network);
};

Konfiguracja syslog-ng sprowadza się do zdefiniowania bloków, w których umieszczamy źródła pochodzenia logów (source), oraz takich samych bloków dotyczących miejsca przeznaczenia przetwarzanych komunikatów (destination). Blok source s_all zbiera logi z domyślnych lokalizacji systemowych. Dalej jest source s_localhost ale to tylko na wypadek gdyby jakieś usługi nie łapały się do tego powyższego bloku. Z kolei destination d_messages określa, że logi mają powędrować do sprecyzowanego tam pliku. Kolejny blok (destination d_network) odpowiada za przesyłanie logów przez sieć. Ostatni kawałek spina źródła z miejscami docelowymi, w skrócie, wszystkie logi w systemie OpenWRT powędrują zarówno do lokalnego pliku jak i do zdalnego serwera logów.

Przyjrzyjmy się nieco bliżej blokowi odpowiedzialnemu za przesył logów przez sieć. Gdybyśmy odkomentowali pierwszą linijkę i zakomentowali wszystko poniżej do znaku pierwszego średnika ; , przesył logów przez sieć by nie był szyfrowany, czyli takie samo zachowanie co w przypadku określania zdalnego logowania via plik /etc/config/system . Z tym, że ten wbudowany mechanizm nie umożliwia szyfrowania komunikatów. I tu właśnie do gry wchodzi pozostała część bloku destination d_network . Pierwsza linijka, ta zaczynająca się od tcp , określa gdzie przesłać logi -- adres IP oraz port. W następnej linijce definiujemy, że chcemy zaszyfrować logi przy pomocy modułu TLS, na którego konfigurację składa się szereg parametrów. Pierwszy z nich to ca_dir i określa on katalog z certyfikatami, tymi, które wcześniej utworzyliśmy i przesłaliśmy na router. Dodatkowo, to w tym katalogu trzeba umieścić certyfikat CA oraz link z nazwą jego hasha. Dalej mamy key_file oraz cert_file wskazujące nazwy kluczy, odpowiednio, prywatnego i publicznego routera. Ostatnia opcja (peer_verify) określa czy weryfikować tożsamość serwera logów (na podstawie certyfikatu CA).
Odpalamy syslog-ng i generujemy sobie testową wiadomość:

# /etc/init.d/syslog.ng start 
# logger -t test my syslog-test-message

Powinna ona zostać zapisana w pliku /var/log/messages . Jeśli tak się stało, oznacza to, że część roboty wykonaliśmy prawidłowo. Trzeba także zalogować się na zdalny serwer logów i zobaczyć czy wiadomość również powędrował przez sieć i została odszyfrowana. W moim przypadku wszystko gra:

Oct 25 15:27:28 the-mountain.mhouse.lh s_all@the-mountain syslog-ng[2782] syslog-ng starting up; version='3.0.5' 
Oct 25 15:27:28 the-mountain.mhouse.lh s_all@the-mountain syslog-ng[2782] Syslog connection established; fd='11', server='AF_INET(192.168.1.150:514)', local='AF_INET(0.0.0.0:0)' 
Oct 25 15:27:28 the-mountain.mhouse.lh s_all@the-mountain syslog-ng[2782] Certificate subject matches configured hostname; hostname='192.168.1.150', certificate='192.168.1.150' 
Oct 25 15:27:31 the-mountain.mhouse.lh s_all@the-mountain test: my syslog-test-message

Z tym, że by sprawdzić czy komunikat jest faktycznie szyfrowany i jego treść jest nieczytelna w przypadku gdy ktoś próbuje podsłuchać transmisję, trzeba posłużyć się jakimś snifferem, np. wiresharkiem.

OpenWRT ma własny mechanizm logowania, który jest odpalany via skrypt /etc/init.d/log i jeśli chcemy korzystać z nowego daemona logowania, musimy ten standardowy mechanizm wyłączyć. W przeciwnym razie, syslog-ng otrzyma jedynie tylko część logów i takie komunikaty jak próby logowania na SSH nie zostaną przesłane przez sieć. Zamieniamy zatem daemony:

# /etc/init.d/log disable
# /etc/init.d/syslog-ng enable

Teraz już tylko wystarczy zresetować router.