Prometheus安全加固实战:Nginx反向代理与内置认证配置详解

Prometheus安全加固实战:Nginx反向代理与内置认证配置详解

1. 项目概述:为什么我们需要给Prometheus“上锁”?

在监控领域,Prometheus 以其强大的数据抓取能力和灵活的查询语言(PromQL)成为了事实上的标准。但很多朋友在初次部署时,往往会忽略一个关键环节:安全。默认情况下,Prometheus 的 Web UI 和 API 是直接暴露的,没有任何访问控制。想象一下,你的服务器性能指标、业务运行状态,甚至是一些包含敏感信息的标签(比如数据库连接串、内部服务地址),就这么“裸奔”在网络上,任何人只要知道 IP 和端口就能一览无余。这无异于把自家大门的钥匙插在锁上。

我见过不止一个团队,在内部测试环境部署了 Prometheus,因为觉得是内网就跳过了认证,结果某次端口意外暴露到公网,差点酿成数据泄露的风险。所以,给 Prometheus 加上“锁”——也就是加密配置和登录认证,绝不是可有可无的“高级功能”,而是生产环境部署的必备步骤。这不仅仅是防止未授权访问,更是满足各类安全审计和合规性要求的基础。

本次分享,我将结合自己多次在生产环境落地的经验,详细拆解两种主流的 Prometheus 安全加固方式:基于 Web 服务器(如 Nginx/Apache)的反向代理认证,以及 Prometheus 自身集成的 Web 配置文件和基础认证。我会把配置的每一步、背后的原理,以及我踩过的那些“坑”都摊开来讲清楚。无论你是运维工程师、SRE,还是正在搭建自己监控体系的开发者,这篇内容都能帮你构建一个既安全又可靠的 Prometheus 监控栈。

2. 安全加固的两种核心路径解析

在开始动手之前,我们得先理清思路。Prometheus 本身在设计上遵循“只做一件事并做好”的 Unix 哲学,其核心是抓取和存储时间序列数据,因此原生不提供复杂的用户认证和授权系统。要实现安全访问,我们需要借助外部组件或其有限的内置功能。主流方案可以归结为以下两条路径,它们各有优劣,适用场景也不同。

2.1 路径一:反向代理网关模式

这是目前生产环境中最主流、最推荐的方式。其核心思想是:不直接暴露 Prometheus 服务,而是在其前面部署一个成熟的 Web 服务器(如 Nginx、Apache、Caddy)或 API 网关(如 Traefik、Envoy)作为反向代理和认证网关

工作原理

  1. 用户或客户端(如 Grafana)的所有请求首先到达反向代理服务器。
  2. 代理服务器负责完成 TLS/SSL 加密(HTTPS)、用户认证(如 Basic Auth、OAuth2、LDAP)等所有安全相关的工作。
  3. 认证通过后,代理服务器将请求转发给后端的 Prometheus 服务(通常监听在 localhost 或内部网络)。
  4. Prometheus 本身无需任何修改,它只接收来自可信代理的“干净”请求。

为什么这是首选方案?

  • 功能强大且成熟:Nginx 等 Web 服务器经过多年实战检验,其 TLS 实现、认证模块非常稳定和全面。你可以轻松集成多种认证方式,这是 Prometheus 自身无法比拟的。
  • 职责分离:安全(认证、加密)与业务(监控数据抓取、查询)解耦。Prometheus 可以专注于其核心任务,安全策略的变更和升级不影响监控服务本身。
  • 统一入口:在实际架构中,你很可能不止有 Prometheus 需要保护,还有 Alertmanager、Grafana 等其他组件。使用同一个反向代理作为统一的安全网关,可以简化证书管理和认证策略配置。
  • 灵活性高:你可以轻松添加 IP 白名单、限流、访问日志审计等更多安全层。

2.2 路径二:Prometheus 内置 Web 配置文件认证

从 Prometheus 2.24 版本开始,引入了通过web.config.yml文件配置 TLS 和基础认证(Basic Authentication)的支持。这种方式将安全配置直接内嵌到 Prometheus 进程中。

工作原理

  1. 你需要准备一个web.config.yml配置文件,其中定义了 TLS 证书路径和 HTTP 基础认证的用户密码哈希。
  2. 在启动 Prometheus 时,通过--web.config.file参数指定该配置文件。
  3. Prometheus 的 Web 服务器将直接使用该配置,提供 HTTPS 服务和基础认证。

它的适用场景与局限

  • 优点:部署简单,无需引入额外组件,适合小型环境或快速原型验证。所有配置集中在一个 Prometheus 实例上。
  • 缺点
    • 功能单一:仅支持静态配置的基础认证,无法集成 OAuth、LDAP 等复杂认证系统。
    • 管理不便:用户密码以哈希形式写在配置文件中,添加或修改用户需要更新配置文件并重启 Prometheus。
    • 耦合性高:安全与业务耦合,证书轮换等操作需要重启服务。
    • 版本依赖:需要较新版本的 Prometheus(>=2.24)。

我的经验选择:对于任何严肃的生产环境,我毫无保留地推荐路径一(反向代理模式)。它更符合现代云原生架构的理念,扩展性和可维护性要好得多。路径二可以作为一个轻量级的备选方案,或者在开发测试环境中临时使用。接下来,我将以最常用的 Nginx 作为反向代理为例,展开详细配置。

3. 实战:基于 Nginx 反向代理的完整配置流程

我们将搭建一个标准的架构:用户 -> HTTPS (Nginx with Basic Auth) -> HTTP (Prometheus)。目标是让 Prometheus 在http://localhost:9090安全地运行,而外部通过https://your-domain.com/prometheus来访问。

3.1 环境准备与组件安装

首先,确保你的服务器上已经安装了 Prometheus。如果还没安装,可以通过以下步骤快速完成(以 Linux 为例):

# 下载最新版本的 Prometheus (请从官网替换为最新版本号) wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz # 解压 tar xvf prometheus-*.tar.gz cd prometheus-* # 将可执行文件移动到系统路径 sudo cp prometheus promtool /usr/local/bin/ # 创建配置和数据目录 sudo mkdir -p /etc/prometheus /var/lib/prometheus sudo cp prometheus.yml /etc/prometheus/

接下来,安装 Nginx。大多数 Linux 发行版都可以通过包管理器安装:

# Ubuntu/Debian sudo apt update && sudo apt install nginx apache2-utils -y # CentOS/RHEL sudo yum install nginx httpd-tools -y

这里我们同时安装了apache2-utils(或httpd-tools),因为它包含了htpasswd工具,用于生成基础认证的密码文件。

3.2 生成密码文件与配置基础认证

安全的第一步是创建授权用户。我们将用户名和密码哈希存储在一个文件中。

# 创建密码文件,首次添加用户使用 -c 参数,后续添加不要用 -c,否则会覆盖! sudo htpasswd -c /etc/nginx/.htpasswd prometheus_admin

执行命令后,会提示你输入并确认密码。prometheus_admin是你指定的用户名。请务必将生成的/etc/nginx/.htpasswd文件权限设置为仅 root 可读,以保护密码哈希。

sudo chmod 600 /etc/nginx/.htpasswd

3.3 获取与配置 SSL/TLS 证书

没有 HTTPS 的认证是“纸糊的墙”,因为密码在网络上明文传输。我们必须启用 HTTPS。

对于生产环境:你应该使用来自 Let‘s Encrypt(免费)或其他商业 CA 签发的可信证书。使用 Certbot 可以自动化这个过程:

# 安装 Certbot (以 Nginx on Ubuntu 为例) sudo apt install certbot python3-certbot-nginx -y # 获取并自动配置证书,your-domain.com 替换为你的域名 sudo certbot --nginx -d your-domain.com

Certbot 会自动修改你的 Nginx 配置,启用 HTTPS。

对于测试或内部环境:你可以使用自签名证书。虽然浏览器会警告,但用于内部服务或配合 Grafana(可配置跳过证书验证)是可行的。

# 生成自签名证书 (有效期365天) sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/ssl/private/nginx-selfsigned.key \ -out /etc/ssl/certs/nginx-selfsigned.crt

你需要填写一些证书信息,其中Common Name最好填写你的服务器 IP 或域名。

3.4 编写核心的 Nginx 服务器配置

这是最关键的一步。我们将在/etc/nginx/sites-available/prometheus创建一个新的服务器块配置。假设你的域名是monitor.yourcompany.com

server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name monitor.yourcompany.com; # 你的域名 # SSL 证书路径 (使用 Certbot 的路径通常如下,自签名证书需调整) ssl_certificate /etc/letsencrypt/live/monitor.yourcompany.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/monitor.yourcompany.com/privkey.pem; # 启用 SSL 会话复用,提升性能 ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 安全地转发到 Prometheus location /prometheus/ { # 1. 启用基础认证 auth_basic "Prometheus Server Authentication"; auth_basic_user_file /etc/nginx/.htpasswd; # 2. 反向代理到本地的 Prometheus proxy_pass http://localhost:9090/; # 注意结尾的斜杠,它很重要! # 3. 传递必要的头部信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 4. 设置 WebSocket 支持 (Grafana Live 特性可能需要) proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 5. 适当调大超时时间,应对大量查询 proxy_read_timeout 300; proxy_connect_timeout 300; } # 可选:重定向 HTTP 到 HTTPS # server { # listen 80; # server_name monitor.yourcompany.com; # return 301 https://$server_name$request_uri; # } }

配置要点解析

  1. auth_basicauth_basic_user_file指令启用了基础认证,并指定了密码文件。
  2. proxy_pass将匹配/prometheus/路径的请求转发给本地 9090 端口的 Prometheus。结尾的斜杠/至关重要,它会将/prometheus/api/v1/query这样的请求正确地重写为http://localhost:9090/api/v1/query。如果没有这个斜杠,路径会错乱,这是最常见的配置错误之一。
  3. proxy_set_header系列指令确保了原始请求的客户端信息(如真实 IP)能传递给 Prometheus,这对于日志记录和审计很有帮助。
  4. WebSocket 头部的设置是为了兼容 Grafana 的“实时预览”等高级功能。
  5. 超时时间的调整是因为 Prometheus 的查询,尤其是范围查询,可能耗时较长,需要避免代理层过早断开连接。

3.5 启用配置并启动服务

创建符号链接启用站点配置,并测试 Nginx 配置语法。

sudo ln -s /etc/nginx/sites-available/prometheus /etc/nginx/sites-enabled/ sudo nginx -t # 测试配置,必须看到 “syntax is ok” 和 “test is successful”

如果测试成功,重启 Nginx 使配置生效。

sudo systemctl restart nginx

现在,确保你的 Prometheus 服务正在运行(默认监听localhost:9090)。然后,你就可以通过浏览器访问https://monitor.yourcompany.com/prometheus,会弹出一个登录框,输入之前设置的prometheus_admin和密码即可访问。

4. 另一种选择:配置 Prometheus 内置的 Web 认证

如果你坚持使用内置方案,以下是具体步骤。再次强调,这更适合轻量级、非核心的场景。

4.1 创建 Web 配置文件

在 Prometheus 配置目录(如/etc/prometheus)下创建web-config.yml

tls_server_config: cert_file: /etc/prometheus/ssl/prometheus.crt key_file: /etc/prometheus/ssl/prometheus.key basic_auth_users: prometheus_admin: $2y$12$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • tls_server_config:指定你的 TLS 证书和私钥路径。证书生成方式同上。
  • basic_auth_users:定义用户名和密码的 bcrypt 哈希。密码不是明文!

4.2 生成密码哈希

使用htpasswd或其他工具生成 bcrypt 哈希。这里用openssl

# 生成 bcrypt 哈希 (rounds 是成本因子,默认12,越高越安全但也越慢) openssl passwd -6 -stdin

输入你的密码后,会输出一个以$2b$$2y$开头的哈希字符串,将其复制到web-config.yml中。

4.3 修改 Prometheus 启动命令

你需要修改 systemd 服务文件(通常是/etc/systemd/system/prometheus.service)或直接修改启动命令,添加--web.config.file参数:

ExecStart=/usr/local/bin/prometheus \ --config.file=/etc/prometheus/prometheus.yml \ --storage.tsdb.path=/var/lib/prometheus/ \ --web.console.templates=/etc/prometheus/consoles \ --web.console.libraries=/etc/prometheus/console_libraries \ --web.config.file=/etc/prometheus/web-config.yml \ # 新增这行 --web.listen-address=0.0.0.0:9090

重启 Prometheus 服务后,它将在 9090 端口提供 HTTPS 服务,并需要基础认证。

5. 关键踩坑点与疑难问题排查实录

理论配置看起来简单,但实操中陷阱不少。下面是我总结的几个典型“坑”及其解决方案。

5.1 路径代理的“斜杠”陷阱

这是 Nginxproxy_pass指令最经典的坑。

  • 错误配置location /prometheus { proxy_pass http://localhost:9090; }
  • 现象:访问https://domain/prometheus可能正常,但访问https://domain/prometheus/api/v1/targets时,Nginx 会将请求转发给http://localhost:9090/api/v1/targets丢失了/prometheus前缀。这会导致 Prometheus 返回 404,因为它的 API 根路径是/,而不是/prometheus
  • 正确配置
    • 方案A(推荐):在locationproxy_pass的 URL 后都加上斜杠。location /prometheus/ { proxy_pass http://localhost:9090/; }。这样 Nginx 会将/prometheus/前缀从请求路径中剥离后再转发。
    • 方案B:使用rewrite指令重写路径。location /prometheus { rewrite ^/prometheus/(.*) /$1 break; proxy_pass http://localhost:9090; }

5.2 Grafana 数据源配置认证

当 Prometheus 开启基础认证后,Grafana 数据源必须配置对应的凭据。

  1. 在 Grafana 中,进入Configuration -> Data Sources -> Prometheus
  2. HTTP部分:
    • URL:填写完整的代理地址,如https://monitor.yourcompany.com/prometheus
    • Auth:开启Basic Auth
    • UserPassword:填写你在.htpasswd中设置的用户名和密码。
  3. 点击Save & Test。如果成功,会显示 “Data source is working”。

常见问题

  • 证书错误:如果使用自签名证书,Grafana 会报 SSL 错误。需要在数据源配置的TLS/SSL Auth部分,开启Skip TLS Verify(仅限测试环境)。生产环境请务必使用可信证书。
  • 路径错误:确保 Grafana 中配置的 URL 包含了 Nginx 中设置的路径前缀(如/prometheus)。

5.3 Prometheus 抓取配置(scrape_configs)的认证

如果你的 Prometheus 需要从同样需要认证的 exporter(如 Node Exporter with HTTPS)抓取数据,需要在prometheus.ymlscrape_configs中配置认证。

scrape_configs: - job_name: 'node' basic_auth: username: 'exporter_user' password: 'your_secure_password' tls_config: insecure_skip_verify: true # 谨慎使用,仅用于测试或内部自签名证书 static_configs: - targets: ['node-exporter-host:9100']

这里配置的是Prometheus(客户端)去访问exporter(服务端)时使用的认证,与前面讲的保护 Prometheus 自身(服务端)的认证是两回事,不要混淆。

5.4 性能与超时问题

当配置了反向代理和认证后,链路过长可能引入性能开销和超时风险。

  • 问题:在 Grafana 中加载一个跨度较大的仪表盘时,可能遇到 “504 Gateway Time-out” 错误。
  • 排查
    1. 检查 Nginx 错误日志:sudo tail -f /var/log/nginx/error.log
    2. 通常能看到upstream timed out相关记录。
  • 解决:在 Nginx 的location块中增加超时设置,如前面配置示例中的proxy_read_timeout 300;。这个值需要根据你的查询复杂度和数据量进行调整。同时,也可以考虑优化 PromQL 查询,避免全时间范围扫描。

5.5 系统服务与权限问题

  • SELinux/AppArmor:在开启了强制安全模块的系统上,Nginx 可能被禁止访问密码文件.htpasswd或代理到本地端口。可以通过审计日志排查,或临时设置为宽容模式测试。
  • 防火墙:确保 Nginx 的 443 端口对外部开放,同时确保 Prometheus 的 9090 端口仅对本地(127.0.0.1)或内部网络开放,不要暴露到公网。

6. 进阶考量与最佳实践建议

完成基础配置只是第一步,要让这套安全体系更健壮,还需要考虑以下几点。

6.1 认证方式的升级:从 Basic Auth 到 OAuth2

基础认证简单,但不够安全(密码每次请求都传输)也不便于管理(多服务需重复配置)。在生产环境中,更推荐使用 OAuth2 代理(如oauth2-proxy)或直接使用支持 OAuth2 的入口网关(如ingress-nginx的注解配置)。

其工作流程变为:用户访问 -> 网关重定向到身份提供商(如 Google, GitHub, 企业内部 SSO)登录 -> 登录成功后携带令牌访问 -> 网关验证令牌并转发请求给 Prometheus。这种方式用户体验更好,也更安全。

6.2 细粒度授权(RBAC)

基础认证或简单的 OAuth2 只解决了“你是谁”的问题,没有解决“你能做什么”。Prometheus 本身不支持基于角色的访问控制(RBAC)。如果你需要限制不同用户只能查看特定的监控数据(例如,开发团队只能看应用指标,运维团队才能看主机和数据库指标),目前需要借助更外层的方案:

  • 使用 Grafana 的数据源权限:在 Grafana 中可以为不同团队创建不同的数据源,每个数据源连接到一个经过过滤的 Prometheus 查询代理(如promxy或自建代理服务),该代理根据用户身份对 PromQL 查询进行改写或过滤。
  • 专门的监控门户:开发一个轻量级前端,集成认证,后端调用 Prometheus API 时根据用户角色注入不同的标签过滤条件。

6.3 配置管理与自动化

当你有成百上千个监控目标时,手动管理认证凭据是不现实的。

  • 密码/密钥管理:使用诸如 HashiCorp Vault、AWS Secrets Manager 等工具动态管理密码和 TLS 证书,并通过 sidecar 或 init container 注入到 Nginx 或 Prometheus 的容器中。
  • 配置即代码:将 Nginx 配置、Prometheus 的web-config.yml纳入 Git 版本控制,结合 CI/CD 流水线进行自动化部署和检查。
  • 在 Kubernetes 中的实践:在 K8s 中部署时,通常使用 Ingress 资源来配置反向代理和 TLS。认证可以通过 Ingress Annotations 集成oauth2-proxy或使用 Service Mesh(如 Istio)的授权策略来实现,管理起来更加云原生。

安全是一个持续的过程,而不是一次性的配置。给 Prometheus 加上认证和加密,是构建可靠监控体系的坚实第一步。从简单的 Nginx 反向代理开始,随着业务复杂度的提升,再逐步演进到更完善的统一认证授权体系,这是一个稳妥且实用的路径。