在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路径,部分老版本路径可能不同,但整体逻辑完全一致。