1. 为什么你的Prometheus需要一道“门”?
最近在帮一个朋友的公司做监控系统迁移,他们之前用的Prometheus一直是“裸奔”状态,直接暴露在公网上,谁都能访问9090端口,看到所有的监控指标。结果你猜怎么着?有一天他们发现CPU使用率监控图里,多了一堆完全不认识的服务器名字,内存使用量也高得离谱。一查,好家伙,不知道被哪个“热心网友”当成了公开的监控面板,往里塞了自己的数据。这事儿虽然没造成直接的数据泄露,但也够吓人的,万一有人手滑执行了/api/v1/admin/tsdb/delete_series这种危险操作,历史监控数据可就全没了。
所以啊,给Prometheus加上登录认证,就跟给你家大门装把锁一样,不是可有可无的“高级功能”,而是最基本的安全底线。尤其是现在很多公司都把监控部署在云上,或者内网边界比较模糊,一个没有认证的Prometheus,就像在闹市区开着一扇没锁的保险柜门。我们今天要聊的,就是怎么用最经典、也最稳妥的“基础认证”(Basic Auth),给Prometheus装上这把锁。整个过程不复杂,核心就是三件事:用bcrypt把密码加密成“乱码”、写一个叫web.yml的“锁芯说明书”、最后用promtool这把“钥匙”试试锁芯灵不灵。跟着我一步步走,半小时内绝对搞定,让你睡个安稳觉。
2. 密码不能“裸奔”:深入理解bcrypt加密
说到设置密码,很多新手的第一反应可能是:“我在web.yml里直接写admin: mypassword123不就行了?” 兄弟,这可就踩了大坑了。想象一下,你把保险柜的密码,用粉笔写在保险柜旁边墙上,这锁装了跟没装有啥区别?Prometheus的配置文件通常是跟着代码一起走版本控制的(比如Git),要是明文密码被提交上去,基本上就等于全网广播了。所以,我们必须把密码“打乱”,变成一堆谁也看不懂的字符,这个过程就叫哈希(Hash)。
为什么偏偏是bcrypt,而不是MD5或者SHA-256呢?这里有个关键点:防“彩虹表”攻击。简单说,“彩虹表”就是坏人预先算好的、海量明文和其对应哈希值的对照表。如果你的密码是123456,用MD5算出来的哈希值是固定的(比如e10adc3949ba59abbe56e057f20f883e),坏人只需要在他的巨型“字典”里查一下这个哈希值,瞬间就能反推出你的原始密码。MD5和SHA-256这类算法速度太快了,专门为计算哈希设计的显卡(比如矿卡)一秒钟能算上百亿次,暴力破解起来非常吓人。
bcrypt的聪明之处在于,它天生就“慢”。它引入了一个叫“工作因子”(work factor)的概念,你可以理解为加密的“难度系数”。这个因子值越大,加密一次所需要的时间和计算资源就越多。比如我常用的因子是12,在我的开发机上加密一个密码大概需要0.3秒。这个时间对人来说就是一眨眼,但对想要暴力破解的坏人来说,成本就高到无法承受了——他尝试一个密码就要0.3秒,尝试一万个就得将近一个小时。而且,即使两个人的明文密码一模一样,由于bcrypt在加密过程中会加入随机的“盐值”(salt),最终生成的哈希字符串也是完全不同的,这彻底废掉了“彩虹表”攻击。所以,在安全界,bcrypt是存储密码的黄金标准之一。
2.1 手把手生成你的第一个bcrypt哈希密码
理论说完了,咱们动动手。生成bcrypt哈希密码,我最推荐用Python,因为几乎每台Linux服务器上都有它,而且代码简单明了。
首先,确保你的环境有pip3和python3。然后,安装我们需要的bcrypt库:
# 通常系统自带的pip3就可以
pip3 install bcrypt
如果提示权限问题,可以加上--user参数安装到用户目录:
pip3 install bcrypt --user
安装成功后,我们不用写复杂的脚本,直接在Python交互式命令行里操作就行,更直观:
python3
进入Python环境后,输入以下代码(你可以直接复制粘贴):
import bcrypt
import getpass
# 安全地输入密码,屏幕上不会显示
password = getpass.getpass("请输入你要为Prometheus设置的密码: ")
# 使用bcrypt进行哈希加密,gensalt()默认的rounds(工作因子)是12,安全性足够
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
# 将字节类型的哈希值转换为字符串,并打印出来
print("生成的bcrypt哈希密码是:")
print(hashed_password.decode('utf-8'))
操作过程看起来是这样的:
$ python3
>>> (执行上面的代码)
请输入你要为Prometheus设置的密码: (你输入密码,屏幕无回显)
生成的bcrypt哈希密码是:
$2b$12$NQIRqy66j6Mk4OSJ7njM5ORpuSFl.mWHCWZjHp.pu..M4Ns7cnHW6
请务必完整复制最后打印出来的那一长串字符,比如上面的$2b$12$NQIRqy66j6Mk4OSJ7njM5ORpuSFl.mWHCWZjHp.pu..M4Ns7cnHW6。它就是你的密码“化身”,我们接下来要把它放进配置文件。这个字符串的格式是有讲究的:$2b$表示使用的是bcrypt算法;12$表示工作因子是12;后面那一大串就是“盐值”和最终的哈希值混合体了。
3. 编写安全认证的“心脏”:web.yml配置文件
拿到了加密后的密码,我们就可以来配置Prometheus的“门卫”——web.yml文件了。这个文件是Prometheus专门用来配置Web UI和API相关安全性的。它需要和你的prometheus.yml主配置文件放在同一个目录下(通常是/etc/prometheus/或你自定义的数据目录)。
我们用vim(或你喜欢的任何编辑器)创建并编辑这个文件:
sudo vim /etc/prometheus/web.yml
文件内容非常简单,核心就是一个basic_auth_users的映射结构:
basic_auth_users:
admin: $2b$12$NQIRqy66j6Mk4OSJ7njM5ORpuSFl.mWHCWZjHp.pu..M4Ns7cnHW6
viewer: $2b$12$8RuGmPzOeA7k5B6lY9qZQuYQe9cK1jJp8nLm2VvCwzN3oPxRyHsTd
我来解释一下这个YAML格式:
basic_auth_users:这是固定的根键,告诉Prometheus这里要配置基础认证的用户。- 下面的每一行就是一个用户,格式是
用户名: 加密后的密码哈希。 - 我上面配置了两个用户:
admin和viewer。在实际项目中,我强烈建议你至少分两个角色:一个高权限的admin用户,用于修改配置、管理TSDB等;一个只读的viewer或readonly用户,给日常需要看监控图表但不需要操作的人用。这样即使viewer用户的密码不小心泄露了,风险也是可控的。
这里有几个我踩过坑的注意事项:
- 缩进问题:YAML对缩进非常敏感。
admin:那一行必须比basic_auth_users:缩进两个空格(或者一个Tab,但我强烈建议用空格,避免跨编辑器解析问题)。用户名后面的哈希值,直接跟在冒号和空格后面就行。 - 哈希值完整性:从Python里复制出来的哈希值,一定要确保完整、没有换行、开头结尾没有多余空格。一个字符错了,认证就会失败。最稳妥的方法是,复制后先粘贴到一个文本编辑器里确认一下,再粘贴到配置文件中。
- 文件权限:这个文件里虽然存的不是明文密码,但也是关键的安全配置。建议把它的权限设置为仅限root和Prometheus进程用户可读:
sudo chmod 640 /etc/prometheus/web.yml sudo chown prometheus:prometheus /etc/prometheus/web.yml # 假设你的Prometheus运行用户是prometheus
4. 开工前的“安全演习”:用promtool验证配置
配置文件写好了,先别急着重启Prometheus!直接重启万一配置有语法错误,可能导致服务起不来,监控就中断了。Prometheus非常贴心地提供了一个神器——promtool。它是Prometheus官方发行版里自带的一个命令行工具,就在和prometheus主程序同一个目录下。我们可以用它来对web.yml做一次“语法体检”。
验证命令非常简单:
# 假设你的promtool和web.yml都在/etc/prometheus/目录下
cd /etc/prometheus
sudo ./promtool check web-config web.yml
如果一切正确,你会看到一个令人安心的输出:
web.yml SUCCESS
这个SUCCESS意味着两件事:第一,你的YAML语法完全正确;第二,Prometheus能识别basic_auth_users这个配置结构。但这里有个重要提示:promtool check web-config 并不会去验证你提供的bcrypt哈希字符串本身是否有效。它只检查格式。也就是说,哪怕你胡乱写一串字符放在admin:后面,只要符合YAML语法,它也会返回SUCCESS。
那怎么确认哈希值本身没问题呢?我们可以写一个简单的Python脚本做反向验证,当然,更直接的办法是,在下一步配置好Prometheus并重启后,用浏览器实际登录一下,这是最终的验收测试。不过,在重启服务前,用promtool检查一遍,能排除掉99%的低级语法错误,比如缩进不对、冒号写成中文冒号等,已经能避免大部分启动失败了。
5. 让Prometheus“认领”你的安全配置
好了,锁芯(web.yml)造好了,也初步检查过了,现在得告诉Prometheus这位“门卫”去使用这个新锁芯。这就需要修改Prometheus的启动参数。
如果你是用Systemd管理的Prometheus服务(现在绝大多数Linux发行版都是),那么需要修改它的service文件。文件通常在这里:/etc/systemd/system/prometheus.service 或者 /lib/systemd/system/prometheus.service。
用编辑器打开它:
sudo vim /etc/systemd/system/prometheus.service
找到ExecStart这一行,它定义了Prometheus的启动命令。通常它长这样:
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus/data \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries
我们需要在最后面加上我们的新参数 --web.config.file,指向刚才创建的web.yml文件。修改后像这样:
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus/data \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.config.file=/etc/prometheus/web.yml
注意:每一行结尾的 \ 是换行连接符,表示下一行还是同一个命令的一部分。最后一行参数后面不要加 \。
修改完成后,需要让Systemd重新加载配置,然后重启Prometheus服务:
# 重新加载systemd配置,使其识别service文件的更改
sudo systemctl daemon-reload
# 重启prometheus服务
sudo systemctl restart prometheus
# 查看服务状态,确认没有报错,正常启动
sudo systemctl status prometheus
看到状态显示为active (running),并且下面的日志没有红色的error字样,就说明服务带着新的认证配置成功启动了。
6. 验收成果:登录你的安全监控面板
现在,打开你的浏览器,访问Prometheus的地址(通常是 http://你的服务器IP:9090)。如果之前能直接打开,现在你会看到一个熟悉的HTTP基础认证弹窗,或者浏览器自带的登录框,要求你输入用户名和密码。
输入你在web.yml里设置的用户名(比如admin)和对应的原始明文密码(注意,不是那一长串哈希值!),点击登录。如果密码正确,你就会顺利进入Prometheus的Web界面,一切功能和之前一模一样。
这里有个小技巧:现代浏览器在你成功登录一次后,通常会缓存这个认证信息。如果你想测试另一个用户(比如viewer),或者想体验一下登录失败的效果,需要关闭所有标签页并重新打开浏览器,或者使用浏览器的“无痕模式”进行测试。
登录成功后,你可以顺便检查一下,之前配置的Alertmanager、Grafana数据源等需要连接Prometheus API的服务是否还正常。因为这些服务在连接时,也需要提供用户名和密码了。以Grafana添加Prometheus数据源为例,在配置页面你会看到“Auth”部分,打开“Basic Auth”开关,然后填写你刚刚设置的viewer用户的用户名和密码即可。这样,Grafana就能带着认证信息去拉取监控数据了。
7. 进阶与排坑:你可能遇到的几个问题
实战中,很少有一次就完美成功的,总会遇到些小波折。我把几个常见的问题和解决办法列出来,你可以提前有个心理准备。
问题一:重启Prometheus失败,日志报错 error loading web config: yaml: unmarshal errors...
这几乎肯定是web.yml的YAML语法错误。别慌,再用promtool check web-config仔细检查一遍。最常见的错误是缩进用了Tab键,请全部换成空格。还有一个隐蔽的错误是,bcrypt哈希值里可能包含YAML的特殊字符(比如冒号),如果哈希值没有用引号括起来可能会被误解析。保险起见,可以给哈希值加上单引号:
basic_auth_users:
admin: '$2b$12$NQIRqy66j6Mk4OSJ7njM5ORpuSFl.mWHCWZjHp.pu..M4Ns7cnHW6'
问题二:能弹出登录框,但密码始终错误 首先,百分之百确认你输入的是原始明文密码,而不是哈希值。其次,检查生成哈希值时输入的密码,和现在尝试登录的密码是否完全一致,包括大小写和首尾空格。最彻底的排查方法是写一个验证脚本:
import bcrypt
# 这是你尝试登录的密码
attempt_password = "你的密码".encode('utf-8')
# 这是web.yml里存储的哈希字符串
stored_hash = "$2b$12$NQIRqy66j6Mk4OSJ7njM5ORpuSFl.mWHCWZjHp.pu..M4Ns7cnHW6".encode('utf-8')
# 用bcrypt检查是否匹配
if bcrypt.checkpw(attempt_password, stored_hash):
print("密码正确!")
else:
print("密码错误。")
运行这个脚本,就能明确知道是密码记错了,还是哈希值复制粘贴时出了问题。
问题三:其他服务(如Node Exporter)无法被Prometheus抓取了
这是个好问题!我们只给Prometheus自己的Web界面加了认证,但Prometheus去抓取其他Exporter(目标)的HTTP连接,默认是不带认证的。如果那些Exporter也配置了HTTP基础认证,那么你需要在Prometheus的prometheus.yml文件里的scrape_configs中,为每个需要认证的job单独配置basic_auth。例如:
scrape_configs:
- job_name: 'node'
basic_auth:
username: 'prometheus_scraper' # Exporter上设置的用户名
password: 'scraper_password' # Exporter上设置的密码(明文,这里只能写明文)
static_configs:
- targets: ['localhost:9100']
注意,这里的password字段是明文,因为Prometheus需要用这个明文去和Exporter进行认证握手。因此,要确保这个prometheus.yml文件本身也有严格的权限控制。
问题四:想添加或修改用户怎么办?
很简单,分三步:1. 用同样的bcrypt方法生成新密码的哈希值。2. 编辑web.yml,添加新行或修改现有用户的哈希值。3. 重启Prometheus服务 (sudo systemctl restart prometheus)。无需修改Systemd的service文件,除非web.yml的路径变了。
走完这一整套流程,你的Prometheus就从“门户大开”变成了“戒备森严”。这套基础认证方案虽然简单,但结合bcrypt的强哈希和HTTPS(强烈建议在生产环境为Prometheus也配置SSL/TLS),足以应对绝大多数内部监控场景的安全需求。安全这件事,永远是“防患于未然”的成本,远低于“亡羊补牢”的代价。花上半个小时,换来监控数据的安心,这笔时间投资绝对划算。
377



被折叠的 条评论
为什么被折叠?



