4. Node Exporter 安全指标:监控主机层面的安全配置

主机层是集群安全的最后一道物理防线。Node Exporter 不仅采集 CPU、内存等性能指标,还通过 textfile collector、procfs 和 sysfs 暴露大量与安全配置直接相关的指标。本章聚焦三类核心安全基线:文件权限、内核参数、用户审计,并演示如何通过 PromQL 将原始指标转化为可告警的安全评分。

4.1 安全指标采集架构

Node Exporter 默认不开启所有安全相关 collector。你需要显式启用以下模块:

Collector 名称 启用参数 覆盖的安全维度
textfile --collector.textfile.directory 自定义安全基线检查脚本输出
filefd --collector.filefd 文件描述符限制与使用率
ksmd --collector.ksmd 内核同页合并(KSM)安全风险
processes --collector.processes 进程总数与异常进程检测
systemd --collector.systemd Systemd 服务单元安全状态
生产建议:不要开启所有 collector。每个额外 collector 都会增加 Node Exporter 的内存开销和 /proc 读取频率。建议在测试环境先使用 --collector.disable-defaults --collector.textfile 组合,逐步添加安全相关模块。

4.2 文件权限监控:textfile collector 实战

文件权限检查是主机安全基线的核心。通过 textfile collector,你可以将自定义的权限检查脚本输出为 Prometheus 指标格式。以下是一个检查 /etc/shadow 和 /etc/ssh/sshd_config 权限的脚本示例:

#!/bin/bash
# /usr/local/bin/node_security_check.sh
# 输出格式:node_security_file_permission{file="...",expected="..."} 0|1

# 检查 /etc/shadow 权限应为 640
shadow_perm=$(stat -c "%a" /etc/shadow 2>/dev/null)
if [ "$shadow_perm" = "640" ]; then
  echo 'node_security_file_permission{file="/etc/shadow",expected="640"} 0'
else
  echo 'node_security_file_permission{file="/etc/shadow",expected="640"} 1'
fi

# 检查 /etc/ssh/sshd_config 权限应为 600
ssh_perm=$(stat -c "%a" /etc/ssh/sshd_config 2>/dev/null)
if [ "$ssh_perm" = "600" ]; then
  echo 'node_security_file_permission{file="/etc/ssh/sshd_config",expected="600"} 0'
else
  echo 'node_security_file_permission{file="/etc/ssh/sshd_config",expected="600"} 1'
fi

将脚本加入 cron,每分钟输出到 textfile 目录:

* * * * * /usr/local/bin/node_security_check.sh > /var/lib/node_exporter/textfile_collector/security.prom

Node Exporter 自动读取该文件后,Prometheus 中会出现指标 node_security_file_permission。当值为 1 时表示权限异常。

PromQL 告警规则:
node_security_file_permission == 1
该查询直接命中所有文件权限偏离基线的节点。建议结合 count by (instance) 聚合,生成节点级安全评分。

4.3 内核参数安全基线

内核参数直接影响网络层和内存层的攻击面。Node Exporter 通过 sysfs 暴露部分内核参数,但更完整的方案是使用 textfile collector 读取 /proc/sys 下的关键文件。以下表格列出需要重点监控的内核参数:

内核参数路径 安全基线值 风险说明
net.ipv4.ip_forward 0 IP 转发开启可能导致容器逃逸后的横向移动
net.ipv4.conf.all.rp_filter 1 反向路径过滤关闭易受 IP 欺骗攻击
kernel.randomize_va_space 2 ASLR 关闭降低漏洞利用难度
net.ipv4.tcp_syncookies 1 SYN Cookie 关闭增加 SYN Flood 风险
fs.protected_hardlinks 1 硬链接保护关闭可能导致提权

采集脚本示例(片段):

#!/bin/bash
# 检查内核参数基线
params=(
  "net.ipv4.ip_forward:0"
  "net.ipv4.conf.all.rp_filter:1"
  "kernel.randomize_va_space:2"
  "net.ipv4.tcp_syncookies:1"
  "fs.protected_hardlinks:1"
)

for param in "${params[@]}"; do
  key="${param%%:*}"
  expected="${param##*:}"
  filepath="/proc/sys/${key//./\/}"
  actual=$(cat "$filepath" 2>/dev/null)
  if [ "$actual" = "$expected" ]; then
    echo "node_security_kernel_param{param=\"$key\",expected=\"$expected\"} 0"
  else
    echo "node_security_kernel_param{param=\"$key\",expected=\"$expected\"} 1"
  fi
done
注意:部分内核参数(如 kernel.randomize_va_space)在容器内读取的是宿主机的命名空间值。如果你在 Kubernetes 节点上运行 Node Exporter 作为 DaemonSet,请确保使用 hostPID: true 和 hostNetwork: true,否则读取的可能是容器自身的参数,而非宿主机真实值。

4.4 用户审计指标

用户账户安全是主机入侵检测的重要维度。Node Exporter 原生不提供用户列表指标,但可以通过 textfile collector 暴露以下审计信息:

  • 空密码用户数:node_security_user_empty_password,值为 1 表示存在风险用户。
  • UID 0 的非 root 用户数:node_security_user_uid0_nonroot,直接反映权限滥用。
  • 最近 24 小时登录失败次数:node_security_login_failures_total,用于暴力破解检测。
  • sudoers 文件权限异常:node_security_sudoers_permission,预期为 440。

采集脚本示例:

#!/bin/bash
# 用户审计指标

# 空密码用户
empty_pwd=$(awk -F: '($2 == "" || $2 == "!") {print $1}' /etc/shadow 2>/dev/null | wc -l)
echo "node_security_user_empty_password $empty_pwd"

# UID 0 的非 root 用户
uid0_nonroot=$(awk -F: '($3 == 0 && $1 != "root") {print $1}' /etc/passwd 2>/dev/null | wc -l)
echo "node_security_user_uid0_nonroot $uid0_nonroot"

# sudoers 权限
sudoers_perm=$(stat -c "%a" /etc/sudoers 2>/dev/null)
if [ "$sudoers_perm" = "440" ]; then
  echo 'node_security_sudoers_permission 0'
else
  echo 'node_security_sudoers_permission 1'
fi

4.5 安全指标聚合与可视化

将上述三类指标聚合为节点安全评分,便于全局视图。以下 SVG 展示了从原始指标到安全评分的转换流程:

节点安全评分计算流程 文件权限指标 内核参数指标 用户审计指标 PromQL 聚合:count(... == 1) 节点安全评分(0-100) 评分 = (1 - 异常项/总项) × 100

对应的 PromQL 聚合查询:

# 计算每个节点的安全异常项总数
count by (instance) (
  node_security_file_permission == 1
  or
  node_security_kernel_param == 1
  or
  node_security_user_empty_password > 0
  or
  node_security_user_uid0_nonroot > 0
  or
  node_security_sudoers_permission == 1
)
评分阈值建议:在 Grafana 面板中设置颜色区间——绿色(0 异常)、黄色(1-2 项异常)、红色(≥3 项异常)。当节点进入红色区间时,自动触发告警并关联到对应节点的安全剧本。

4.6 安全基线的持续验证

指标驱动的安全基线检查不是一次性工作。建议建立以下持续验证循环:

  1. 基线定义:在 Git 仓库中维护 security_baseline.yml,包含文件权限、内核参数、用户审计的期望值。
  2. 自动部署:通过 Ansible 或 DaemonSet 将检查脚本分发到所有节点。
  3. 指标采集:Node Exporter textfile collector 每分钟刷新指标。
  4. 告警触发:Prometheus 告警规则检测到异常指标持续超过 5 分钟。
  5. 自动修复:通过 Webhook 触发修复作业(如 Ansible Playbook 或 Kubernetes Job)。

以下 SVG 展示了这一闭环流程:

安全基线持续验证闭环 基线定义
(Git YAML) 脚本分发
(Ansible/DaemonSet)
指标采集
(Node Exporter)
告警触发
(Prometheus)
自动修复
(Webhook + Job)
虚线表示基线版本更新反馈
关键成功因素:安全基线检查脚本必须与节点初始化流程解耦。不要将脚本硬编码到节点镜像中,而是通过配置管理工具统一分发和版本控制。这样当基线标准更新时,只需修改 Git 仓库中的 YAML 文件,所有节点会自动同步。