在Debian服务器上部署syslog-ng作为日志收集中枢时,最让人头疼的往往不是初始安装,而是如何从海量日志中精准捞出真正有价值的安全事件,并高效地送到SIEM平台。很多运维习惯用rsyslog,但面对复杂的过滤逻辑、百万级日志吞吐以及需要结构化输出的场景,syslog-ng的管道机制和解析能力优势非常明显。这里直接讲具体的配置思路和落地细节,不绕弯子。
明确需要捕获的安全事件类型动手配置前,必须先把安全事件的范围定死。常见的Linux安全事件包括SSH暴力破解失败、sudo提权操作、用户账号增删、关键文件完整性变更、防火墙丢弃的可疑连接、内核OOM或段错误等。以Debian为例,这些日志分散在/var/log/auth.log、/var/log/syslog、/var/log/kern.log以及auditd的审计日志中。syslog-ng要做的就是从这些来源里,用过滤器把符合规则的行提取出来,丢弃噪音,只把安全事件推送到SIEM。不要试图把所有日志都扔过去,那样成本高且SIEM端处理压力大,毫无意义。
syslog-ng源配置:统一接入所有日志流在/etc/syslog-ng/syslog-ng.conf中,首先定义source。Debian系统默认的syslog-ng已经包含了system()源,它自动读取/dev/log、/proc/kmsg等。但为了更细粒度控制,建议显式声明多个source,比如:
source s_sys {
system();
};
source s_auth {
file("/var/log/auth.log");
};
source s_kern {
file("/var/log/kern.log");
};
source s_audit {
file("/var/log/audit/audit.log");
};
这样做的好处是后续可以为不同来源分配不同的过滤器和解析器,逻辑清晰。如果服务器上有容器或应用自定义日志,同样用file()源引入,并加上follow-freq(1)和flags(no-parse)来确保实时读取和避免提前解析破坏原始格式。
解析器与消息结构化:用patterndb和parser拆出字段直接转发原始syslog文本到SIEM,对方很难做关联分析。syslog-ng的强项在于可以在本地完成消息解析,把非结构化的日志变成键值对。例如SSH登录失败日志长这样:
Apr 7 10:23:45 debian sshd[1234]: Failed password for root from 192.168.1.100 port 22 ssh2
可以写一个简单的csv-parser或者用内置的patterndb。对于SSH事件,syslog-ng已经自带了sshd的patterndb规则,位于/usr/share/syslog-ng/include/patterndb.d/sshd.pdb,只需要在配置中引用即可:
parser p_sshd {
db-parser(
file("/usr/share/syslog-ng/include/patterndb.d/sshd.pdb")
);
};
应用这个解析器后,消息会被自动提取出.ssh.auth_method、.ssh.client_ip、.ssh.username等字段。对于自定义应用日志,可以使用regexp-parser或json-parser。比如某个应用输出JSON格式日志,直接:
parser p_app_json {
json-parser(prefix(".app."));
};
结构化后的数据在转发时能极大提升SIEM的解析效率和告警准确度。
过滤器编写:精准提取安全事件过滤器是核心。syslog-ng支持多种过滤方式:facility、level、message内容匹配、以及基于解析后字段的过滤。以SSH暴力破解为例,需要过滤出所有“Failed password”消息,但排除掉那些仅仅是连接关闭的无害日志:
filter f_ssh_failed {
match("Failed password" value("MESSAGE"))
and not match("Connection closed" value("MESSAGE"));
};
更精确的做法是利用解析后的字段:
filter f_ssh_failed {
match("failed" value(".ssh.auth_status") type("string"));
};
对于sudo提权操作,关注/var/log/auth.log中包含“COMMAND”的行:
filter f_sudo_cmd {
match("COMMAND" value("MESSAGE"))
and facility(auth);
};
用户账号变更(useradd、usermod、userdel)通常也在auth.log中,可以用:
filter f_account_change {
match("useradd|usermod|userdel|groupadd" value("MESSAGE"))
and facility(auth);
};
内核级安全事件如OOM killer、segfault,从kern.log中抓取:
filter f_kern_oom {
match("Out of memory" value("MESSAGE"))
or match("segfault" value("MESSAGE"));
};
防火墙日志如果由iptables输出到syslog,通常包含“DROP”或“IN=”、“OUT=”等特征,直接匹配即可。把这些过滤器组合起来,可以形成一个综合的安全事件过滤器:
filter f_security_events {
filter(f_ssh_failed)
or filter(f_sudo_cmd)
or filter(f_account_change)
or filter(f_kern_oom);
};
注意syslog-ng中filter是惰性求值,用or连接时一旦匹配就停止后续检查,性能很好。
日志重写与字段标准化在转发前,可能需要对消息做微调。比如某些SIEM要求事件类型字段必须统一命名,或者需要添加静态标签标明日志来源主机角色。用rewrite规则可以轻松完成:
rewrite r_set_event_type {
set("SSH_FAILED_LOGIN" value(".event_type")
condition(match("Failed password" value("MESSAGE"))));
set("SUDO_EXEC" value(".event_type")
condition(match("COMMAND" value("MESSAGE"))));
set("ACCOUNT_CHANGE" value(".event_type")
condition(match("useradd|usermod|userdel" value("MESSAGE"))));
};
还可以添加静态标签,比如标识这台Debian服务器的角色:
rewrite r_add_tags {
set-tag("production");
set-tag("debian-server");
set("web-server" value(".host_role"));
};
这些标签和字段在SIEM中可以直接用来做分类和路由。
转发至SIEM:使用syslog或直接TCP/JSON输出syslog-ng支持多种输出驱动。最传统的是syslog()驱动,将日志以RFC5424格式发送到SIEM的syslog接收端口:
destination d_siem_syslog {
syslog("192.168.10.50"
transport("tcp")
port(514)
template("$(format-json --scope rfc5424 --scope dot-nv-pairs)
"));
};
这里使用了format-json模板,把消息和所有解析出的字段打包成JSON,比纯文本syslog包含更多信息。很多现代SIEM(如Splunk、Elastic、QRadar)都支持直接接收JSON格式的syslog,或者通过HEC、Beats等接口。如果SIEM提供HTTP接口,可以用http()驱动:
destination d_siem_http {
http(
url("http://siem-collector:8088/services/collector/event")
method("POST")
user-agent("syslog-ng")
headers("Authorization: Splunk ")
body("$(format-json --scope rfc5424 --scope dot-nv-pairs)")
);
};
对于需要高吞吐低延迟的场景,建议使用tcp()驱动并配合json-parser在SIEM端直接解析,避免多层syslog封装带来的开销。配置时务必开启tls和证书验证,安全事件日志在网络上明文传输是严重风险。Debian上需要先安装ca-certificates,并在destination中指定tls选项:
destination d_siem_tls {
network("siem.example.com"
port(6514)
transport("tls")
tls(
ca-file("/etc/ssl/certs/ca-certificates.crt")
cert-file("/etc/syslog-ng/cert/client-cert.pem")
key-file("/etc/syslog-ng/cert/client-key.pem")
)
template("$(format-json --scope rfc5424 --scope dot-nv-pairs)")
);
};
日志流组合与最终管道
把source、filter、parser、rewrite和destination串联成log语句:
log {
source(s_sys);
source(s_auth);
source(s_kern);
source(s_audit);
parser(p_sshd);
parser(p_app_json);
filter(f_security_events);
rewrite(r_set_event_type);
rewrite(r_add_tags);
destination(d_siem_tls);
flags(flow-control);
};
flags(flow-control)很重要,它启用背压机制,当SIEM端处理不过来时,syslog-ng会暂停读取日志而不是丢数据。对于安全事件,完整性优先于实时性。
性能调优与日志轮转配合Debian上syslog-ng的默认配置比较保守。如果日志量很大,需要调整几个参数。在syslog-ng.conf的options部分:
options {
chain_hostnames(no);
keep_hostname(yes);
flush_lines(100);
flush_timeout(1000);
log_fifo_size(10000);
log_msg_size(65536);
stats_freq(600);
time_reopen(10);
};
flush_lines和flush_timeout控制批量发送,减少网络往返。log_fifo_size增大缓冲区应对突发流量。log_msg_size设大一些避免长日志被截断,特别是JSON格式输出时。同时要确保/var/log目录所在磁盘IO和空间充足,logrotate配置要合理,避免syslog-ng持有已轮转文件的句柄导致磁盘不释放。可以在logrotate的postrotate脚本中加一句:
/bin/kill -HUP `cat /var/run/syslog-ng.pid 2>/dev/null` 2> /dev/null || true
让syslog-ng重新打开文件。
监控与验证配置完成后,先用syslog-ng -s检查语法,然后systemctl restart syslog-ng。验证过滤器是否生效,可以用logger命令模拟安全事件:
logger -p auth.info "Failed password for root from 10.0.0.1 port 22 ssh2"
然后在SIEM端查看是否收到JSON格式的事件,字段是否完整。syslog-ng自身也提供统计信息,通过syslog-ng-ctl stats可以查看各source、destination的处理量和丢弃量,帮助判断过滤器是否过于宽松或严格。如果发现某些安全事件没抓到,检查/var/log/syslog中syslog-ng自身的错误日志,通常能定位到解析器或网络连接问题。
高级场景:关联分析与上下文补充单纯转发单条日志往往不足以支撑SIEM的精确告警。可以在syslog-ng端做简单的上下文补充。例如SSH暴力破解通常伴随同一源IP多次失败,可以用grouping-by解析器统计时间窗口内的失败次数,当超过阈值时生成一条聚合事件:
parser p_ssh_brute {
grouping-by(
key(".ssh.client_ip")
aggregate(
value("count" type("int"))
value("last_username" value(".ssh.username"))
)
timeout(60)
trigger(
condition(match("count > 5" value("count")))
)
);
};
这样SIEM收到的就不是零散的失败日志,而是一条“IP x.x.x.x在60秒内失败6次”的聚合告警,极大降低噪音。这种就地聚合的思路在分布式日志架构中非常有效,能减少SIEM的存储和计算压力。
整个方案的核心在于:用syslog-ng的解析能力在日志产生端就完成数据清洗和结构化,只把高价值的安全事件以机器可读的格式加密传输到SIEM。Debian作为服务器系统的稳定性加上syslog-ng的灵活管道,可以构建一套非常可靠的安全事件管道,而且完全开源,没有许可成本。实际部署时,记得根据自身Debian版本调整patterndb路径,部分老版本路径可能不同,但整体逻辑完全一致。
