Centralny system składowania logów

maj 31st, 2007

Po nieco ponad miesiącu intensywnego testowania niedawnego dzieła postanowiłem napisać nieco o możliwości jakie daje syslog-ng :)


Jak to więc wygląda ? W DMZ znajduje się serwer który posiada otwarty port 514 udp dla maszyn z DMZ które mają korzystać z centralnego systemu logów oraz port 3306 dostępny tylko z jednego serwera z LAN. Na serwerze tym działa baza MySQL oraz Syslog-NG. Zdalne urządzenia / serwery przekazują logi do daemona który to zapisuje jednocześnie do MySQL. W czasie rzeczywistym baza jest replikowana na serwer pracujący w LAN i na tej maszynie uruchomiony jest apache oraz panel PHP do przeglądania oraz analizowania logów. Tutaj także uruchamiane są skrypty rotujące i backupujące archiwalne logi (w MySQL). Podyktowane jest to faktem że baza z którą łączy sie panel www jest tylko replika bazy z serwera zlokalizowanego w DMZ. Oznacza to, że jeśli agresor/intruz przejąłby kontrolę nad serwerem w DMZ mógłby usunąć cała bazę logów a serwer w LAN replikując te działanie także usunąłby bazę logów.

Do dzieła. Najpierw oczywiście serwer w DMZ. Poniżej modyfikowane kawałki syslog-ng.conf

options {
chain_hostnames(0);
long_hostnames(off);
create_dirs(yes);
dir_perm(0755);
sync(10);
owner(root);
group(logs);
perm(0640);
use_dns(yes);
dns_cache(yes);
log_msg_size(4096);
log_fifo_size(2048);
};
source net {
udp();
};
destination mysql {
pipe("/var/log/mysql.pipe"
template("INSERT INTO logs(host, facility, priority, level, tag, datetime, program, msg)
VALUES ( '$HOST', '$FACILITY', '$PRIORITY', '$LEVEL', '$TAG', '$YEAR-$MONTH-$DAY $HOUR:$MIN:$SEC', '$PROGRAM', '$MSG' );\n") template-escape(yes));
};
filter f_remote {
(
facility(user,daemon,auth,authpriv,syslog,lpr,uucp,ftp,local0,local1,local2,local3,local4,local5,local6,local7)
and level(info..emerg)
) or (
facility(kern,mail,cron,news)
and level(err..emerg)
);
};
log {
source(src);
filter(f_remote);
destination(mysql);
};
log {
source(net);
filter(f_remote);
destination(mysql);
};

Pojawiło się odwołanie do potoku więc musi być także stworzony, np /etc/rc.d/init.d/syslog-mysql i odpowiednio zlinkowany

SYSLOG_HOST="127.0.0.1"
SYSLOG_PORT="3306"
SYSLOG_USER="syslogfeeder"
SYSLOG_PASSWD="Haslo"
SYSLOG_DB="syslog"
if [ ! -e /var/log/mysql.pipe ]; then
mkfifo /var/log/mysql.pipe
fi
while [ -e /var/log/mysql.pipe ]
do
mysql -h $SYSLOG_HOST -u $SYSLOG_USER --password=$SYSLOG_PASSWD $SYSLOG_DB /dev/null
done

Na koniec pozostała rzecz najważniejsza czyli utworzenie bazy danych w MySQL. Oczywiscie wymaga zalogownia do bazy na prawach użytkownika, który może dodawać userów oraz tworzyć bazy.

CREATE DATABASE syslog;
USE syslog;
#
CREATE TABLE logs (
host varchar(32) default NULL,
facility varchar(10) default NULL,
priority varchar(10) default NULL,
level varchar(10) default NULL,
tag varchar(10) default NULL,
datetime datetime default NULL,
program varchar(15) default NULL,
msg text,
seq bigint(20) unsigned NOT NULL auto_increment,
PRIMARY KEY (seq), KEY host (host),
KEY program (program), KEY datetime (datetime),
KEY priority (priority), KEY facility (facility)
) TYPE=MyISAM;
#
CREATE TABLE users (
username varchar(32) default NULL,
pwhash char(40) default NULL,
sessionid char(32) default NULL,
exptime datetime default NULL,
PRIMARY KEY (username)
) TYPE=MyISAM;
#
CREATE TABLE search_cache (
tablename varchar(32) DEFAULT NULL,
type ENUM('HOST','FACILITY'),
value varchar(32) DEFAULT NULL,
updatetime datetime DEFAULT NULL,
INDEX type_name (type, tablename)
) TYPE=MyISAM;
#
CREATE TABLE user_access (
username varchar(32) DEFAULT NULL,
actionname varchar(32) DEFAULT NULL,
access ENUM('TRUE','FALSE'),
INDEX user_action (username, actionname)
) TYPE=MyISAM;
#
CREATE TABLE actions (
actionname varchar(32) NOT NULL,
actiondescr varchar(64) DEFAULT NULL,
defaultaccess ENUM('TRUE','FALSE'),
PRIMARY KEY (actionname)
) TYPE=MyISAM;
#
INSERT INTO actions (actionname, actiondescr, defaultaccess) VALUES ('add_user', 'Add users', 'TRUE');
INSERT INTO actions (actionname, actiondescr, defaultaccess) VALUES ('edit_user', 'Edit users (delete and change password)', 'TRUE');
INSERT INTO actions (actionname, actiondescr, defaultaccess) VALUES ('reload_cache', 'Reload search cache', 'TRUE');
INSERT INTO actions (actionname, actiondescr, defaultaccess) VALUES ('edit_acl', 'Edit access control settings', 'TRUE');
INSERT INTO users (username, pwhash) VALUES('admin', 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3');
#
USE mysql;
#
INSERT INTO user (Host, User, Password) VALUES ('localhost','sysloguser', password('NononoMamHaslo'));
INSERT INTO db (Host, Db, User) VALUES ('localhost','syslog','sysloguser');
INSERT INTO user (Host, User, Password) VALUES ('localhost','syslogfeeder', password('Haslo'));
INSERT INTO db (Host, Db, User) VALUES ('localhost','syslog','syslogfeeder');
INSERT INTO user (Host, User, Password) VALUES ('localhost','syslogadmin',password('OjejejJakieHaslo'));
INSERT INTO db (Host, Db, User) VALUES ('localhost','syslog','syslogadmin');
COMMIT;
FLUSH PRIVILEGES;
GRANT USAGE ON *.* TO syslogadmin@localhost;
GRANT ALL ON syslog.* TO syslogadmin@localhost;
GRANT RELOAD ON *.* TO syslogadmin@localhost;
REVOKE ALL PRIVILEGES ON syslog.* FROM sysloguser@localhost;
GRANT USAGE ON *.* TO sysloguser@localhost;
GRANT SELECT ON syslog.* TO sysloguser@localhost;
GRANT UPDATE ON syslog.users TO sysloguser@localhost;
REVOKE ALL PRIVILEGES ON syslog.* FROM syslogfeeder@localhost;
GRANT USAGE ON *.* TO syslogfeeder@localhost;
GRANT INSERT ON syslog.* TO syslogfeeder@localhost;
GRANT ALL ON syslog.search_cache TO sysloguser@localhost;
GRANT SELECT ON syslog.user_access TO sysloguser@localhost;
GRANT ALL ON syslog.user_access TO syslogadmin@localhost;
GRANT SELECT ON syslog.actions TO sysloguser@localhost;
GRANT ALL ON syslog.actions TO syslogadmin@localhost;
GRANT UPDATE ON syslog.users TO sysloguser@localhost;
GRANT INSERT ON syslog.search_cache TO sysloguser@localhost;
COMMIT;
FLUSH PRIVILEGES;

Słowo wyjaśnienia pojawiający się w INSERcie hast to umożliwiającą logowanie para login=”admin” passwd=”test”.
Aby całość działała poprawnie najpierw należy dodać bazę oraz użytkownika do MySQL, potem utworzyć potok i finalnie uruchomić syslog-ng. Konfigurację firewalla zupełnie pomijam.

Tym oto sposobem mamy prawie wszystko. Wszystko ponieważ brakuje panelu PHP :) Ale wystarczy zajrzeć tutaj.

ZOLTAN

P.S. Uwaga co ma logować do bazy, jeśli dodamy routery brzegowe bądź też firewalle to baza dziennie potrafi przyrastać o około 350 - 400 MB objętości, natomiast w kwestii loadu maszyny nie są to jakieś wielkie wartości. Reasumując dużo dysku, średnio ramu a CPU pomijalne.

5 Responses to “Centralny system składowania logów”

  1. 1 x
    maj 31st, 2007 at 4:18 pm

    Pojawia się pytanie dot. analizowania czy przeszukiwania takich logów pod kątem występujących w nich stringów - puszczenie LIKE ‘%costam%’ zabije serwer mysql.

  2. 2 daniel
    maj 31st, 2007 at 6:44 pm

    szczerze to nie

    testowane z wielkaaaa baza (wiecej niz 1.2 GB) na 2 GB RAM i Pentium 4 2.26 GHz HT przeszukiwanie adresu IP zwrocilo ponad 200k rekordow i trwalo to nieco ponad 17 sekund natomiast ta sama baza replikowana na serwerze w LAN 2 Opterony dual core i 2 GB ram mniej niz 3 sek wiec nie ma problemu.

  3. 3 Andrzej Dopierała
    czerwiec 3rd, 2007 at 2:38 pm

    Hm… baza 1.2gb na komputerze z 2gb ram oznacza ze się cała zmieściła do pamięci ;) Więc wyszukiwanie nie powinno być wolne.

    A co w momencie gdy logi osiagną kilkanaście/kilkadziesiąt gigabajtów?

    Kilka lat temu próbowaliśmy wdrożyć podobne rozwiązanie w jednym miejscu. Serwer logów to był jakiś pentium 1ghz z duużym(jak na owe czasy) dyskiem 80gb, do tego postgresql i do wrzucania msyslog (oferował bodajże bezpośrednią komunikację z sql-em). I generalnie wszystko było ok przy małej ilości logów. W sytuacji gdy wrzuciliśmy w to kilkanaście serwerów i kilkaset stacji roboczych - maszynka umierała przy samym logowaniu, o wyszukaniu czegokolwiek można było zapomnieć.
    Do tego pojawił się problem.. braku miejsca. dysk co prawda był duży, ale - nie z gumy. A kompresji w sql-u chyba jeszcze nie wynaleziono ;)

    Od tego czasu (z przerwami) funkcjonuje tam trochę inne rozwiązanie - serwer z zwykłym syslogiem, plus skrypty które w nocy “rozdzielają” logi na poszczególne serwery i kompresują je… A maszynka - jest nieco słabsza ;)

  4. 4 daniel
    czerwiec 4th, 2007 at 7:18 am

    Hmmm tutaj głównym celem jest nie tyle śledzenie na bieżąco ale cykliczna analiza i ewentualnie audyt więc nie wymagane jest wieczne przechowywanie logów.
    Zamysł był i jest aby przez okres 1-3 miesiące można bez problemu przeszukiwać bazę MySQL a co miesiąc wykonują się skrypty które odpowiednio eksportują historyczne dane do pliku , kompresują i docelowo na DVD / taśmę.
    Obliczyliśmy, że to takiego działania wystarczy około 80GB przeznaczone na bazę danych w DMZ.

    Jak wcześniej napisałem system sprawdza się od ponad miesiąca przy dość znaczącym obciążeniu.

    Myśle, że najistotniejsze jest rozdzielenie logiczne (wyszukiwanie/przeglądanie i insertowanie) na dwa fizyczne serwery.

  5. 5 wolvverine
    czerwiec 26th, 2008 at 12:51 pm

    dla logów w bazie postgresql jest dobry interface PhpLogCon http://www.phplogcon.com/

Leave a Reply