日志格式与标准:Syslog、JSON、CEF 在 PKI 中的应用
咱们做 PKI 日志监控,第一个要面对的难题就是日志格式。我不夸张地说,格式不统一,后面一切仪表盘都是白搭。你想想看,CA 签发证书、OCSP 响应、CRL 更新,不同厂商、不同组件出来的日志长得完全不一样。我刚开始搭建 ELK 那会儿,就吃过这个亏——硬生生花了三天才把混乱的格式梳理干净。
这一章我们就来拆解三种最主流的日志格式:Syslog、JSON、CEF。我会结合 PKI 场景,告诉你每种格式适合什么、坑在哪里、怎么在 Logstash 里把它们吃进去。
4.1 三种格式的家族谱系
先给一张全景图,看清楚它们各自的位置和关系。
4.2 Syslog 格式 —— PKI 系统的“通用语言”
Syslog 是历史最悠久的日志协议,也是目前 CA 设备、Linux 服务器默认输出的格式。我记得第一次对接一家金融客户的 ADCS(Active Directory Certificate Services),发现它发的就是 Syslog,但消息体里夹杂着 Windows EventLog 的糟粕——嗯,要额外清洗。
Syslog 的核心结构如下:
<PRI>VERSION TIMESTAMP HOSTNAME APPNAME PROCID MSGID [STRUCTURED-DATA] MSG
例子(CA 证书颁发事件):
<14>1 2025-03-12T14:32:17.128Z ca01.ad.corp lsass 4567 - [msEventLog severity=4 provider="Microsoft-Windows-ActiveDirectory_CertificateServices"] Certificate issued: serial=0xAB123456, subject=CN=node1.corp, SHA1=ABCDEF...
这里 PRI 的值(14)代表 facility=1(user-level)和 severity=6(informational)。我在项目中经常遇到有人忘记配置结构化数据(STRUCTURED-DATA),导致后面 Logstash 解析时丢失关键字段。注意!PKI 的证书序列号、主题、指纹最好都放在结构化数据里,不然提取会很痛苦。
rfc5424 头选项。我在一个跨国项目中,因为用了老旧的 RFC 3164 格式(BSD style),解析时的时间戳没有时区,差点把事件时间全搞错。
4.3 JSON 格式 —— ELK 的“亲儿子”
JSON 不用多说,Elasticsearch 本身就用 JSON 序列化。如果你能控制 PKI 系统的应用层输出,我强烈建议直接输出 JSON。你想想看,Logstash 的 json 过滤器一上,字段自动映射,省掉无数 grok 正则的痛苦。
一个典型的 PKI JSON 日志长这样:
{
"timestamp": "2025-03-12T14:32:17.128Z",
"event": "certificate_issued",
"ca": "ca01.ad.corp",
"serial": "0xAB123456",
"subject": {
"CN": "node1.corp",
"O": "Acme Corp",
"C": "CN"
},
"fingerprint": {
"sha1": "ABCDEF1234567890",
"sha256": "1111222233334444"
},
"validity": {
"not_before": "2025-03-12T00:00:00Z",
"not_after": "2026-03-12T00:00:00Z"
},
"client_ip": "10.0.1.100"
}
subject.CN、subject.O 这样一级对象就够了。
JSON 还有一个好处,可以携带 @version 和 tags 元字段,方便 Logstash 做分支处理。
4.4 CEF 格式 —— 安全运营的“国际语言”
CEF(Common Event Format)是 ArcSight 定义的标准化日志格式,很多安全设备和 PKI 网关(比如 SSL 解密设备、OCSP 代理)都会输出 CEF。说白了这个格式的好处是:字段命名统一,不同厂商的设备之间可以直接关联。比如你用 CEF 格式的证书吊销日志,可以直接跟防火墙的 SSL 握手日志做 timeline 关联。
CEF 的标准结构:
CEF:0|Vendor|Device|Version|SignatureID|Name|Severity|Extension
例子(OCSP 请求被拒绝):
CEF:0|OpenXPKI|OCSP|2.0|1003|Certificate revocation check|5|src=192.168.1.1 spt=443 act=denied reason=certificate_revoked cs1=0xDEADBEEF cs1Label=serialNumber
| CEF 字段 | 含义 | PKI 使用建议 |
|---|---|---|
| SignatureID | 事件编号(唯一标识事件类型) | 1000~1999 建议分配给证书签发相关 |
| Name | 事件名称 | 用英文简洁词组,如 "Certificate Issued" |
| Severity | 严重等级 (0-10) | 证书吊销建议 8 以上,普通查询 1-3 |
| Extension | 扩展字段(key=value 对,空格分隔) | 常用 cs1~cs6 存放证书序列号、主题等 |
cs1=CN=server1, O=My Corp,Logstash 解析到 “My Corp” 时直接断开,后面全丢了。正确的写法是 cs1=CN=server1\,\ O=My\ Corp。
4.5 在 Logstash 中如何选择解析策略
说了这么多,落地到 ELK 时你到底该用哪种格式?我一般根据 PKI 组件的类型来定:
- Linux 上的 CA 服务(如 EJBCA、OpenXPKI) – 优先启用 JSON 输出,如果不行就用 Syslog + 结构化数据。
- Windows CA – 只能用 Syslog(通过 EventLog 转发),或者装第三方 Agent 转换为 CEF。
- 安全设备(SSL 解密、防火墙) – 绝大多数支持 CEF,直接用 CEF。
Logstash 对应的解析配置片段:
Syslog 解析(需要 grok)
filter {
grok {
match => { "message" => "<%{POSINT:pri>%{SYSLOG5424LINE}" }
overwrite => [ "message" ]
}
if [appname] =~ /lsass|ADCS|ejbca/ {
kv {
source => "msg"
field_split => ","
value_split => "="
}
}
}
JSON 解析(最省事)
filter {
json {
source => "message"
target => "pki_event"
}
date {
match => [ "[pki_event][timestamp]", "ISO8601" ]
}
}
CEF 解析(使用 logstash-filter-translate 或 grok)
filter {
grok {
match => { "message" => "CEF:0\\|%{DATA:cef_vendor}\\|%{DATA:cef_device}\\|%{DATA:cef_version}\\|%{DATA:cef_sigid}\\|%{DATA:cef_name}\\|%{INT:cef_severity}\\|%{GREEDYDATA:cef_extension}" }
}
kv {
source => "cef_extension"
field_split => " "
value_split => "="
transform_key => "lowercase"
}
}
json 过滤器,它的性能比 grok 高一个数量级。我曾经在客户环境下,把 Syslog 的 grok 改成 JSON 解析,CPU 直接从 70% 降到 15%。
4.6 一点总结
日志格式没有的“最好”,只有“最适合你的 PKI 环境”。我的建议是:能出 JSON 就出 JSON,不能出 JSON 就标准化到 CEF,实在没办法才用原生 Syslog。但不管你用哪种,一定要在 Logstash 中保持字段名的统一习惯——比如 [pki][serial_number]、[pki][subject],这样后续复用仪表盘模板时会非常爽。