grafana使用JWT
项目背景:
由于grafana的dashboard界面需要内嵌到自己的项目iframe中,而iframe又不能携带请求头这些进行登录访问,如果设置匿名登录就会造成无需密码就可以查看,对甲方来说这是一个严重漏洞,我就查阅了官方文档得出可以使用jwt进行url拼接token进行访问,由于官方文档具体流程不是很清晰,只讲述了配置,所以我这里记录一次从头到尾的实现jwt登录的操作。
我的版本:grafana version 10.2.2
这里附上官方文档地址:https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/jwt/
操作流程
-
生成私钥
openssl genrsa -out private.pem 2048
-
根据私钥生成公钥
openssl rsa -in private.pem -pubout -out public.pem
-
编写python代码,环境要有pyjwt,python3(python应该也可以,未尝试过)
pip install pyjwt vim jwtTest.py
import jwt import datetime # 读取私钥和公钥 with open('/Users/zhb/Documents/private.pem', 'r') as f: private_key = f.read() with open('/Users/zhb/Documents/public.pem', 'r') as f: public_key = f.read() # 需要传递的信息 payload = { 'iss': 'zhb', # 签发者 'iat': int(datetime.datetime.now().timestamp()), # 签发时间 'exp': int(datetime.datetime.now().timestamp()) + 3600, # 过期时间(一小时,可根据需求修改) 'sub': 'views'# 即用户名,注意不能写默认用户名admin } # 使用私钥生成JWT token = jwt.encode(payload, private_key, algorithm='RS256') print('Generated Token:', token) # 使用公钥验证JWT try: decoded = jwt.decode(token, public_key, algorithms=['RS256']) print('Decoded Token:', decoded) except jwt.ExpiredSignatureError: print('Token is expired') except jwt.InvalidTokenError as e: print('Token is invalid:', str(e))
-
运行代码
cd /usr/local/bin/ #python3执行程序安装完后一般在这个目录下 python3 /Users/xxx/Documents/jwtTest.py #运行该命令 #返回内容如下 Generated Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGIiLCJpYXQiOjE3MTEzNjA3MDUsImV4cCI6MTcxMTM5NjcwNSwic3ViIjoiYWRtaW4ifQ.MxpMQXRosMDOgTN5-KbIMbv-NlTv_ZPk-FPJ_WlQc5-Hz1nIXxhfSltLvf4O64BJBJ39vECzqtWRZE9EhqD6i9EOnQH7nA0ewxM8NTm3GUidBNU40DpLVDVQlyWw--GYLtf7Z0qjrDKFZFniQ3zx3aefWh-AAshN1PI9X7lBSugX8kQH0gNRvCuxgXtCacB3eczI_mQG3uBynCsCT8MAV096j-QpOxJZcPi-4gQC-kyv9wVWWo_ulyaHWTUPDcLZ_2iGFxsqTTErYYKI-r7sfnUUOJo7CUqRGpHJMA5hsu8XhJ_n6YmVeGGhD_0KdmamAyRJyVef2jmsALSoquNNlg Decoded Token: {'iss': 'zhb', 'iat': 1711360705, 'exp': 1711396705, 'sub': 'views'} ##我们只需要token的内容:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGIiLCJpYXQiOjE3MTEzNjA3MDUsImV4cCI6MTcxMTM5NjcwNSwic3ViIjoiYWRtaW4ifQ.MxpMQXRosMDOgTN5-KbIMbv-NlTv_ZPk-FPJ_WlQc5-Hz1nIXxhfSltLvf4O64BJBJ39vECzqtWRZE9EhqD6i9EOnQH7nA0ewxM8NTm3GUidBNU40DpLVDVQlyWw--GYLtf7Z0qjrDKFZFniQ3zx3aefWh-AAshN1PI9X7lBSugX8kQH0gNRvCuxgXtCacB3eczI_mQG3uBynCsCT8MAV096j-QpOxJZcPi-4gQC-kyv9wVWWo_ulyaHWTUPDcLZ_2iGFxsqTTErYYKI-r7sfnUUOJo7CUqRGpHJMA5hsu8XhJ_n6YmVeGGhD_0KdmamAyRJyVef2jmsALSoquNNlg
-
修改grafana的配置文件
[auth.anonymous] # 这个是匿名登录的配置,true代表允许,因为项目需求不允许匿名登录,所以这里不去修改了 ;enabled = false [users] # disable user signup / registration 这里要修改成true,使允许注册账号 allow_sign_up = true #################################### Auth JWT ########################## [auth.jwt] enabled = true header_name = X-JWT-Assertion #代表使用请求体中的sub的值来当做用户名 email_claim = sub ;username_claim = sub ;jwk_set_url = https://foo.bar/.well-known/jwks.json ;jwk_set_file = /path/to/jwks.json ;cache_ttl = 60m ;expect_claims = {"aud": ["foo", "bar"]} #需要把公钥的文件配置进去 key_file = /path/to/key/public.pem # Use in conjunction with key_file in case the JWT token's header specifies a key ID in "kid" field ;key_id = kid ;role_attribute_path = ;role_attribute_strict = false #这个为true代表用户名自动匹配,为匹配到就去注册 auto_sign_up = true #这个指标代表运行url中带token,不然这个token还是得写在请求头中 url_login = true ;allow_assign_grafana_admin = false
-
配置好后重新启动即可通过url进行访问
http://10.8.0.22:3000/d/fe1b2ab1-05f7-472b-86d0-123/linuxe4b8bb-e69cba-e79b91-e68ea7?orgId=1&auth_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGIiLCJpYXQiOjE3MTEzNjA3MDUsImV4cCI6MTcxMTM5NjcwNSwic3ViIjoiYWRtaW4ifQ.MxpMQXRosMDOgTN5-KbIMbv-NlTv_ZPk-FPJ_WlQc5-Hz1nIXxhfSltLvf4O64BJBJ39vECzqtWRZE9EhqD6i9EOnQH7nA0ewxM8NTm3GUidBNU40DpLVDVQlyWw--GYLtf7Z0qjrDKFZFniQ3zx3aefWh-AAshN1PI9X7lBSugX8kQH0gNRvCuxgXtCacB3eczI_mQG3uBynCsCT8MAV096j-QpOxJZcPi-4gQC-kyv9wVWWo_ulyaHWTUPDcLZ_2iGFxsqTTErYYKI-r7sfnUUOJo7CUqRGpHJMA5hsu8XhJ_n6YmVeGGhD_0KdmamAyRJyVef2jmsALSoquNNlg