日志采集与标准化:从源头打好地基
日志采集这件事,说白了就是解决一个问题:数据怎么从各个系统里安全、完整地流到你的分析平台。我见过太多团队,安全分析做不好,根子不在工具不行,而是日志采集阶段就埋了坑。今天咱们就把这块掰开揉碎讲清楚。
日志采集架构:三种主流模式
采集架构没有银弹,得根据你的环境选。我个人习惯把采集方式分成三类:Agent、Syslog、API。咱们一个个看。
1. Agent 模式
在目标服务器上装一个轻量级程序,由它负责读取日志文件、过滤、转发。这是目前最灵活的方式。
- 优点:能处理复杂日志格式,支持多行日志合并,自带断网续传
- 缺点:每台机器都要装,运维成本高
- 适用场景:应用服务器、容器环境、需要结构化处理的场景
2. Syslog 模式
网络设备、Linux 系统原生支持的日志协议。配置简单,但功能有限。
- 优点:零部署,设备原生支持
- 缺点:UDP 传输可能丢包,格式单一,不支持结构化
- 适用场景:防火墙、路由器、交换机等网络设备
3. API 拉取模式
通过 REST API 或 SDK 从云服务、SaaS 平台拉取日志。比如 AWS CloudTrail、阿里云 ActionTrail。
- 优点:无需部署,按需拉取,权限管控清晰
- 缺点:有频率限制,实时性差,依赖厂商接口稳定性
- 适用场景:云环境、SaaS 应用、第三方服务
这三种模式不是互斥的。我建议你在实际项目中混合使用:服务器用 Agent,网络设备走 Syslog,云服务走 API。下面这张图能帮你理清整体架构:
日志标准化:为什么非做不可?
你想想看,防火墙的日志字段名叫 src_ip,Web 服务器的叫 client_ip,数据库的叫 source_address。如果不做标准化,写一条关联规则得查三个字段名,累不累?
标准化要解决三个核心问题:
- 字段名统一:所有日志用同一套字段命名规范
- 时间格式统一:全部转成 ISO 8601 带时区
- 事件类型统一:登录失败、权限变更、文件操作等有固定编码
三种主流标准格式
| 标准 | 全称 | 特点 | 适用场景 |
|---|---|---|---|
| CEF | Common Event Format | 键值对格式,ArcSight 推广,字段名固定 | SIEM 对接、安全设备日志 |
| LEEF | Log Event Extended Format | IBM 推广,支持自定义扩展字段 | QRadar 环境、IBM 生态 |
| JSON Schema | JSON Schema | 灵活、可嵌套、生态好 | 现代应用、云原生、ELK 栈 |
我的建议:新项目直接上 JSON Schema。CEF 和 LEEF 在传统 SIEM 里用得比较多,但 JSON 的灵活性和可扩展性明显更好。如果你要对接 ArcSight 或 QRadar,那就得按它们的格式来。
CEF 格式示例
CEF:0|Security|ThreatManager|1.0|100|Login Failed|5|src=10.0.0.1 dst=192.168.1.1 dhost=web01 msg=Invalid password
CEF 的格式是管道符分隔,前面是固定头,后面是键值对扩展。说实话,可读性一般,但解析效率高。
JSON Schema 示例
{
"event": {
"category": "authentication",
"type": "failure",
"outcome": "failed"
},
"source": {
"ip": "10.0.0.1",
"port": 54321
},
"destination": {
"hostname": "web01",
"ip": "192.168.1.1"
},
"message": "Invalid password for user admin"
}
JSON 的好处是嵌套结构清晰,字段可以随意扩展。我在做容器安全审计时,就喜欢用 JSON Schema,因为 Kubernetes 的日志天然就是 JSON 格式,直接映射过来就行。
常见采集工具:选型与实战
工具选型这事儿,没有最好只有最合适。我按自己的使用经验给你排个序:
1. Filebeat
Elastic 出品,轻量级采集器。Go 语言写的,资源占用极低。
- 优点:内存占用小(通常 10-20MB),配置简单,原生支持 Elasticsearch
- 缺点:处理能力有限,复杂转换需要配合 Logstash
- 我的用法:每台服务器装 Filebeat,只做采集和简单过滤,然后发给 Kafka 或 Logstash
2. Fluentd
CNCF 毕业项目,Ruby 写的,插件生态丰富。
- 优点:插件多(500+),路由灵活,支持多种输出
- 缺点:Ruby 性能不如 Go,内存占用偏高
- 我的用法:在 Kubernetes 里用 Fluentd 做 DaemonSet,采集容器日志
3. Logstash
ELK 栈的老大哥,Java 写的,功能最全。
- 优点:过滤能力强,支持 Grok 解析,插件丰富
- 缺点:吃内存(默认 1GB),启动慢
- 我的用法:作为集中处理层,做日志解析、标准化、富化
工具对比速查
| 特性 | Filebeat | Fluentd | Logstash |
|---|---|---|---|
| 语言 | Go | Ruby + C | Java |
| 内存占用 | 低(10-30MB) | 中(50-150MB) | 高(256MB-1GB) |
| 处理能力 | 简单过滤 | 中等 | 强 |
| 插件数量 | 30+ | 500+ | 200+ |
| 配置难度 | 简单 | 中等 | 复杂 |
| 推荐场景 | 边缘采集 | 容器/云原生 | 集中处理 |
标准化实战:一个完整的例子
假设我们要采集 Nginx 访问日志,原始格式是这样的:
192.168.1.10 - - [10/Oct/2023:13:55:36 +0000] "POST /api/login HTTP/1.1" 401 234 "-" "Mozilla/5.0"
用 Logstash 的 Grok 解析后,转成标准 JSON:
filter {
grok {
match => { "message" => "%{IP:source.ip} - - \[%{HTTPDATE:event.created}\] \"%{WORD:http.method} %{URIPATHPARAM:url.path} HTTP/%{NUMBER:http.version}\" %{NUMBER:http.response.status_code} %{NUMBER:http.response.bytes} \"%{DATA:http.request.referrer}\" \"%{DATA:user_agent.original}\"" }
}
date {
match => ["event.created", "dd/MMM/yyyy:HH:mm:ss Z"]
target => "@timestamp"
}
mutate {
rename => { "message" => "original_message" }
remove_field => ["event.created"]
}
}
标准化后的输出:
{
"@timestamp": "2023-10-10T13:55:36.000Z",
"source": { "ip": "192.168.1.10" },
"http": {
"method": "POST",
"response": { "status_code": 401, "bytes": 234 },
"request": { "referrer": "-" }
},
"url": { "path": "/api/login" },
"user_agent": { "original": "Mozilla/5.0" },
"event": { "category": "web", "type": "access" }
}
event.category 和 event.type 字段。这样后面写安全规则时,直接按 category 过滤,不用每条规则都写一堆 IP 和端口条件。
嗯,日志采集和标准化这块,说白了就是一句话:把脏活累活做在前面。采集架构选对了,标准化做好了,后面的安全分析才能事半功倍。我见过太多团队在分析阶段花大价钱买工具,结果发现日志字段对不上、时间戳不统一,最后还得回头补采集的坑。别走那条路。