3. Zeek配置体系与启动流程

Zeek 单机运行时,只需要一条 zeek -i eth0 命令即可抓包分析。但在生产网络中,流量往往分散在多个网段、多个采集口,甚至需要多台机器协同处理。这时就要引入 Zeek 自带的集群管理框架 zeekctl。理解 zeekctl 与几个核心配置文件的分工,是搭建可运维 Zeek 集群的第一步。

一、zeekctl 的角色:集群的“控制面”

zeekctl 是一个 Python 编写的命令行管理工具,它本身不解析流量,而是负责生成配置、启动/停止进程、监控状态、轮转日志。它把一份份声明式配置翻译成实际的 Zeek 进程拓扑。常用子命令包括:

zeekctl check      # 校验配置语法与节点定义
zeekctl deploy     # 安装配置并启动/重启集群
zeekctl status     # 查看各节点运行状态
zeekctl stop       # 停止全部节点
zeekctl diag       # 输出诊断信息(崩溃、日志、配置快照)

可以把 zeekctl 理解为“控制面”,而真正跑在网卡上抓包的是它拉起的“数据面”进程。控制面与数据面分离,是 Zeek 集群化设计的核心。

二、四类配置文件的职责划分

Zeek 集群的配置集中在安装目录(通常 /opt/zeek/etc 与 /opt/zeek/share/zeek/site)下,各文件职责边界清晰:

  • node.cfg:定义“有哪些节点、各自是什么角色、监听哪个接口”。这是集群拓扑的唯一来源。每个节点用一段 [节点名] 描述,关键字段有 type(standalone / manager / proxy / worker / logger)、host(所在主机)、interface(抓包接口)、lb_method(负载均衡方式)、lb_procs(worker 进程数)。
  • networks.cfg:定义“哪些网段属于本地网络”。每行一个 CIDR,用于让 Zeek 判断源/目的地址是内网还是外网,直接影响 local_orig、local_resp 等字段以及扫描、外联类告警的判定。
  • site/local.zeek:定义“加载哪些脚本、启用哪些策略”。它是站点级脚本入口,通过 @load 引入框架脚本和自定义脚本,并可覆盖变量、调整阈值。它决定“分析什么、告警什么”。
  • zeekctl.cfg:定义“zeekctl 自身的行为”,如日志目录 LogDir、邮件通知 MailTo、崩溃重启策略 CrashesToReport 等,属于运维参数而非分析逻辑。

一句话概括分工:node.cfg 管拓扑,networks.cfg 管地址空间,local.zeek 管分析逻辑,zeekctl.cfg 管运维行为。四者互不越界,修改后由 zeekctl deploy 统一生效。

Zeek 集群配置体系与启动数据流 node.cfg 拓扑 / 角色 / 接口 networks.cfg 本地网段 CIDR site/local.zeek 脚本加载 / 策略 zeekctl.cfg 日志 / 通知 / 重启 zeekctl deploy 校验 → 生成配置 → 分发启动 Manager 汇总 / 策略下发 Proxy 流量分发 Worker × N 抓包 / 协议解析 Logger 日志落盘 数据面:网卡 → Worker 解析 → Logger 写盘;控制面:Manager 汇总状态 zeekctl status 可查看各节点 running / crashed / stopped 状态

三、node.cfg 的典型写法

下面是一个双 worker 的集群示例(示例参数,非实测环境):

[manager]
type=manager
host=localhost

[proxy-1]
type=proxy
host=localhost

[worker-1]
type=worker
host=localhost
interface=eth0
lb_method=custom
lb_procs=2

[logger-1]
type=logger
host=localhost

其中 lb_procs=2 表示在该 worker 节点上启动 2 个抓包进程,配合 lb_method 实现多进程负载均衡。若只有单机单口,可只保留一个 type=standalone 节点,此时不需要 manager/proxy/logger。

四、networks.cfg 与 local.zeek 的配合

networks.cfg 内容非常简洁,每行一个网段:

10.0.0.0/8
192.168.0.0/16
172.16.0.0/12

它不产生任何脚本逻辑,但为脚本提供“本地/外部”判断依据。例如 scan.zeek 判断某地址是否在本地网段内,从而决定是否触发扫描告警。若漏配内网段,内网横向扫描可能被误判为外网扫描,告警质量明显下降。

site/local.zeek 则是脚本入口,典型内容:

@load base/protocols/conn
@load base/protocols/http
@load base/protocols/dns
@load policy/protocols/ssl/validate-certs
@load policy/frameworks/notice/community-id

redef Site::local_nets += { 10.10.0.0/16 };
redef Notice::emailed_types += { Scan::Address_Scan };

这里 @load 决定加载哪些分析脚本,redef 用于覆盖默认变量。注意:Site::local_nets 与 networks.cfg 存在关联——zeekctl 会把 networks.cfg 的内容注入到 Site::local_nets,因此两者应保持一致,避免冲突。

五、集群化启动与状态管理

配置完成后,标准启动流程是:

  1. zeekctl check:校验 node.cfg 语法、接口是否存在、脚本能否加载。任何一项失败都会给出明确报错,先修配置再继续。
  2. zeekctl deploy:安装配置、生成各节点脚本、按拓扑启动进程。首次部署会创建日志目录与状态文件。
  3. zeekctl status:查看每个节点状态。正常输出类似 worker-1 running;若显示 crashed,需用 zeekctl diag worker-1 查看崩溃原因。
  4. zeekctl stop / zeekctl restart:停止或重启集群,常用于脚本更新后重新加载。

状态管理的关键在于理解“进程状态”与“配置状态”是两回事。zeekctl status 反映的是进程是否存活;而配置是否生效,要看 deploy 是否成功执行。修改 local.zeek 后若不 deploy,运行中的进程仍使用旧脚本。因此运维习惯应是:改配置 → check → deploy → status 确认。

排障提示:若 zeekctl status 显示某 worker 反复 crashed,优先检查三处:接口名是否写错(interface=)、是否有权限抓包(需 root 或 CAP_NET_RAW)、local.zeek 中 @load 的脚本路径是否存在。用 zeekctl diag 可一次性拿到崩溃日志与配置快照,比逐个文件排查高效得多。