sexta-feira, 23 de maio de 2008

Refinando os logs do Gentoo





From Gentoo Linux Wiki


As it is stated in the Gentoo Security Guide, syslog-ng provides some of the same features as syslog and metalog with a small difference. It can filter messages based on level and content (like metalog), provide remote logging like syslog, handle logs from syslogd (even streams from Solaris), write to a TTY, execute programs, and it can act as a logging server. Basically it is the best of both loggers combined with advanced configuration.










Quick Start


First, you have to emerge syslog-ng and add it to the default runlevel. If you want to start syslog-ng just now, execute the init script. Also, it is recomended to unmerge any system logger you have previously installed as loggers often use /dev/log (see this thread):


# emerge -av syslog-ng
# rc-update add syslog-ng default
# /etc/init.d/syslog-ng start

Also, you may want logrotate to rotate your logs


# emerge -av logrotate

For a quick start, here there is a classic configuration file slightly modified from Gentoo Security Guide.






File: /etc/syslog-ng/syslog-ng.conf




# /etc/syslog-ng/syslog-ng.conf
# From the Gentoo Linux Security Guide
# http://www.gentoo.org/doc/en/gentoo-security.xml
# Creative Commons - Attribution / Share Alike License
# http://creativecommons.org/licenses/by-sa/2.0

options { chain_hostnames(off); create_dirs (yes); sync(0); stats(43200); };

#source where to read log
source src { unix-stream("/dev/log"); internal(); };
source kernsrc { file("/proc/kmsg"); };

#define destinations
destination authlog { file("/var/log/auth.log"); };
destination syslog { file("/var/log/syslog"); };
destination cron { file("/var/log/cron.log"); };
destination daemon { file("/var/log/daemon.log"); };
destination kern { file("/var/log/kern.log"); };
destination lpr { file("/var/log/lpr.log"); };
destination user { file("/var/log/user.log"); };
# Should be maillog (Without dot) as it was the default on logwatch
destination mail { file("/var/log/maillog"); };

destination mailinfo { file("/var/log/mail.info"); };
destination mailwarn { file("/var/log/mail.warn"); };
destination mailerr { file("/var/log/mail.err"); };

destination newscrit { file("/var/log/news/news.crit"); };
destination newserr { file("/var/log/news/news.err"); };
destination newsnotice { file("/var/log/news/news.notice"); };

destination debug { file("/var/log/debug"); };
destination messages { file("/var/log/messages"); };
destination console { usertty("root"); };
destination console_all { file("/dev/tty12"); };
destination xconsole { pipe("/dev/xconsole"); };

#create filters
filter f_auth { facility(auth); };
filter f_authpriv { facility(auth, authpriv); };
filter f_syslog { not facility(authpriv, mail); };
filter f_cron { facility(cron); };
filter f_daemon { facility(daemon); };
filter f_kern { facility(kern); };
filter f_lpr { facility(lpr); };
filter f_mail { facility(mail); };
filter f_user { facility(user); };
filter f_debug { not facility(auth, authpriv, news, mail); };
filter f_messages { level(info..warn)
and not facility(auth, authpriv, mail, news); };
filter f_emergency { level(emerg); };

filter f_info { level(info); };
filter f_notice { level(notice); };
filter f_warn { level(warn); };
filter f_crit { level(crit); };
filter f_err { level(err); };
filter f_failed { match("failed"); };
filter f_denied { match("denied"); };

#connect filter and destination
log { source(src); filter(f_authpriv); destination(authlog); };
log { source(src); filter(f_syslog); destination(syslog); };
log { source(src); filter(f_cron); destination(cron); };
log { source(src); filter(f_daemon); destination(daemon); };
log { source(kernsrc); filter(f_kern); destination(kern); };
log { source(src); filter(f_lpr); destination(lpr); };
log { source(src); filter(f_mail); destination(mail); };
log { source(src); filter(f_user); destination(user); };
log { source(src); filter(f_mail); filter(f_info); destination(mailinfo); };
log { source(src); filter(f_mail); filter(f_warn); destination(mailwarn); };
log { source(src); filter(f_mail); filter(f_err); destination(mailerr); };

log { source(src); filter(f_debug); destination(debug); };
log { source(src); filter(f_messages); destination(messages); };
log { source(src); filter(f_emergency); destination(console); };

#default log
log { source(src); destination(console_all); };




You will see your defined log files in /var/log. In the following sections we will explain this configuration file in order to understand how syslog-ng works.


Sources


Syslog-ng receives log messages from a source. To define a source you should follow the following syntax:


source <identifier> { source-driver(params); source-driver(params); ... };


You can look at the identifiers and source-drivers in the manuals. This will follow the manual to explain the configuration file above.

The unix-stream() source-driver opens the given AF_UNIX socket and starts listening on it for messages. The internal() source-driver gets messages generated by syslog-ng.
Therefore,


source src { unix-stream("/dev/log"); internal(); };

Means: src gets messages from /dev/log socket and syslog-ng.

The kernel sends log messages to /proc/kmsg and the file() driver reads log messages from files. Therefore:


source kernsrc { file("/proc/kmsg"); };

Means: kernsrc gets messages from file /proc/kmsg

In the default configuration file after emerging syslog-ng, the source is defined as:


source src { unix-stream("/dev/log"); internal(); pipe("/proc/kmsg"); };

Reading messages by pipe("/proc/kmsg") gives a better performance but because it opens its argument in read-write mode can be a security hazard as the syslog-ng admin guide states in section 7.1.6:


Pipe is very similar to the file() driver, but there are a few
differences, for example pipe() opens its argument in read-write
mode, therefore it is not recommended to be used on special files
like /proc/kmsg." (You can follow this discussion in this post.)

Destinations



syslog-ng sends log messages to files. The syntax is very similar to sources:


destination <identifier> {destination-driver(params); destination-driver(params); ... };

You will be normally logging to a file, but you could log to a different destination-driver: pipe, unix socket, TCP-UDP ports, terminals or to specific programs. Therefore:


destination authlog { file("/var/log/auth.log"); };

Means sent authlog messages to /var/log/auth.log

usertty() sends messages to the terminal of the specified user, if the user is logged in. Then:


destination console { usertty("root"); };

Sends console messages to root's terminal if it is logged in.

pipe() sends messages to a pipe /dev/xconsole. Then:


destination xconsole { pipe("/dev/xconsole"); };

Sends xconsole messages to the pipe /dev/xconsole. This needs some more configuration, so you could look at the sub-section xconsole below.

udb() sends on the network


destination remote_server { udp("10.0.0.2" port(514)); };

this will send your log data out to a another server


xconsole



ATTENTION: this part is not yet finished.
You can look and contribute at this thread discussing the topic,
and have a look at this explanation
.

syslog-ng can send messages to the pipe /dev/xconsole. You should create it with mkfifo, giving the appropriate access and owner permissions:


# mkfifo /dev/xconsole
# chmod 644 /dev/xconsole
# chown root.tty /dev/xconsole

Afterwards, you need a program to read the messages sent to /dev/xconsole. xconsole is a console that monitors system messages with X. Frist step is to emerge xconsole:


emerge -av xconsole

And tell xconsole to read /dev/xconsole



# xconsole -file /dev/xconsole

You can modify the text window space editing /usr/share/X11/app-defaults/XConsole:


*text.width: 900
*text.height: 100

And the geometry:


xconsole -file /dev/xconsole -geometry +67+640

Creating Filters for Messages



Syntax for the filter statement:


filter <identifier> { expression; };

Functions can be used in the expression, such as the fuction facility() which selects messages based on the facility codes (look at the sub-section below for a list of facility codes). Therefore, the filter


filter f_auth { facility(auth); };

filters those messages coming from authorisation, like:


May 11 23:42:31 mimosinnet su(pam_unix)[18569]: session opened for user root by (uid=1000)


Expression can use the boolean operators and, or, not, so the filter:


filter f_debug { not facility(auth, authpriv, news, mail); };

selects those messages not coming from authorisation, network news or mail.

The funciont level() selects messages based on its priority level, therefore:


filter f_info { level(info); };

selects informational levels.

Functions and boolean operators can be combined in more complex expressions like:


filter f_messages { level(info..warn)
and not facility(auth, authpriv, mail, news); };

that filters messages with a priority level from informational to warning not coming from atuh, authpriv, mail and news facilities.

Messages can also be selected by matching a regular expression in the message with the function match(regexp). For example:


filter f_failed { match("failed"); };

Facilities and log-levels


The linux kernel has a few facilities you can use for logging. Each facility has a log-level; where debug is the most verbose, and panic only shows serious errors. You can find the facilities, log levels and priority names in /usr/include/sys/syslog.h:






File: /usr/include/sys/syslog.h




/* facility codes */
#define LOG_KERN (0<<3) /* kernel messages */
#define LOG_USER (1<<3) /* random user-level messages */
#define LOG_MAIL (2<<3) /* mail system */
#define LOG_DAEMON (3<<3) /* system daemons */
#define LOG_AUTH (4<<3) /* security/authorization messages */
#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
#define LOG_LPR (6<<3) /* line printer subsystem */
#define LOG_NEWS (7<<3) /* network news subsystem */
#define LOG_UUCP (8<<3) /* UUCP subsystem */
#define LOG_CRON (9<<3) /* clock daemon */
#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
#define LOG_FTP (11<<3) /* ftp daemon */
/* other codes through 15 reserved for system use */
#define LOG_LOCAL0 (16<<3) /* reserved for local use */
#define LOG_LOCAL1 (17<<3) /* reserved for local use */
#define LOG_LOCAL2 (18<<3) /* reserved for local use */
#define LOG_LOCAL3 (19<<3) /* reserved for local use */
#define LOG_LOCAL4 (20<<3) /* reserved for local use */
#define LOG_LOCAL5 (21<<3) /* reserved for local use */
#define LOG_LOCAL6 (22<<3) /* reserved for local use */
#define LOG_LOCAL7 (23<<3) /* reserved for local use */

#ifdef SYSLOG_NAMES
CODE facilitynames[] =
{
{ "auth", LOG_AUTH },
{ "authpriv", LOG_AUTHPRIV },
{ "cron", LOG_CRON },
{ "daemon", LOG_DAEMON },
{ "ftp", LOG_FTP },
{ "kern", LOG_KERN },
{ "lpr", LOG_LPR },
{ "mail", LOG_MAIL },
{ "mark", INTERNAL_MARK }, /* INTERNAL */
{ "news", LOG_NEWS },
{ "security", LOG_AUTH }, /* DEPRECATED */
{ "syslog", LOG_SYSLOG },
{ "user", LOG_USER },
{ "uucp", LOG_UUCP },
{ "local0", LOG_LOCAL0 },
{ "local1", LOG_LOCAL1 },
{ "local2", LOG_LOCAL2 },
{ "local3", LOG_LOCAL3 },
{ "local4", LOG_LOCAL4 },
{ "local5", LOG_LOCAL5 },
{ "local6", LOG_LOCAL6 },
{ "local7", LOG_LOCAL7 },

* priorities (these are ordered)
*/
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */

CODE prioritynames[] =
{
{ "alert", LOG_ALERT },
{ "crit", LOG_CRIT },
{ "debug", LOG_DEBUG },
{ "emerg", LOG_EMERG },
{ "err", LOG_ERR },
{ "error", LOG_ERR }, /* DEPRECATED */
{ "info", LOG_INFO },
{ "none", INTERNAL_NOPRI }, /* INTERNAL */
{ "notice", LOG_NOTICE },
{ "panic", LOG_EMERG }, /* DEPRECATED */
{ "warn", LOG_WARNING }, /* DEPRECATED */
{ "warning", LOG_WARNING },




Log Paths


syslog-ng connects sources, filters and destinations with log statements. The syntax is:


log {source(s1); source(s2); ...
filter(f1); filter(f2); ...
destination(d1); destination(d2); ...
flags(flag1[, flag2...]); };

For example:


log { source(src); filter(f_mail); filter(f_info); destination(mailinfo); };


Sends messages from 'src' source to 'mailinfo' destination filtered by 'f_info' filter.


Tips and Tricks


After understanding the logic behind syslog-ng, many possible and complex configuration are possible. Here there are some examples.


[edit] Move log to another file



in order to move some log from messages to another file:


#sshd configuration
destination ssh { file("/var/log/ssh.log"); };
filter f_ssh { program("sshd"); };
log { source(src); filter(f_ssh); destination(ssh); };

Configuring as a loghost


Configuring your system to be a loghost is quite simple.
Drop the following into your configuration, and create the needed directory.






File: /etc/syslog-ng/syslog-ng.conf




source net { udp(); };
destination remote { file("/var/log/remote/$FULLHOST"); };
log { source(net); destination(remote); };



With this simple configuration, log filenames will be based on the FQDN of the remote host, and located in; /var/log/remote/

After creating the remote directory, reload your syslog-ng.configuration.


Use pipe("/proc/kmsg") or file("/proc/kmsg")



In the default configuration file after emerging syslog-ng, the source is defined as:


source src { unix-stream("/dev/log"); internal(); pipe("/proc/kmsg"); };

It is not clear if we should use pipe("/proc/kmsg") or file("/proc/kmsg")- As the syslog-ng admin guide states in section 7.1.6:


Pipe is very similar to the file() driver, but there are a few
differences, for example pipe() opens its argument in read-write
mode, therefore it is not recommended to be used on special files
like /proc/kmsg."

(You can follow this discussion in this post.


Improve Performance



syslog performance can be improved in different ways:


Avoid redundant processing and disk space with flag(final)


A single log message can be sent to different log files several times. For example, in the initial configuration file, we have the following definitions:


destination cron { file("/var/log/cron.log"); };
destination messages { file("/var/log/messages"); };
filter f_cron { facility(cron); };
filter f_messages { level(info..warn)
and not facility(auth, authpriv, mail, news); };
log { source(src); filter(f_cron); destination(cron); };
log { source(src); filter(f_messages); destination(messages); };

The same message from the 'cron' facility will end up in both the cron.log and messages file. To change this behavior we can use the final flag, ending up further processing with the message. Therefore, in this example, if we want messages from the 'cron' facility not ending up in the messages file, we should change the cron's log sentence by:


log { source(src); filter(f_cron); destination(cron); flags(final); };

Postgresql Destination


Some of this information was obtained from http://www.kdough.net/docs/syslog_postgresql/.

Please note that this is a work in progress. For one, psql never gets killed when you restart syslog-ng. I just got this going today, so I haven't had a chance to look into it. For another, there are security implications.

Also, I'm still debating with myself whether there's really value in putting syslog logs into an RDBM.


[edit] syslog-ng-pgsql-pipe.sh



The following file can reside in /usr/local/sbin/syslog-ng-pgsql-pipe.sh


#!/bin/bash
#
# File: syslog-ng-pgsql-pipe.sh
#
# Take input from a FIFO and run execute it as a query for
# a PostgreSQL database.
#
# IMPORTANT NOTE: This could potentially be a huge security hole.
# You should change permissions on the FIFO accordingly.
#

ERROR_CODE=0

if [ -e /var/run/syslog-ng.pgsql.pipe ]; then
while [ -e /var/run/syslog-ng.pgsql.pipe ] && [ "$ERROR_CODE" -ne "143" ]
do
psql -q -h localhost -U syslog syslog < /var/run/syslog-ng.pgsql.pipe
/usr/local/bin/syslog-ng-parse.awk < /var/run/syslog-ng.pgsql.pipe
done
else
mkfifo /var/run/syslog-ng.pgsql.pipe
fi

syslog-ng.conf



#
# SQL logging support
#
destination d_pgsql {
pipe("/var/run/syslog-ng.pgsql.pipe"
template("INSERT INTO logs (host, facility, priority, level, tag, date,
time, program, msg) VALUES ( '$HOST', '$FACILITY', '$PRIORITY', '$LEVEL', '$TAG',
'$YEAR-$MONTH-$DAY', '$HOUR:$MIN:$SEC', '$PROGRAM', '$MSG' );\n"
)
template-escape(yes)
);
};
# make a filter if you like
# filter postfix {program ("postfix");};
log { source(src); destination(d_pgsql); };

syslog-ng (init.d)


I still can't figure out how to make the psql process die, during a stop or a restart of syslog-ng. pidof returns nothing, when run inside the syslog-ng init script. And using --make-pidfile of start-stop-daemon is almost useless, because it only kills the shell script that start psql, not psql itself.



start()


+ start-stop-daemon --start --background --quiet --exec /usr/local/sbin/syslog-ng-pgsql-pipe.sh
+ echo `pidof psql` > /var/run/syslog-ng-pgsql-pipe.pid
start-stop-daemon --start --quiet --exec /usr/sbin/syslog-ng ${SYSLOG_NG_OPTS}

[edit] stop()



  start-stop-daemon --stop --quiet --pidfile /var/run/syslog-ng.pid
+ start-stop-daemon --stop --quiet --pidfile /var/run/syslog-ng-pgsql-pipe.pid

PostgreSQL


In order for this to work, you're going to need a TRUST rule in pg_hba.conf, or a password, for the syslog user. There's obviously security implications for this, if you're using a TRUST rule. Although INSERTS into syslog will be possible, reads/modifications of existing log entries will not be. If you use a password, you may be able to restrict the init script to root access only. I'm not sure if that will work though. I'll have to try it. :) Alternatively, you can use the ~/.pgpass file to supply the credentials. See the reference, http://www.postgresql.org/docs/current/interactive/libpq-pgpass.html

~/.pgpass


hostname:port:database:username:password


su - postgres
createdb syslog
psql -h localhost -U postgres syslog
CREATE USER syslog WITH PASSWORD 'syslogXXXXXXX';
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,
date date default NULL,
time time default NULL,
program varchar(15) default NULL,
msg text,
seq serial,
PRIMARY KEY (seq)
);
GRANT INSERT ON logs TO syslog; # security so people can't update the logs

[edit] Links





























Nenhum comentário: