OPA 進階-分散式利器 Bundle

newbmiao發表於2020-04-18

BundleOPA管理policydata的一種方式。

OPA實現的輕量級策略引擎,一開始就是為了雲原生環境的service提供解耦的策略服務,分散式是必然要考慮的問題。

Bundle api的設計中,其實就全面考慮並體現了在分散式應用中如何更好的解耦策略引擎的管理。

比如:

  • 如何做集中配置管理
  • 如何動態更新策略
  • 如何監控策略引擎節點的狀態以及決策日誌收集

有了這些功能,再加上其高效的策略描述語言RegoOPA才真正稱得上是雲原生時代的通用策略引擎

本文將帶大家簡單梳理一遍Bundle的組織方式、管理 api、及監控方式。

考慮到一次性過完不易消化,文末會提供一個直接可實操的docker-compose版本的demo,將全面覆蓋本文細節

建議大家看完本文,本機執行去體驗一下,會有更直觀的理解。

Bundle 檔案組織方式

下面我們先來看下Bundle的檔案組織方式

Bundle下的data,只能被識別data.jsondata.yaml的檔案, 而其上邊的目錄會作為其資料字首

如下邊roles/data.json (bundle/example作為一個bundle),會將data.json的資料掛在data.roles節點下

cd bundle/example
tree -a
.
├── .manifest
├── bindings
   └── data.json
├── main.rego
├── rbac.rego
└── roles
    └── data.json

其中.manifest檔案是Bundle的一個可選的後設資料(metadata)配置檔案

cat .manifest
{
  "revision" : "9f160bcd446bf50b1b17b570c322198a68d8e106",
  "roots": ["roles", "bindings","rbac","system"]
}

它的作用是宣告Bundle的版本revision及其下的路徑字首(roots: path prefix

roots不僅規定了Bundle應該有的路徑字首;在用Bundle api(後邊會提到)更新檔案時,也會按其規定的路徑字首來更新檔案

然後bundle也支援tarball格式載入到server

例如opa run -b的方式指定Bundle

cd bundle/example
tar -czf bundle.tar.gz .
opa run -b bundle.tar.gz

Tips: 關於如何在互動式命令列裡傳遞input。 之前非 bundle 使用 opa run quick-start repl.input:quick-start/input.json 到 bundle 格式時,就需要構建 repl/input/data.json 檔案格式作為輸入

具體可以用時參考文件bundle-file-format

opa server api

在瞭解Bundle支援的管理 api 前,我們先看下opa server api

主要 api 如下:

type 用途
Data api 查詢文件(能被輸出的規則、虛擬文件等)
Policy api 查詢策略
Query api 執行命令
Compile api 執行部分查詢計算(partial evaluate query
Health api 健康檢查
Metric api 指標統計(prometheus格式)

下面我們以文件查詢(Data)api 為例嘗試下:

我們先用之前quick-start的程式碼起一個opa sever

opa run --server quick-start

(注意:opa server api的路徑字首為/v1/, 對應的,查詢 api 路徑字首為/v1/data/,)

# 構造input輸出請求
cat <<EOF > v1-data-input.json
{
    "input": $(cat quick-start/input.json)
}
EOF
# 查詢 example_rbac
curl -s  http://0.0.0.0:8181/v1/data/example_rbac?pretty=true -d @v1-data-input.json

{
  "result": {
    "allow": true,
    "role_has_permission": [
      "widget-reader"
    ],
    "user_has_role": [
      "widget-reader"
    ]
  }
}

Tips:不指定路徑時,預設路徑為data.system.main,這時輸入不需要包裹在input key 內。 也可以使用--set--set-file 可以覆蓋配置檔案中的配置 opa run --server --set=default_decision=example_rbac/allow/ quick-start curl -s http://0.0.0.0:8181/ -d @quick-start/input.json

而且 Data 查詢也支援組合引數如explain,metrics,provenance等,詳細檢視文件,這裡就不展開了。

Bundle 管理 api

Bundle為了在分散式系統中更好的展現 OPA 的威力,提供了四種 Api:

  • Bundles 用於策略分發,可以定時輪訓更新Bundle
  • Decision Logs 定期上傳日誌包,支援按大小分片,開啟後會有日誌 id,決策日誌可追溯
  • Status 定期上傳服務狀態,包含metrics等資訊
  • Discovery 服務發現,可以用於集中管理OPABundle配置,各個節點下載定期同步配置後,按配置去更新Bundle

如下圖:

management api

這裡舉個帶註釋Bundle的四種介面配置例子

(先掃一遍留個印象,具體使用時檢視文件,後邊會提供可實操的程式碼)

# opa/config-bundle.yaml
services:
  # 定義服務,支援多個
  - name: example_bundle
    url: http://demo-server:8888/

labels:
  app: myapp

bundles:
  # 定義bundle, 支援多個
  authz:
    # bundle所處的服務
    service: example_bundle
    # 這裡指從resource處更新bundle檔案包,即:
    # http://demo-server:8888/bundle/rbac.tar.gz
    resource: bundle/rbac.tar.gz
    polling:
      # 300~600s間更新一次
      min_delay_seconds: 300
      max_delay_seconds: 600

decision_logs:
  service: example_bundle
  # partition_name為區分上傳地址,會跟到 /logs 後, 即:
  # http://demo-server:8888/logs/bundle
  # 注意上傳的是gzip日誌檔案
  partition_name: bundle
  reporting:
    min_delay_seconds: 30
    max_delay_seconds: 60

status:
  service: example_bundle
  # 即 http://demo-server:8888/status/bundle
  partition_name: bundle

# 預設查詢路徑
default_decision: rbac/allow

Bundle 整合方式

這裡我們簡單過下整合方式

opa server 方式

執行方式很簡單如下:

opa run -s -a 0.0.0.0:8181 -c opa/config-bundle.yaml

執行後,opa server 會根據配置自動拉取Bundle包:rbac.tar.gz

下載成功後啟動策略服務。同時定期上傳決策日誌和狀態給服務端(即:demo-server:8888

go lib 方式

使用 lib github.com/open-policy-agent/opa/rego整合

關鍵程式碼舉例如下:

// 構建查詢,PrepareForEval可重用
var err error
query, err := rego.New(
    rego.LoadBundle("./rbac.tar.gz"),
    rego.Query("x = data.rbac.allow"),
).PrepareForEval(context.Background())

// 執行查詢
results, err := query.Eval(context.Background(), rego.EvalInput(input))
if err != nil {
    fmt.Fatalln("Opa eval error:", err)
    return
} else if len(results) == 0 {
    fmt.Fatalln("Opa eval error: no result")
    return
}

fmt.Println("Opa result:", results[0].Expressions[0].Value)

具體組織方式官方推薦的有下邊集中式分散式這兩種:

host-local

distributed-enforcement

推薦感興趣的同學再去看下官方 go 整合的 demo: example-api-authz-go

Bundle 的監控

opa server 支援metrics, 而且是prometheus格式的

所以配合prometheus可以直接進行對其資料指標的監控,如下圖:

prometheus

再配合grafanadashbord可以更好的展示metrics資料,如下圖:

grafana

Bundle in action

上邊說這麼多,不實際試一下怎麼知道Bundle究竟如何呢?

這裡提供一個docker-compose版的 demo 給大家去本地驗證嘗試

裡邊提供了三種Bundle版本:

  • opa-bundle
  • opa-discovery
  • demo-sever (go lib 整合)

也提供了兩種版本的monitor

  • slim version
  • advance version

程式碼見:NewbMiao/opa-koans/bundle

裡邊有詳細的操作文件,有問題可以在 Repo 裡提 issue

這個 Repo 包含了這一系列的OPA教程,歡迎感興趣的同學 star 關注!

同時我在知乎也建了一個OPA 技術圈,也歡迎大家參與討論。

好了,到此,OPA的基本教程就結束了。後邊再抽空結合官方的例子寫些實戰教程吧。


最後附上一個 Repo 中驗證 Bundle 的過程,大家也可以從這裡開始嘗試哦

scripts/bundleVerify.sh


文章首發公眾號:newbmiao

推薦閱讀:OPA 系列

歡迎關注,獲取及時更新內容

更多原創文章乾貨分享,請關注公眾號
  • OPA 進階-分散式利器 Bundle
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章