使用 Grafana Loki + Grafana 实现日志监控
昨天小红书刷到最近曝出一个严重的 Linux 本地提权漏洞 Copy Fail,当时心想补漏洞的话还要重启服务器耽误大家实验进度,实验室的同学应该没什么坏心眼吧。结果第二天做日常维护的时候用到 su 命令,发现怎么没输密码就进 root 了。心想坏了,肯定是有人利用了昨天的漏洞。查了一下系统日志,发现果然有其他用户提权到了 root,再一查用户命令历史,果然是执行了昨天曝出来的 Copy Fail PoC。哎,看来还是要多长个心眼。把这位用户锁定之后,觉得还是要加强防护,需要有一个完善的日志监控系统。毕竟这次对方只是忘记清理痕迹,下次如果遇到更强大的对手可能就永远不会发现自己的服务器已经被人攻破了。
在一番调查之后,我了解到目前主流的日志监控系统主要是 Datadog、ELK Stack 和 Grafana Loki + Grafana。其中 Datadog 和 ELK Stack 有些功能过剩,于是决定部署 Grafana Loki + Grafana。
auditd
auditd 负责收集内核事件,发送到 audispd。
-
安装 auditd:
sudo apt install auditd -
配置审计规则:
sudo curl -o /etc/audit/rules.d/audit.rules https://raw.githubusercontent.com/Neo23x0/auditd/master/audit.rules # 下载 Neo23x0 规则 sudo augenrules --load # 加载规则(不用管报错) sudo systemctl restart auditd # 重启 auditd sudo auditctl -l # 验证规则已加载 -
查看审计日志:
sudo cat /var/log/audit/audit.log
Laurel
Laurel 负责将多行审计事件转换成 JSON。
sudo apt install clang llvm-dev libauparse-dev libacl1-dev # 安装依赖
git clone https://github.com/threathunters-io/laurel.git
cd laurel
cargo build --release # 构建 laurel
sudo install -m755 target/release/laurel /usr/local/sbin/laurel # 安装 laurel 二进制文件
sudo useradd --system --home-dir /var/log/laurel --create-home _laurel # 创建 _laurel 用户
sudo mkdir /etc/laurel
sudo cp etc/laurel/config.toml /etc/laurel/config.toml # 复制配置文件
sudo cp etc/audit/plugins.d/laurel.conf /etc/audit/plugins.d/laurel.conf # 复制 audit 插件配置
sudo systemctl restart auditd # 重启 auditd 使其加载 laurel
Grafana Alloy
Alloy 是通用遥测收集器,可以同时采集日志、指标、链路和性能分析。
-
安装 Alloy:
curl -fsSL https://apt.grafana.com/gpg.key | \ gpg --dearmor | \ sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null && \ echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | \ sudo tee /etc/apt/sources.list.d/grafana.list && \ sudo apt update && \ sudo apt install alloy -
配置 Alloy:
sudoedit /etc/alloy/config.alloy// File Discovery local.file_match "laurel" { path_targets = [{ __path__ = "/var/log/laurel/audit.log", job = "laurel", }] } local.file_match "auth" { path_targets = [{ __path__ = "/var/log/auth.log", job = "auth", }] } local.file_match "sssd" { path_targets = [{ __path__ = "/var/log/sssd/*.log", job = "sssd", }] } // Laurel Audit Logs - Extract key fields loki.source.file "laurel" { targets = local.file_match.laurel.targets forward_to = [loki.process.laurel_json.receiver] } loki.process "laurel_json" { // Extract audit ID stage.json { expressions = { audit_id = "ID", } } // Extract numeric fields (uid, auid, pid, ses) stage.json { expressions = { uid = "USER_CMD.uid", auid = "USER_CMD.auid", ses = "USER_CMD.ses", pid = "USER_CMD.pid", } } // Extract from CRED_REFR events stage.json { expressions = { uid = "CRED_REFR.uid", auid = "CRED_REFR.auid", ses = "CRED_REFR.ses", pid = "CRED_REFR.pid", } } // Extract from other event types stage.json { expressions = { uid = "USER_START.uid", auid = "USER_START.auid", ses = "USER_START.ses", pid = "USER_START.pid", } } // Set labels from extracted fields stage.labels { values = { audit_id = "audit_id", auid = "auid", uid = "uid", } } stage.static_labels { values = { job = "laurel", } } forward_to = [loki.write.loki.receiver] } // Auth Logs loki.source.file "auth" { targets = local.file_match.auth.targets forward_to = [loki.process.auth_filter.receiver] } loki.process "auth_filter" { stage.drop { source = "" expression = ".*Connection closed by authenticating user.*" drop_counter_reason = "noisy_connection_closed" } stage.static_labels { values = { job = "auth", } } forward_to = [loki.write.loki.receiver] } // SSSD Logs loki.source.file "sssd" { targets = local.file_match.sssd.targets forward_to = [loki.process.sssd_filter.receiver] } loki.process "sssd_filter" { stage.static_labels { values = { job = "sssd", } } forward_to = [loki.write.loki.receiver] } // Loki Output loki.write "loki" { endpoint { url = "http://localhost:3100/loki/api/v1/push" } } -
重启 Alloy:
sudo systemctl enable alloy sudo systemctl restart alloy
参见:Install Grafana Alloy on Linux | Grafana Alloy documentation
Grafana Loki
Loki 负责存储和索引日志。
-
安装 Loki:
sudo apt install loki -
配置 Loki:
sudoedit /etc/loki/config.ymlauth_enabled: false ingester: chunk_idle_period: 3m max_chunk_age: 1h wal: enabled: true dir: /var/lib/loki/wal lifecycler: ring: kvstore: store: inmemory replication_factor: 1 limits_config: allow_structured_metadata: false reject_old_samples: true reject_old_samples_max_age: 168h schema_config: configs: - from: 2020-10-24 store: boltdb-shipper object_store: filesystem schema: v11 index: prefix: index_ period: 24h server: http_listen_port: 3100 log_level: info storage_config: boltdb_shipper: active_index_directory: /var/lib/loki/index cache_location: /var/lib/loki/boltdb-cache filesystem: directory: /var/lib/loki/chunks chunk_store_config: table_manager: retention_deletes_enabled: false retention_period: 0s compactor: working_directory: /var/lib/loki/compactor -
创建数据目录:
sudo mkdir -p /var/lib/loki/{index,chunks,wal,compactor} sudo chown -R loki:nogroup /var/lib/loki -
重启 Loki:
sudo systemctl enable alloy sudo systemctl restart loki -
等待 15s 后,验证:
$ curl http://localhost:3100/ready ready
Grafana OSS
Grafana OSS 负责查询 Loki,可视化和告警。
-
安装:
sudo apt install grafana -
启动:
sudo systemctl enable --now grafana-server -
访问 http://localhost:3000,用户名:
admin, 密码:admin
参见:Install Grafana on Debian or Ubuntu | Grafana documentation
添加数据源
-
访问
http://localhost:3000,登录(admin / admin) -
Connections>Data Sources>Add data source -
选择
Loki -
配置:
Name: Loki URL: http://localhost:3100 -
点击
Save & Test -
测试查询:
-
Explore -
选择数据源:
Loki -
在 Code 模式查询框输入:
{job="auth"} |= `sudo` |= `COMMAND` -
点
Run Query,你应该能看到 sudo 命令的日志。
-
-
点击
Add to dashboard添加到仪表板。

浙公网安备 33010602011771号