第13篇 监控安全与权限治理

前面把监控体系从「能采集」一路做到了「能看、能告警、能出报告、还能高可用长期存」。但是:系统本身几乎是敞开的。

本篇目标:覆盖 Prometheus / Exporter / Alertmanager / Grafana / 网络五个环节的加固做法,重点解决三件事:

  1. 把默认裸奔的接口锁上认证
  2. 把「谁能看什么」做成分级授权
  3. 把敏感数据挡在采集与展示之外

原则只有一条:监控网络也不可信,默认拒绝,按需放行。

一、先给监控系统定个性:它是高危资产

1、监控系统握着什么

资产 攻击者拿到后能做什么
全量指标数据 画出资产拓扑、依赖关系、容量水位 → 精准侦察
主机/应用明细指标 node_exporter 的 env、启动参数、挂载点可能直接泄露路径与凭据
主动抓取能力 Prometheus 能访问所有 target,等于一个内网探测器,可被当跳板
数据删除能力 admin API 可删序列、清墓碑,破坏事后取证
告警通道 伪造/轰炸告警,做钓鱼或淹没真告警
Grafana 面板 面板是数据出口,插件与数据源配置甚至可能成为命令执行入口

2、默认配置的风险清单

先把「出厂即不安全」的地方列清楚,再逐条处理:

组件 默认状态 风险等级
Prometheus Web / HTTP API 无认证、无 TLS 高
Prometheus admin API 默认关闭,但第12篇为做快照开过 一旦开启即高危
node_exporter (:9100) 无认证、监听 0.0.0.0 高
Alertmanager (:9093) 无认证 中
Grafana admin/admin,匿名访问可开 高
Docker 端口映射 -p 9090:9090 默认绑全网卡 高

二、Prometheus:把 Web 与 API 锁上

1、Web 与 API 认证(web.config.file)

Prometheus 从 v2.24 起支持 --web.config.file,用一份独立配置同时开 TLS 和 basic auth,是最省事的加固手段。

先生成密码哈希:

bash 复制代码
# 用 htpasswd 生成 bcrypt 哈希(-B 强制 bcrypt,-C 10 代价因子)
$ htpasswd -nBC 10 "" | tr -d ':'
$2y$10$..........   # 复制这一串

写 web-config.yml:

yaml 复制代码
# /etc/prometheus/web-config.yml
tls_server_config:
  cert_file: /etc/prometheus/certs/prometheus.crt
  key_file: /etc/prometheus/certs/prometheus.key
  min_version: TLS12          # 拒绝 TLS1.0/1.1

basic_auth_users:
  monitor: $2y$10$..........   # 认证用户 monitor
  readonly: $2y$10$..........  # 只读账号

启动参数挂上:

bash 复制代码
--web.config.file=/etc/prometheus/web-config.yml

⚠️ 注意:web-config.yml 里的密码是 bcrypt 哈希而非明文,但文件本身要 chmod 600,且不要和 prometheus.yml 混在同一个只读挂载里。

2、别让 admin API 常开

--web.enable-admin-api 一旦打开,就多了以下能改数据的接口:

接口 作用
/api/v1/admin/tsdb/delete_series 删除匹配的序列
/api/v1/admin/tsdb/clean_tombstones 清墓碑,删除不可恢复
/api/v1/admin/tsdb/snapshot 生成快照

3、抓取端认证:让 Prometheus 能过 target 的鉴权

加固不能只加固 Prometheus 自己,当 exporter 或业务端点也要求认证时,scrape 配置得能带凭据。三种方式:

yaml 复制代码
scrape_configs:
  # 方式一:basic_auth
  - job_name: "node-detail"
    basic_auth:
      username: monitor
      password_file: /etc/prometheus/secrets/node_pw   # 用 *_file,别写明文

  # 方式二:Bearer Token(推荐用 authorization)
  - job_name: "spring-app"
    authorization:
      type: Bearer
      credentials_file: /etc/prometheus/secrets/app_token

  # 方式三:TLS 客户端证书(mTLS)
  - job_name: "secure-target"
    scheme: https
    tls_config:
      ca_file: /etc/prometheus/certs/ca.crt
      cert_file: /etc/prometheus/certs/client.crt
      key_file: /etc/prometheus/certs/client.key
      insecure_skip_verify: false    # 绝不要设 true

⚠️ 注意:优先用 _file 变体(password_file / credentials_file)。 明文写在 prometheus.yml 里的凭据,会随配置进 Git、进备份、进镜像层,属于典型的「写死即泄露」。

4、远程读写(remote_write)走加密通道

第12篇的 remote_write 默认是明文 HTTP。跨机房或跨网段时,改成 HTTPS + 认证:

yaml 复制代码
remote_write:
  - url: https://victoria-metrics:8428/api/v1/write
    basic_auth:
      username: writer
      password_file: /etc/prometheus/secrets/rw_pw
    tls_config:
      ca_file: /etc/prometheus/certs/ca.crt

5、收敛危险端点

除 admin API 外,还有几个端点要留意:

端点 说明 处理
/-/reload 配置热加载,需 --web.enable-lifecycle 反代层限制来源
/debug/pprof/* 性能剖析,可能泄露内存中的敏感信息 生产环境在反代层屏蔽
/api/v1/query 可执行任意 PromQL 必须跟 Web 一样认证

第一道也是最有效的一道防线:反代层只放行白名单路径。

三、Exporter:管好「口子」和「内容」

1、监听地址:从 0.0.0.0 收到内网

exporter 是最容易被忽略的暴露面,exporter 通常以 root 或高权限运行,且监听全网卡。

bash 复制代码
# node_exporter 只监听本机,由 Prometheus 走同宿主机或隧道访问
node_exporter --web.listen-address=127.0.0.1:9100

# 若 Prometheus 在另一台机器,则绑定内网网卡
node_exporter --web.listen-address=10.0.2.15:9100

再叠加防火墙/安全组只放行 Prometheus 的 IP:

bash 复制代码
# 只允许 Prometheus 主机访问 9100
$ iptables -A INPUT -p tcp --dport 9100 -s 10.0.2.10 -j ACCEPT
$ iptables -A INPUT -p tcp --dport 9100 -j DROP

2、exporter 自身也开认证

node_exporter 同样支持 --web.config.file:

bash 复制代码
node_exporter \
  --web.listen-address=:9100 \
  --web.config.file=/etc/node_exporter/web-config.yml

配合第二节 scrape 的 basic_auth,端点就从「裸奔」变成「持证访问」。

3、挡住敏感指标:先看清「默认开没开」

很多人以为 exporter 会泄露一堆敏感指标,其实恰恰相反,node_exporter 里很多高危的 collector 默认就是关闭的,风险反而常来自「为排障临时打开、用完忘了关」。所以加固第一步不是裁剪,而是先核对到底开了哪些 collector:

bash 复制代码
# 查看当前各 collector 的启用与采集情况
$ curl -s http://localhost:9100/metrics | grep '^node_scrape_collector_success'
collector / 指标 默认状态 泄露内容 建议
systemd(node_systemd_unit_*) 默认关闭 单元名、运行状态,可能含业务命名 仅排障时临时 --collector.systemd;长期开启需评估
processes(node_processes_*) 默认关闭 进程数、可按状态聚合 需要才开,非必要不开
logind / interrupts / perf 默认关闭 登录会话、中断、性能剖析 同上,非必要不开
node_filesystem_*(mountpoint 标签) 默认开启 挂载点路径,可能暴露业务目录结构 视情况裁剪
node_uname_info 默认开启 内核版本、主机名 接受或裁剪
node_network_info 默认开启 网卡 MAC、operstate 一般保留

⚠️ 注意:「默认关闭」不等于安全。 一旦有人加 --collector.systemd 把 systemd collector 打开,node_systemd_unit_* 这类敏感指标立刻上线;而这类「临时开启」往往没人记录、没人回收。真正要做的是先摸清并锁定 collector 清单,把它纳入变更与巡检。

裁剪仍在采集末端做(metric_relabel_configs),但作用对象应是你确认开启、且确属敏感的序列:

yaml 复制代码
metric_relabel_configs:
  # 例:若确实开了 systemd collector,又不想让单元名入库
  - source_labels: [__name__]
    regex: "node_systemd_unit_state"
    action: drop

⚠️ 注意:drop 不可逆,历史和未来一起消失,先在线下验证无人引用再上生产。

4、Pushgateway 与短命任务

短命任务走 Pushgateway,默认也不鉴权,且任何人 push 的指标都会长期留存。加固要点:

bash 复制代码
pushgateway --web.config.file=/etc/pushgateway/web-config.yml \
            --web.listen-address=127.0.0.1:9091

并约定 push 时带 job/instance 命名规范,便于审计来源。

四、Alertmanager 与通知链路

1、Alertmanager 的认证

Alertmanager 从 v0.22 起也支持 --web.config.file:

bash 复制代码
alertmanager \
  --config.file=/etc/alertmanager/alertmanager.yml \
  --web.config.file=/etc/alertmanager/web-config.yml \
  --cluster.listen-address=0.0.0.0:9093

集群里,节点间 gossip 通信(cluster 端口)同样应限制在集群内部网段,不要暴露。

2、通知渠道的凭据别明文

alertmanager.yml 里常出现 webhook 密钥、邮箱密码、IM token。以下反例是重灾区:

yaml 复制代码
# ❌ 反例:明文写在配置里
receivers:
  - name: "webhook"
    webhook_configs:
      - url: "https://hook.example.com/alert?token=abc123"

改用外部文件引用:

yaml 复制代码
# ✅ 正确:从外部文件读取
receivers:
  - name: "webhook"
    webhook_configs:
      - url_file: /etc/alertmanager/secrets/webhook_url

3、告警内容脱敏

第9篇的告警模板会把 label 渲染进通知,而 label 里可能带 instance(暴露内网 IP)、svc、甚至业务标识。发往企业微信、钉钉、外部 Webhook 前,检查模板是否泄露了不该外传的信息。涉及外部渠道时,宁可只发 summary + description,不发原始 label 全集。

五、Grafana:权限治理的主战场

「权限治理」落到实践上大半都在 Grafana。因为 Grafana 直接面向人:开发、测试、运维、业务方、负责人,各自该看到什么、能改什么,全靠这一层约束。

1、上线第一件事:关掉匿名与默认口令

ini 复制代码
# grafana.ini
[auth.anonymous]
enabled = false          # 禁止匿名访问

[security]
admin_user = admin
admin_password = <强口令>
cookie_secure = true      # 仅 HTTPS 传输 cookie

[users]
allow_sign_up = false     # 禁止自助注册

⚠️ 注意:admin/admin 是 Grafana 最经典的失守点。装完先改口令,再谈其他。

2、认证集成:从本地账号到 SSO

不要在 Grafana 里单独建号、单独发密码。应对接企业统一认证,账号生命周期跟着 HR/AD 走:

方式 适用 关键配置
LDAP / AD 已有域控 [auth.ldap],配 bind 与 group 映射
OAuth / OIDC 已有 SSO(Keycloak、企业微信、飞书等) [auth.generic_oauth]
SAML 企业级 SSO [auth.saml](需企业版)

OIDC 核心片段:

ini 复制代码
[auth.generic_oauth]
enabled = true
name = SSO
client_id = grafana
client_secret = ${GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET}   # 走环境变量,不写死
scopes = openid profile email groups
auth_url = https://sso.example.com/auth
token_url = https://sso.example.com/token
api_url = https://sso.example.com/userinfo
role_attribute_path = contains(groups[*], 'monitor-admins') && 'Admin' || 'Viewer'

最后一行:用 SSO 的 group 自动决定 Grafana 角色,不用在 Grafana 里手工授权。

3、三层模型:组织、团队、用户

Grafana 的权限是分层叠加的,先理清三个概念:

概念 含义 用途
Organization(组织) 彼此隔离的空间,数据源与 Dashboard 不互通 多租户,如「生产」与「研发测试」
Team(团队) 组织内的一组用户 按职责分组,如「支付组」「基础架构组」
User(用户) 账号 最小授权单位

4、角色:给最小权限

Grafana 内置三种组织角色(OSS 版):

角色 能做什么 给谁
Viewer 只看,不能改 业务方、上级
Editor 能建改 Dashboard,但不能动数据源/用户 开发、测试
Admin 能管数据源、用户、组织设置 运维、平台管理员

⚠️ 注意:默认只给 Viewer,不能给 Editor。 Editor 虽不能管用户,但能创建任意查询、导出数据、改面板,等同于能拿到他能访问的所有数据。业务方一律 Viewer 起步。

5、文件夹权限:按团队隔离

Dashboard 靠文件夹(Folder)组织,权限也挂在文件夹上:

yaml 复制代码
组织: 生产监控
├── 文件夹: 支付业务面板     → Team: 支付组 (Edit)、业务方 (View)
├── 文件夹: 基础架构面板     → Team: 基础架构组 (Edit)
└── 文件夹: 容量与成本       → 仅 Admin 可见

在 Folder → Permissions 里配置:View / Edit / Admin 三级,分别授权给 User / Team / Role。默认继承组织的「Viewer 可见」,要隔离就把默认降权,再显式授权。

6、数据源权限:最容易被忽略的盲区

⚠️ 默认情况下,任何登录用户(包括 Viewer)都能用「Explore」直接对数据源跑任意 PromQL。 即使把 Dashboard 锁得再死,Viewer 只要会写 PromQL,就能把整个 Prometheus 的数据查个底朝天,包括没给他看的面板背后的数据。

解法是 Data source permissions(数据源权限):

r 复制代码
数据源 prometheus-prod → Permissions → 只授权给 Team: 基础架构组

开启后,只有被显式授权的团队能用这个数据源查询;其他人即使有 Explore 权限,也选不到这个数据源。这就是「面板级隔离」和「数据级隔离」的关键差别。

7、其他几处开关

配置 作用 建议
viewers_can_edit Viewer 是否可临时改面板 false
[explore] enabled Explore 查询功能 按需,敏感环境可关
editors_can_admin Editor 能否管理其团队的权限 谨慎开启
[snapshots] external_enabled 是否允许公开分享快照 false,快照会绕过权限

8、审计

  • Grafana 审计日志(Audit Log)记录登录、查询、修改操作,属企业版能力;OSS 版可退而用反向代理访问日志 + SSO 侧日志拼出操作轨迹。
  • Prometheus、Alertmanager 的访问也应经反代记录来源 IP,便于事后追查。

六、网络与传输安全

1、网络分段:监控网独立

把 Prometheus、Alertmanager、Grafana、各 exporter 放进独立的监控网段,与业务网、办公网隔离:

  • 监控网 → 业务网:只放行抓取所需端口(9100、应用 actuator 等),其余全拒;
  • 办公网 → 监控网:只经 Grafana 反代入口,直连 Prometheus/AM 一律拒绝;
  • 监控网 → 互联网:原则上不出,如需推送告警,走白名单出站。

2、统一入口:反向代理 + 认证

不能直连 Prometheus 的 9090,用 Nginx 做统一入口,把认证、TLS、路径白名单一次解决:

nginx 复制代码
server {
  listen 443 ssl;
  server_name prom.example.com;

  ssl_certificate     /etc/nginx/certs/prom.crt;
  ssl_certificate_key /etc/nginx/certs/prom.key;

  # 屏蔽危险端点
  location ~ ^/(api/v1/admin|debug/pprof) { return 403; }

  location / {
    auth_basic "monitor";
    auth_basic_user_file /etc/nginx/.htpasswd;

    proxy_pass http://prometheus:9090;
    proxy_set_header X-Real-IP $remote_addr;    # 记录真实来源,供审计
  }
}

Grafana 则让它自己做认证与授权,反代只负责 TLS 与限源:

nginx 复制代码
location /grafana/ {
  allow 10.0.0.0/8;      # 仅办公网/内网
  deny all;
  proxy_pass http://grafana:3000/;
  proxy_set_header X-Real-IP $remote_addr;
}

3、mTLS(高安全场景)

对跨机房、跨云的监控链路,用双向 TLS:Prometheus 持有客户端证书,exporter 用 --web.config.file 校验。

4、出站控制

Prometheus 的输出面(remote_write、webhook、抓取)应有出站白名单,防止被攻破后当成数据回传通道。

七、凭据管理:把密钥从配置里拿出来

凭据分三类,处理方式不同:

凭据类型 示例 正确存放 反例
服务账号密码 scrape basic_auth *_file 指向 600 权限文件 写在 prometheus.yml
API Token SSO client_secret、webhook token 环境变量 / K8s Secret / Vault 写在 grafana.ini、alertmanager.yml
证书私钥 TLS key 600 权限,挂载只读 打进镜像层

文件权限,最小可读原则:

bash 复制代码
# 凭据文件:只有运行用户可读
$ chmod 600 /etc/prometheus/secrets/node_pw
$ chown 65534:65534 /etc/prometheus/secrets/node_pw   # Prometheus 容器内 nobody

# 目录:可进入但不可列举
$ chmod 700 /etc/prometheus/secrets

⚠️ 注意:Docker/K8s 里不要把凭据用 -e PASSWORD=xxx 传。 docker inspect 和进程列表都能看到环境变量明文。用挂载的 secret 文件,或用支持 secret 引用的编排方式(K8s Secret、Compose 的 secrets:)。

八、一份可落地的加固清单

不必一次做完,按「投入产出比」分三批推进即可。

第一批:立杆见效(高风险、低成本)

项 动作 验证
改默认口令 Grafana 改 admin 密码 不再能 admin/admin 登录
关匿名 auth.anonymous.enabled=false 未登录访问被拒
端口收敛 Prometheus/Grafana/exporter 绑定内网 IP 公网扫不到端口
关 admin API 移除 --web.enable-admin-api /api/v1/admin 404
凭据文件化 scrape 密码改 *_file 配置里搜不到明文

第二批:安全升级(需协调)

项 动作
Web 认证 Prometheus/AM 配 web.config.file 开 TLS + basic auth
反代收口 Nginx 统一入口 + 白名单 + 屏蔽 pprof/admin
SSO 对接 Grafana 接 LDAP/OIDC,按 group 映射角色
数据源权限 开启 Data source permissions,按团队授权

第三批:常态化(体系化)

项 动作
网络分段 监控网独立,最小放行
collector 清单 锁定启用的 collector,回收临时开启项
文件夹权限 按团队建立文件夹权限矩阵
凭据管理 引入统一 secret 管理(Vault / K8s Secret)
审计 开启审计日志,定期 review 高权限账号
巡检 把「是否匿名访问、是否新增 admin API、是否新增非必要 collector、是否有明文凭据」纳入月度巡检

九、小结

安全不是监控体系的「附加项」,而是前面十二篇所有能力能否被信任的前提,一个没有认证的 Prometheus,采得越全、看得越透,被攻破时泄露得越彻底。

本篇核心要点:

  • 一是默认即不安全。Prometheus、Alertmanager、Grafana、exporter 出厂都是敞开或弱口令的,第一个动作永远是关默认、收端口、上认证。
  • 二是认证有三个层面 :入口认证(谁能访问)、抓取认证(Prometheus 怎么证明身份)、传输加密(TLS/mTLS);Prometheus、Alertmanager、node_exporter 都支持同一套 --web.config.file,配置风格统一。
  • 三是权限治理的主战场是 Grafana,且要分「面板级」和「数据级」两层,只锁 Dashboard 是假隔离,必须开 Data source permissions,否则 Viewer 用 Explore 就能绕过。
  • 四是敏感指标先摸清 collector 再谈裁剪。node_exporter 的高危 collector(如 systemd、processes)默认是关闭的,风险常来自「临时开、忘了关」;加固重点是把 collector 清单管住,而非盲目 drop。
  • 五是凭据绝不进配置文件 。用 *_file、环境变量或 secret 管理,配合 600 权限,堵住「配置即泄露」这条最常见的数据外流通道。
  • 六是加固可以分期推进:先做「立杆见效」的一批,风险立刻下降一大截,再逐步做到网络分段与审计常态化。

至此,监控体系在能力上和安全上完成了闭环,既采得全、看得清、告得准、存得久,也守得住。

相关推荐
鸿观工坊6 小时前
第11篇 监控报告编写:SLO/SLI 与数据分析方法
监控
鸿观工坊3 天前
第09篇 告警体系设计:Alertmanager 路由与告警治理
监控
做萤石二次开发的哈哈7 天前
视频解码器怎么对接?解码上墙、电视墙开窗与场景切换的ISAPI接入实战
人工智能·物联网·监控·视频编解码·大屏端·萤石开放平台·蓝海aiot一站式工作台
lisanmengmeng7 天前
nagios 图形化监控部署
监控·nagios
鸿观工坊7 天前
第5篇 Nginx 监控:流量、连接与性能指标
监控
鸿观工坊8 天前
第4篇 Spring Boot 应用监控:Micrometer 与 JVM 指标
监控
鸿观工坊8 天前
第1篇 Prometheus 监控体系全景与基础环境搭建
监控
苏渡苇15 天前
Spring Insight 里如何把 Span 画成瀑布时间线
后端·spring·spring cloud·springboot·监控·apm
行百里er15 天前
轻量级 Spring 监测工具——Spring Insight 发布了
spring boot·后端·监控