Grafana Basic Auth 趟坑小记
迁移 Grafana
本来其实是一个非常简单的需求,我需要把自己一个很早以前手动用包管理器安装的 Grafana/InfluxDB 套件迁移到另一个主机上,并且改为纯 Docker 部署并且重新制作面板(丢掉之前的数据),因为不需要考虑之前的数据了,所以迁移流程非常简单,先做一个简单的 docker-compose.yml
文件,内容大概如下:
version: "3"
services:
influxdb:
image: influxdb
container_name: influxdb
ports:
- "192.168.1.3:8086:8086"
restart: always
volumes:
- ./data/influxdb:/var/lib/influxdb
grafana:
image: grafana/grafana
container_name: grafana
ports:
- "127.0.0.1:3000:3000"
restart: always
volumes:
- ./data/grafana:/var/lib/grafana
environment:
- GF_SERVER_DOMAIN=internal.yyyy.xxx
- GF_AUTH_DISABLE_LOGIN_FORM=false
- GF_SERVER_ROOT_URL=https://internal.yyyy.xxx/grafana/
- GF_SERVER_SERVE_FROM_SUB_PATH=true
关于底下的 environment ,可以参考 Configuration | Grafana Labs,简单来说就是,如果配置中是:
# default section
instance_name = ${HOSTNAME}
[security]
admin_user = admin
[auth.google]
client_secret = 0ldS3cretKey
[plugin.grafana-image-renderer]
rendering_ignore_https_errors = true
那么对应到环境变量上就是:
GF_DEFAULT_INSTANCE_NAME=my-instance
GF_SECURITY_ADMIN_USER=owner
GF_AUTH_GOOGLE_CLIENT_SECRET=newS3cretKey
GF_PLUGIN_GRAFANA_IMAGE_RENDERER_RENDERING_IGNORE_HTTPS_ERRORS=true
启动好容器之后就是一点 Nginx 的配置,大概是这样的:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /path/to/ssl.pem;
ssl_certificate_key /path/to/ssl.key;
server_name internal.yyy.xxx;
# 这里有个其他的服务,服务没有登录功能,需要用 Nginx 的 Basic Auth 保护一下
location /service-a {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/htpasswd;
proxy_pass http://192.168.1.7:8888;
}
location /grafana/ {
proxy_pass http://localhost:3000/;
}
}
看上去没有任何问题,然后访问一下 URL,就会看到:"invalid username or password"
啊这?我这还没输入密码呢?!
在继续前,大伙可以停下来,先根据上面的配置信息想想可能是哪儿出了问题.
Grafana 的验证方式
在看了一个看上去和我情况相似的 Issue 之后发现,在 User Authentication Overview,中,Grafana 支持多种验证方式,最常见的就是简单的用户名密码的方式,此外还有 SAML,LDAP 啥的:
但是如果足够细心往下看,就会发现有个叫 Basic authentication
的小节,内部是这样说明的:
Basic auth is enabled by default and works with the built in Grafana user password authentication system and LDAP authentication integration.
To disable basic auth:
[auth.basic] enabled = false
这个时候问题就已经比较明了了,由于这个 internal.yyyy.xxx
还反代了一个其他服务,也就是上文中的:
location /service-a {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/htpasswd;
proxy_pass http://192.168.1.7:8888;
}
正好我的浏览器之前有登录过那个服务,浏览器便给整个 internal.yyyy.xxx
域名的访问都加上了针对那个服务的 Authorization: Basic xxxxxxx
的 Header,正好 Nginx 把这个 Header 也传给了 Grafana,加上 Grafana 优先通过这个 Header 来验证用户,就有了上面那一出 "invalid username or password"
的问题了。
然后解决方法也比较明了了,只需要在 docker-compose.yml
的 Grafana 下环境变量中加入一条:
- GF_AUTH_BASIC_ENABLED=false
这样 Grafana 就不会关注那个不是给他看的 Header 了。
为这么个问题折腾了这么久,主要原因还是因为他(我)们(没)文(看)档(文)没(档)有写好,不应该不应该,记录此文,希望可以帮到其他可能在这里踩坑的同学。