对于第三方集成grafana,需要可以通过链接直接访问管理界面,跳过登录页面。
传统方法是使用代理认证,而最新的jwt方法可以更好地实现这个需求。
不过网络上相关教程文档较少,缺乏详细说明,故此记录。
一 控制台/面板-分享
grafana本身支持面板的内嵌分享,见 https://grafana.com/docs/grafana/latest/dashboards/share-dashboards-panels
注意修改以下配置,这里以环境变量的写法表示:
domain需要填写外部访问的host
port这里也修改成非默认端口,建议直接修改端口号而不是反向代理形式来隐藏默认端口
下面两个是允许内嵌和允许匿名访问,是关键。
GF_SERVER_DOMAIN="192.168.10.192"
GF_SERVER_HTTP_PORT=33303
GF_SECURITY_ALLOW_EMBEDDING=true
GF_AUTH_ANONYMOUS_ENABLED=true
二 免登录访问
对于第三方集成grafana,需要可以通过链接直接访问管理界面,跳过登录页面。传统方法是使用代理认证,而最新的jwt方法可以更好地实现这个需求。
1 认证代理方式资料
传统的方法是使用认证代理(Auth Proxy),需和nginx、apache等集成,如:
- openresty: http://blog.helongfei.com/2019/%E4%BD%BF%E7%94%A8-openresty-%E5%AE%9E%E7%8E%B0-grafana-%E5%85%8D%E7%99%BB%E5%BD%95/
- java代理程序:https://blog.51cto.com/u_15127641/4530608
- apache:https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/auth-proxy/
2 jwt方式资料
- https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/jwt/
- https://github.com/grafana/grafana-iframe-oauth-sample
- https://www.cnblogs.com/yinxy/p/14893595.html
三 jwt免密访问步骤
1 获取jwks文件
访问 https://mkjwk.org/ ,参考如下值,keyId自行填写
将中间部分(含public、private的)保存为jwks.json文件,用于生成token。
右边的public key保存为jwks-public.json,用于对token进行认证。注意外围也要加上{"keys": [ ]}
,否则grafana会找不到keys。
2 启动grafana
这里以容器方式启动,注意,以下配置适用于9.3.2及以后版本
注意这里使用的是jwks-public.json
docker run \
-p 33303:33303 \
--user root \
--name my-grafana \
--restart=always \
--env GF_SERVER_DOMAIN="localhost" \
--env GF_SERVER_HTTP_PORT=33303 \
--env GF_SECURITY_ADMIN_PASSWORD="123456" \
--env GF_SECURITY_ALLOW_EMBEDDING=true \
--env GF_AUTH_ANONYMOUS_ENABLED=true \
--env GF_USERS_DEFAULT_THEME=light \
--env GF_AUTH_JWT_ENABLED=true \
--env GF_AUTH_JWT_ENABLE_LOGIN_TOKEN=true \
--env GF_AUTH_JWT_HEADER_NAME=GF-JWT \
--env GF_AUTH_JWT_USERNAME_CLAIM=sub \
--env GF_AUTH_JWT_EMAIL_CLAIM=sub \
--env GF_AUTH_JWT_JWK_SET_FILE='/home/jwks.json' \
--env GF_AUTH_JWT_CACHE_TTL=60m \
--env GF_AUTH_JWT_ROLE_ATTRIBUTE_PATH=role \
--env GF_AUTH_JWT_AUTO_SIGN_UP=true \
--env GF_AUTH_JWT_URL_LOGIN=true \
--env GF_AUTH_JWT_ALLOW_ASSIGN_GRAFANA_ADMIN=true \
--env GF_LOG_LEVEL=info \
-v /tmp/grafana:/var/lib/grafana \
-v /tmp/jwks-public.json:/home/jwks.json \
-d grafana/grafana
docker logs -f my-grafana
GF_AUTH_JWT_HEADER_NAME:token在header的名称,如果是在url中,则固定是auth_token
GF_AUTH_JWT_USERNAME_CLAIM:grafana将使用sub(即subject)字段作为用户名
GF_AUTH_JWT_ROLE_ATTRIBUTE_PATH:grafana将使用role字段作为用户角色
GF_AUTH_JWT_AUTO_SIGN_UP:新用户字段注册
3 生成token
如下,使用D:\tmp\jwks.json文件,生成用户名为user1,角色为Admin,有效期为1小时的token。
package jwk;
import cn.hutool.core.io.FileUtil;
import com.nimbusds.jose.*;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.mint.DefaultJWSMinter;
import com.nimbusds.jwt.JWTClaimsSet;
import org.junit.jupiter.api.Test;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;
public class JwtTest {
@Test
public void test() throws Exception {
System.out.println(getJwt());
}
public String getJwt() throws Exception {
JWKSet jwkSet = JWKSet.load(FileUtil.file("D:\\tmp\\jwks.json"));
DefaultJWSMinter minter = new DefaultJWSMinter();
minter.setJWKSource(new ImmutableJWKSet(jwkSet));
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256)
.type(JOSEObjectType.JWT)
.build();
// Create JWT
Instant nowInstant = Instant.now();
JWTClaimsSet jwtClaims = new JWTClaimsSet.Builder()
.subject("user2")
.expirationTime(new Date(nowInstant.plus(1, ChronoUnit.HOURS).toEpochMilli()))
.notBeforeTime(new Date(nowInstant.toEpochMilli()))
.issueTime(new Date(nowInstant.toEpochMilli()))
.build();
Payload payload = jwtClaims.toPayload();
Map<String, Object> payloadMap = payload.toJSONObject();
payloadMap.put("role", "Admin");
JWSObject jwsObject = minter.mint(header, new Payload(payloadMap), null);
return jwsObject.serialize();
}
}
生成的token可以在https://jwt.io/进行验证,如下
4 使用token进行访问
- url-token访问
http://grafana:33303/datasources?auth_token=YOUR_TOKEN - header访问
headers携带GF-JWT的token,内容为:Bearer YOUR_TOKEN
,注意中间有空格
Q.E.D.