利用envoy實現安全地在運維平臺顯示grafana圖表

前言

Grafana是一個跨平臺的開源的度量分析和可視化工具,能夠經過將採集的數據查詢而後可視化的展現,並及時通知。在實際的運維統一平臺中,常常須要將grafana的圖表集成進來。之因此不選擇本身利用echart本身實現,主要有如下兩個緣由:安全

  • grafana太強大了,在曲線比較密集的時候,依舊能夠保持高性能和良好的自適應。支持衆多的數據源。
  • 節省時間。不必重複造輪子。

通常來講,咱們的grafana是開啓了登陸驗證的,尤爲是對於一個企業而言,大多集成了ldap或是公司的統一身份體系。而集成的方法大可能是經過iframe。這種解決方案,會遇到登陸驗證的問題。用戶瀏覽grafana儀表板頁面的時候須要強制它們進行雙重驗證(一次用於個人網站,一次用於grafana)。這種體驗很是很差,咱們但願能夠只登陸一次。那你們可能首先想到了sso。對於不少開源項目來講,支持sso,可能須要定製開發,不只僅是grafana。
目前支持的是兩種方案:運維

  • 一個選項是enable anonymous access in grafana。這種能夠說安全性太差了。
  • 另一個使用代理。

今天咱們主要利用的是代理的思路去解決。dom

如何利用代理解決

咱們的整體需求是集成端不須要額外作過多的工做,讓代理完成basic auth。socket

grafana默認開啓了basic auth的認證,能夠經過修改grafana.ini 配置文件實現:工具

#################################### Basic Auth ##########################
; [auth.basic]
; ;enabled = true
;

固然認證的用戶必須是真實存在的,也就是須要提早在grafana中建立。這樣的好處是:咱們能夠給該用戶設置具體的權限,好比只具有瀏覽權限,並且能夠限定只能訪問某個文件夾下的圖表。性能

此外通常來講,相似grafana這種公司級別的產品,不會開啓外網訪問。
同時,也能夠在代理實現一些白名單的功能,好比辦公網的網段,就更加安全了。網站

整體相對來講,利用代理解決iframe 集成grafana強制登陸兩次的問題,
在安全上和操做性上,比較合適。lua

envoy的具體設置

咱們知道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必將大放光彩。

相關文章
相關標籤/搜索