Grafana是一个跨平台的开源的度量分析和可视化工具,能够经过将采集的数据查询而后可视化的展现,并及时通知。在实际的运维统一平台中,常常须要将grafana的图表集成进来。之因此不选择本身利用echart本身实现,主要有如下两个缘由:安全
通常来讲,咱们的grafana是开启了登陆验证的,尤为是对于一个企业而言,大多集成了ldap或是公司的统一身份体系。而集成的方法大可能是经过iframe。这种解决方案,会遇到登陆验证的问题。用户浏览grafana仪表板页面的时候须要强制它们进行双重验证(一次用于个人网站,一次用于grafana)。这种体验很是很差,咱们但愿能够只登陆一次。那你们可能首先想到了sso。对于不少开源项目来讲,支持sso,可能须要定制开发,不只仅是grafana。
目前支持的是两种方案:运维
今天咱们主要利用的是代理的思路去解决。dom
咱们的整体需求是集成端不须要额外作过多的工做,让代理完成basic auth。socket
grafana默认开启了basic auth的认证,能够经过修改grafana.ini 配置文件实现:工具
#################################### Basic Auth ########################## ; [auth.basic] ; ;enabled = true ;
固然认证的用户必须是真实存在的,也就是须要提早在grafana中建立。这样的好处是:咱们能够给该用户设置具体的权限,好比只具有浏览权限,并且能够限定只能访问某个文件夹下的图表。性能
此外通常来讲,相似grafana这种公司级别的产品,不会开启外网访问。
同时,也能够在代理实现一些白名单的功能,好比办公网的网段,就更加安全了。网站
整体相对来讲,利用代理解决iframe 集成grafana强制登陆两次的问题,
在安全上和操做性上,比较合适。lua
咱们知道http 的basic auth 实际上是相对简单的一种认证方式。Authorization请求首部中,包含了用户填写的用户名、密码。插件
GET /protected_docs HTTP/1.1 Authorization: Basic Y2h5aW5ncDoxMjM0NTY=
其中 Y2h5aW5ncDoxMjM0NTY= 是 base64(用户名:密码)。代理
envoy 并无提供相似的filter。可是envoy支持了lua编写filter。因此这个问题就变得很简单了,编写basic auth filter。此时想到openresty。那么利用openresty也能够实现。
直接上envoy.yaml:
static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 80 filter_chains: - filters: - name: envoy.http_connection_manager config: codec_type: auto stat_prefix: ingress_http access_log: - name: envoy.file_access_log config: path: "/dev/stdout" format: "[ACCESS_LOG][%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\" \"%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%\"\n" route_config: name: local_route virtual_hosts: - name: gateway domains: - "*" routes: - match: prefix: "/" route: cluster: grafana retry_policy: retry_on: "5xx" num_retries: 2 http_filters: - name: envoy.lua config: inline_code: | function envoy_on_request(request_handle) request_handle:headers():add("Authorization", "Basic Z2FvaGo6bG92ZioxMzE0") end - name: envoy.router config: {} clusters: - name: grafana connect_timeout: 0.5s type: strict_dns lb_policy: round_robin hosts: - socket_address: address: grafana.xxx.com port_value: 80 admin: access_log_path: "/dev/null" address: socket_address: address: 0.0.0.0 port_value: 90
你们注意看envoy.lua处配置。
大体上利用 envoy_on_request方法,对请求添加 Authorization 头。
详细请参考envoy官方docs。
这里简单说下,其实envoy的lua 插件,能够对request和response作拦截处理。以下:
-- Called on the request path. function envoy_on_request(request_handle) -- Wait for the entire request body and add a request header with the body size. request_handle:headers():add("request_body_size", request_handle:body():length()) end -- Called on the response path. function envoy_on_response(response_handle) -- Wait for the entire response body and a response header with the the body size. response_handle:headers():add("response_body_size", response_handle:body():length()) -- Remove a response header named 'foo' response_handle:headers():remove("foo") end
那么实现其余的扩展功能,也很容易了。
其实envoy很快将支持经过Web Assembly 来扩展,wasm性能更高,能够利用rust,c,go等语言编写逻辑,而后编译成机器码执行。届时envoy必将大放光彩。