三、日志收集机制:Syslog、文件采集、API采集
日志收集是整个审计链路的第一公里。数据进不来,后面再花哨的分析、关联都是空中楼阁。我在多个企业的审计平台搭建中踩过不少坑,今天就把三种主流收集方式——Syslog、文件采集、API采集掰开揉碎了讲清楚。
3.1 Syslog:最经典的日志运输协议
Syslog 从 Unix 时代就开始服役,直到今天它依然是网络设备、Linux 系统的默认日志出口。说白了,它就是一个「发完就走」的 UDP/TCP 协议,发送端不管接收端有没有收到。
核心工作流:
日志产生 → 本地 syslogd/rsyslog → 按照 facility + severity 分类 → 发送到远端 Syslog 服务器 → 服务器写入文件或转存。
我这里给一个典型的 rsyslog 配置片段:
# 将所有 auth 设施的日志发送到 192.168.1.100:514
auth.* @192.168.1.100:514
# 将 mail 设施的警告及以上级别日志发送到日志服务器
mail.warn @192.168.1.100:514
# 本地保留一份完整副本
*.info /var/log/messages
你可能会问:UDP 丢包怎么办?嗯,我的建议是:核心审计日志必须走 TCP。我曾经在一个金融项目中,默认用 UDP 收网络防火墙日志,结果高峰期丢掉了将近 15% 的会话日志,最后排查了三天才发现是接收端队列溢出。改成 TCP + 本地缓冲后才稳定下来。
| 特性 | UDP 模式 | TCP 模式 |
|---|---|---|
| 传输可靠性 | 低,可能丢包 | 高,有重传机制 |
| 性能开销 | 极小 | 稍高(建立连接) |
| 适用场景 | 非关键日志、内部网络 | 审计敏感日志、跨网络传输 |
| 推荐 | 监控类日志 | 必选 |
我曾经遇到过一个典型案例:服务器 rsyslog 默认使用 514 端口,但内部安全团队封锁了所有非标准端口,导致日志丢失。解决办法:改用 10514 等高位端口,并在接收端做好 SELinux 放行策略。
3.2 文件采集:直接啃原始日志文件
很多应用不会自己发 Syslog,它们只写本地文件。比如 Nginx access_log、Java 应用的 log4j 输出、数据库的 error log。这时候就需要 Agent 去「盯」着文件,一旦有新增内容就采集走。
文件采集的核心技术就是 inotify / ReadDirectoryChangesW + offset 记录。我项目中用 Filebeat 比较多,它的原理是:
- 轮询文件系统变更事件
- 读取新追加的内容
- 记录读取到的偏移量(registry)
- 断线重连后从上次位置继续读
生产环境一定要开启
close_inactive 和 clean_inactive 参数,否则长时间不活跃的日志文件句柄会堆积。我曾经在一个日处理 2TB 日志的系统上,没配这些参数,Filebeat 内存飙到 8GB,差点 OOM。
Filebeat 采集 nginx 日志的一个标准配置:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log*
fields:
log_type: nginx_access
multiline:
pattern: '^\d{4}-\d{2}'
negate: true
match: after
output.elasticsearch:
hosts: ["192.168.1.200:9200"]
index: "nginx-%{+yyyy.MM.dd}"
注意那个 multiline 块——我见过太多人踩坑了。Java 异常堆栈是多行的,如果不做 multiline 合并,一条异常会被切成十几条独立的日志,审计关联根本没法做。
3.3 API 采集:主动拉取云端与 SaaS 日志
现在越来越多系统跑在云上或 SaaS 平台上——AWS CloudTrail、Azure 活动日志、GitHub Audit Log、Okta 用户事件。这些东西你没法装 Agent,也不能让它们发 Syslog。唯一的办法就是用它们提供的 Rest API 去拉。
API 采集的通用流程:
- 认证( / OAuth2 / JWT)
- 分页拉取(大多数 API 单次返回 100-1000 条)
- 去重与顺序保证(按时间戳排序,避免重复拉取)
- 本地落盘或直接推送到消息队列
我团队维护的一个 AWS CloudTrail 采集脚本核心部分:
import boto3, time, json
from datetime import datetime, timedelta
client = boto3.client('cloudtrail')
start = datetime.utcnow() - timedelta(minutes=5)
response = client.lookup_events(
StartTime=start,
MaxResults=50
)
events = response.get('Events', [])
# 排序保证时间顺序
events.sort(key=lambda e: e['EventTime'])
for e in events:
# 写入本地队列文件
with open('/data/raw/cloudtrail.json', 'a') as f:
f.write(json.dumps(e, default=str) + '\n')
你想想看,这里最大的风险是什么?API 限流和网络抖动。我曾经在拉取 GitHub Audit Log 时,因为并发请求数没控制好,被 Github 封了 IP 15 分钟。后来我加上指数退避重试,并把拉取间隔统一调整为 10 秒。
3.4 三种方式对比矩阵
| 维度 | Syslog | 文件采集 | API 采集 |
|---|---|---|---|
| 适用系统 | 网络设备、Linux 基础服务 | 应用日志、数据库日志 | SaaS、云平台 |
| 部署难度 | 低(配置即可) | 中(需要安装 Agent) | 中高(开发脚本) |
| 数据实时性 | 秒级 | 近实时(秒级) | 分钟级(取决于轮询间隔) |
| 安全性 | 明文传输,需加密 | 本地文件权限控制 | HTTPS + 令牌 |
| 抗丢失能力 | 依赖 TCP/缓冲 | 强(offset 持久化) | 强(可重拉) |
| 典型工具 | rsyslog, syslog-ng, Logstash | Filebeat, Fluentd, Logstash | 自定义脚本, Lambda |
3.5 统一收口:边界关联的第一步
无论你用哪种方式采集,最终所有日志必须汇聚到一个统一的缓冲区里。我个人推荐使用 Kafka 作为中心缓冲层,它天然具备削峰填谷、持久化、多消费组等特性。说白了,三种采集方式就像三条进水管,Kafka 就是那个大水池,下游的分析引擎再从水池里抽水。
核心原则:采集层只做「搬运」,不做格式清洗、不做字段映射、不做告警计算。保持原始日志的「新鲜度」和「完整性」,把复杂加工留给下游流处理引擎。
下面这张图能帮你直观理解三种收集方式如何从不同源头汇入统一平台:
讲到这里,你应该已经清楚三种采集方式各自的定位了。Syslog 适合基础设施设备,文件采集适合应用本地日志,API 采集适合云端场景。没有银弹,根据数据源的类型选择合适的采集方式,然后统一收到 Kafka,这才是可持续的审计日志架构。