注意:在我们深入下面的技术细节之前,我们想强调 Prometheus 作为一个监控系统,收集并提供关于其所监控系统的信息。因此,Prometheus 组件提供的 HTTP 端点不应暴露在可公开访问的网络(如互联网)上(除非你知道自己在做什么并采取了适当的措施)。这包括(但不限于)已检测二进制文件的 /metrics 端点、服务器组件的各种 API 端点,以及用 Go 实现的服务器组件的 /pprof 端点。此外,对这些端点的请求很容易导致服务器过载并最终遭受 DoS 攻击。
Prometheus 是一个复杂的系统,拥有许多组件和与其他系统的众多集成。它可以部署在各种受信任和不受信任的环境中。
本页描述了 Prometheus 的一般安全假设以及某些配置可能带来的攻击向量。
与任何复杂系统一样,几乎可以肯定会发现漏洞,其中一些与安全相关。
对于已经公开披露的_安全漏洞_(例如通过公开的 CVE)且需要的不仅仅是依赖版本升级来修复的,请打开一个Bug 报告并包含所有相关详情,除非已经有人提交了。
如果你发现了一个尚未公开披露的_安全漏洞_,请私下报告给相关仓库的 MAINTAINERS 中列出的维护者,并抄送 prometheus-team@googlegroups.com。我们会尽快修复问题并与你协调发布日期。你可以选择是否希望公开致谢你的贡献以及是否希望提及你的姓名。
大多数依赖版本更新会自动处理。但是,如果一个_安全漏洞_修复只需要更新依赖版本而我们的自动化遗漏了,欢迎直接提交更新。
自动化安全扫描器
安全扫描器用户的特别说明:请对扫描生成的报告保持谨慎。大多数扫描器是通用的,会产生大量误报。越来越多的报告被发送给我们,逐一检查并按你期望的方式认真回复需要大量工作。这个问题在 Go 和 NPM 依赖扫描器中尤为严重。
作为对我们和我们时间的尊重,我们请你不要提交原始报告。相反,请提交报告时附上分析,说明哪些具体结果适用于我们以及原因。
另请注意,作为一个开源项目,我们通常无法访问商业扫描工具,且发现它们的输出经常具有误导性或完全错误。对于 Go 代码,如果你的报告无法通过开源的 govulncheck 工具在你认为受影响版本的源代码上复现(不是二进制文件,因为那无法进行完整分析),那么我们请你三重检查你的发现(包括该代码是否确实从 Prometheus 代码库中可达)。
Prometheus 由志愿者维护,不是由公司维护。因此,修复安全问题是在尽力而为的基础上进行的。我们努力在 7 天内发布安全修复,涉及的项目包括:Prometheus、Alertmanager、Node Exporter、Blackbox Exporter 和 Pushgateway。
Prometheus
假定不受信任的用户可以访问 Prometheus 的 HTTP 端点和日志。他们可以访问数据库中包含的所有时间序列信息,以及各种运维/调试信息。
同样假定只有受信任的用户才有能力更改 Prometheus 和其他组件的命令行、配置文件、规则文件和运行时环境的其他方面。
Prometheus 抓取哪些目标、多久抓取一次以及使用什么其他设置完全由配置文件决定。管理员可以决定使用来自服务发现系统的信息,这与重新标记相结合可能会将部分控制权授予能够修改该服务发现系统中数据的任何人。
被抓取的目标可能由不受信任的用户运行。默认情况下,目标不应该能够暴露冒充不同目标的数据。honor_labels 选项会移除此保护,某些重新标记设置也会如此。
从 Prometheus 2.0 起,--web.enable-admin-api 标志控制对管理 HTTP API 的访问,该 API 包括删除时间序列等功能。默认情况下此功能是禁用的。如果启用,管理和变更功能将在 /api/*/admin/ 路径下可访问。--web.enable-lifecycle 标志控制 Prometheus 的 HTTP 重新加载和关闭。此功能默认也是禁用的。如果启用,它们将在 /-/reload 和 /-/quit 路径下可访问。
在 Prometheus 1.x 中,/-/reload 和在 /api/v1/series 上使用 DELETE 对任何可以访问 HTTP API 的人都是可用的。/-/quit 端点默认禁用,但可以通过 -web.enable-remote-shutdown 标志启用。
远程读取功能允许任何具有 HTTP 访问权限的人向远程读取端点发送查询。例如,如果 PromQL 查询最终直接在关系数据库上运行,那么任何能够向 Prometheus 发送查询的人(例如通过 Grafana)都可以对该数据库运行任意 SQL。
Alertmanager
任何可以访问 Alertmanager HTTP 端点的用户都可以访问其数据。他们可以创建和解除告警。他们可以创建、修改和删除静默规则。
通知发送到哪里由配置文件决定。在某些模板配置下,通知可能会发送到告警定义的目标。例如,如果通知使用告警标签作为目标电子邮件地址,那么任何能够向 Alertmanager 发送告警的人都可以向任意电子邮件地址发送通知。如果告警定义的目标是可模板化的密钥字段,任何可以访问 Prometheus 或 Alertmanager 的人都将能够查看密钥。
任何可模板化的密钥字段都是为了上述用例中的通知路由而设计的。它们不是将密钥与配置文件分离的方式(使用模板文件功能)。存储在模板文件中的任何密钥都可能被能够在 Alertmanager 配置文件中配置接收器的任何人窃取。例如在大型部署中,每个团队可能有一个他们完全控制的 Alertmanager 配置文件片段,然后这些片段被组合成完整的最终配置文件。
Pushgateway
任何可以访问 Pushgateway HTTP 端点的用户都可以创建、修改和删除其中包含的指标。由于 Pushgateway 通常在启用 honor_labels 的情况下被抓取,这意味着任何可以访问 Pushgateway 的人都可以在 Prometheus 中创建任意时间序列。
--web.enable-admin-api 标志控制对管理 HTTP API 的访问,该 API 包括擦除所有现有指标组等功能。默认情况下此功能是禁用的。如果启用,管理功能将在 /api/*/admin/ 路径下可访问。
Exporter
Exporter 通常只与一个配置好的实例通信,使用预设的命令/请求集,这些不能通过其 HTTP 端点扩展。
也有像 SNMP 和 Blackbox exporter 这样从 URL 参数获取目标的 exporter。因此,任何对这些 exporter 具有 HTTP 访问权限的人都可以让它们向任意端点发送请求。由于它们还支持客户端认证,这可能导致密钥泄露,例如 HTTP Basic Auth 密码或 SNMP 社区字符串。挑战-响应认证机制(如 TLS)不受此影响。
客户端库
客户端库旨在包含在用户的应用程序中。
如果使用客户端库提供的 HTTP 处理器,到达该处理器的恶意请求不应该导致除额外负载和失败抓取之外的问题。
认证、授权和加密
Prometheus 和大多数 exporter 支持 TLS,包括通过 TLS 客户端证书进行客户端认证。关于配置 Prometheus 的详情请参阅此处。
Go 项目共享相同的 TLS 库,基于 Go 的 crypto/tls 库。我们默认 TLS 1.2 作为最低版本。我们的策略基于 Qualys SSL Labs 的建议,我们力求在默认配置和正确提供的证书下达到 'A' 级评分,同时在完美安全性和可用性之间取得平衡,并尽可能贴近上游 Go 的默认设置。
TLS 将来会被添加到 Java exporter 中。
如果你有特殊的 TLS 需求,如不同的密码套件或较旧的 TLS 版本,你可以调整最低 TLS 版本和密码,只要密码没有被 crypto/tls 库标记为不安全。如果这仍然不能满足你,当前的 TLS 设置使你能够在服务器和具有更特殊需求的反向代理之间构建安全隧道。
也支持 HTTP Basic 认证。Basic 认证可以不配合 TLS 使用,但那样会在网络上以明文暴露用户名和密码。
在服务器端,Basic 认证密码以 bcrypt 算法的哈希值存储。选择匹配你安全标准的轮数是你的责任。更多的轮数会使暴力破解更困难,但代价是更多的 CPU 消耗和更长的请求认证时间。
各种 Prometheus 组件支持客户端认证和加密。如果提供了 TLS 客户端支持,通常还有一个名为 insecure_skip_verify 的选项用于跳过 SSL 验证。
API 安全
由于管理和变更端点旨在通过 cURL 等简单工具访问,因此没有内置的 CSRF 保护,因为这会破坏此类用例。因此在使用反向代理时,你可能希望阻止此类路径以防止 CSRF。
对于非变更端点,你可能希望在反向代理中设置 CORS 头,如 Access-Control-Allow-Origin,以防止 XSS。
如果你正在构建包含来自不受信任用户输入的 PromQL 查询(例如控制台模板的 URL 参数,或你自己构建的内容),且这些用户不应该能够运行任意 PromQL 查询,请确保任何不受信任的输入都经过适当的转义以防止注入攻击。例如 up{job="<user_input>"} 如果 <user_input> 是 "} or some_metric{zzz=",就会变成 up{job=""} or some_metric{zzz=""}。
对于使用 Grafana 的用户,请注意仪表板权限不等于数据源权限,因此在代理模式下不会限制用户运行任意查询的能力。
密钥
非密钥信息或字段可能通过 HTTP API 和/或日志获取。
在 Prometheus 中,从服务发现获取的元数据不被视为密钥。在整个 Prometheus 系统中,指标不被视为密钥。
配置文件中包含密钥的字段(在文档中明确标记为密钥)不会在日志或 HTTP API 中暴露。密钥不应该放在其他配置字段中,因为组件通常会通过其 HTTP 端点暴露其配置。保护磁盘上的文件不被未授权读写是用户的责任。
依赖项使用的来自其他来源的密钥(例如 EC2 服务发现使用的 AWS_SECRET_KEY 环境变量)可能由于我们控制之外的代码或恰好暴露其存储位置的功能而被暴露。
拒绝服务
对于过载或昂贵的查询有一些缓解措施。但是,如果提供了过多或过于昂贵的查询/指标,组件将会崩溃。受信任的用户意外导致组件崩溃的可能性比恶意行为更高。
确保为组件提供足够的资源(包括 CPU、RAM、磁盘空间、IOPS、文件描述符和带宽)是用户的责任。
建议监控所有组件的故障情况,并使其在故障时自动重启。
库
本文档考虑的是从标准源代码构建的原版二进制文件。如果你修改了 Prometheus 源代码,或在你自己的代码中使用了 Prometheus 内部实现(超出官方客户端库 API 的范围),此处呈现的信息不适用。
构建过程
Prometheus 的构建管道运行在第三方提供商上,Prometheus 开发团队的许多成员和这些提供商的工作人员都有访问权限。如果你关心二进制文件的确切来源,建议你自己构建它们,而不是依赖项目提供的预构建二进制文件。
Prometheus-Community
Prometheus-Community 组织下的仓库由第三方维护者支持。
如果你在 Prometheus-Community 组织中发现了_安全漏洞_,请私下报告给相关仓库的 MAINTAINERS 中列出的维护者,并抄送 prometheus-team@googlegroups.com。
该组织下的一些仓库可能具有与本文档中呈现的不同的安全模型。在这种情况下,请参阅这些仓库的文档。