Policy (政策)

政策! 是什麼東東 ?

提到政策,就會不小心想到治理、授權等等讓人頭皮發麻的詞。然而,政策在軟體服務中是相當常見的某種需求。簡單來說,軟體服務的政策是什麼呢?

一組管理軟體服務行為的規則。

舉凡,定義哪些是受信任的主機、使用者能夠存取哪些功能、網路路由、和服務可以部署到何處等,都能視為服務管理政策。所以當你試著實作 feature toggle、試著實作管理員和一般用戶等功能時,便已經涉及到服務政策的機制了。

傳統上的作法,工程師會在服務中實作相關的資料存取與檢查。先不論此類實作所耗費的額外運算資源,如果有多個團隊在實作多個服務,而都需要基於相同規則進行檢查時,要如何進行?如何能夠和服務管理政策管理者有更好的合作?落實管理政策與提供服務彼此之間如何不互相拉扯等待,而導致服務提供效率降低?

追根究柢,可以把問題濃縮成:

如何讓開發團隊專注在產品主功能開發,讓政策管理者能夠用一致的方法進行管理,而且兩者之間的更動不會輕易地影響對方?

Open Policy Agent 為這個問題提供了一個新的解決方式!

Open Policy Agent (OPA)

Open Policy Agent(OPA, 讀音為 歐趴) 最初是由 Styra 所建立,後來貢獻到 CNCF。目前由 Styra、Google、Microsoft、和 VMWare 構成開源專案的主要貢獻者團隊,撰文的當下它也已經順利地從 CNCF 畢業了。OPA 實現了一個輕量的政策管理服務,因此可以作為服務的 sidecar 運行,也能作為獨立的政策管理服務運行於整體服務群內。軟體服務可以基於給定的資訊透過 RESTful API 的方式「查詢」相關政策的判斷結果。此舉成功地解耦了政策管理的相關實作,讓軟體服務可以專注於使用者功能,至於政策則可以透過一個獨立的服務來實現。政策的管理者與資源的提供者,可以透過統一的管理服務來更新相關政策,從而改變團隊的合作模式,並且可以更高效且一致地施行政策。

政策判斷是如何構成與進行的呢?

進行一個政策的判斷是由三個要素所組成:

  1. 請求資料 (資料格式採用 JSON)
  2. 背景資料 (比方說,某某有哪些權限,資料格式採用 JSON)
  3. 判斷規則 (實際用於判斷的規則)

軟體服務以JSON的格式,將請求資料送入 OPA 所提供的 API,OPA 則透過預先定義好的背景資料和判斷規則,進行運算後返回。OPA 在資料方面採用單純的結構性資料,而在判斷規則上則定義了一個無關乎領域的新描述語言 Rego (讀音為 睿構)。此種設計為政策實作框架提供了極高的彈性,也使得操作者可以快速有效地實現各式各樣的政策。另外,透過如同程式撰寫一樣的方式來實現政策管理需求,讓政策的實現與管理可以基於軟體專案的最佳實踐來達成。

接著,讓我們透過一個簡單的例子來進一步了解 OPA 的運行與實作方式。

範例


組織為存取基礎設施資源定義了兩類角色,一個為 "admin",另一個則為 "user"。
admin : 具有創建、讀取、刪除的權限;
user : 具有讀取權限。

基礎設施的團隊有 Ethan 與 Leo 兩個人,Ethan 作為隊長擁有 admin 的角色權限,而 Leo 作為成員則僅有 user 的權限。

背景資料

OPA 是透過結構型的資料來構築政策判斷的背景資料,這類的資料可以分為 基礎 文本資料與 虛擬 文本資料。前者是具體被定義且既存的資訊,而後者則是經過對具體資訊的運算後,所構成的虛擬(僅存於記憶體中)資料。這個範例我們會建立兩個基礎文本資料,來作為範例的背景資料。一個用來定義角色與權限,另一個則用來定義誰是什麼角色,並且以 acl-set.json_與 members.json 進行儲存。

  • acl-set.json
{
    "admin":["create","read","delet"],
    "user":["read"]
}
  • members.json
{
    "Ethan":"admin",
    "Leo":"user"
}

除了預期為結構化資料外,OPA 並未定義背景資料的具體格式。因此,在定義背景資料時,團隊或者是組織應該對格式(如鍵值名稱)依實際的需要進行規範。

💡 規則運算時,需要讀出背景資料進行處理。因此保持格式的簡潔便十分地重要,別為難了自己。

規則實作

稍早之前的文章有提到,一個規則的判斷是由三個部分組成,除了背景資料外,就是規則與請求。別忘了,規則的運算是開展於外部請求的資料,因此,在實作規則之前,我們需要先定義請求資料的格式,方便規則實作時進行取用。如同背景資料一般,OPA 也並未對請求資料提供特殊的定義,因此,保持簡潔易取讀即可。

  • 請求資料的格式定義,對應的請求意義為 Ethan 對於基礎設施是否具有創建的權限
{
    "input": {
        "user" : "Ethan",
        "operation" : "create"
    }
}

所有的前置資訊都完成了,讓我們開始著手實作政策!政策實作將會以 my-policy.rego 儲存。

package controls.rbac

import data.team
import data.rules
import input

default allow = false

allow {
        role_of_user := team[input.user]
        ops := rules[role_of_user]
        ops[_] == input.operation
}

至此,已經完成了一個基於 RBAC 概念的簡單實作。趕緊來運行看看吧!

運行與查詢

步驟一:下載 OPA 執行檔,並且於本地端運行 OPA 服務

請基於運行的作業環境,到 OPA 的 Github Release Page 進行下載。本範例的運行環境為 Linux。鍵入以下指令,以便啟動 OPA 服務:

opa run --server

步驟二:匯入背景資料

背景資料的預期配置位置為 <服務位置>/v1/data/<預計的命名空間>。此範例會將acl-set.json匯入命名空間 rules 之下,而members.json則匯入 team 之下。

curl -X PUT http://localhost:8181/v1/data/rules --data-binary @acl-set.json
curl -X PUT http://localhost:8181/v1/data/team --data-binary @members.json

步驟三:匯入政策

政策的預期配置位置為 <服務位置>/v1/policies/<預計命名空間>。此範例會將my-policy.rego匯入 _mytestapi_之下。

curl -X PUT http://localhost:8181/v1/policies/mytestapi --data-binary @my-policy.rego

執行查詢

OPA 會按照匯入政策所屬的套件命名空間,將政策的查詢介面配置在 <服務位置>/v1/data/套/件/名/稱/政策。以本範例來說:

curl -X POST http://localhost:8181/v1/data/controls/rbac/allow --data-binary @input.json

💡 此處將前文所定義的請求資料內容,儲存為 input.json,以便進行查詢請求。

查詢結果如下:

{"result":"true"}

除了本地運行 OPA 服務來進行實作測試外,也能透過子指令 opa eval 或者是 opa run 來進行除錯與測試2,此處便不再詳述。

後記

筆者相當看好 Open Policy Agent 的發展前景,其輕量且獨立的特性,更有助於團隊間的協作與服務的開發。目前 OPA 也已經受許多知名企業(如 T-Mobile、Netflix、Pinterest等)所採用。由於這個系列的文章期望以一個完整的端到端應用範例作結,也希望透過最終的範例來展示安全與合規,如何透過工具來更有效率地完成。因此在系列文中介紹了稍後會用到 Open Policy Agent。

在可容受的範圍內提供最多的安全,將是讓自己服務「歐趴」的最短路徑。

💡 由於系列文章並非以 OPA 教學手冊作為目標,因此如果大家希望能夠看到更詳盡的教學,也可透過聯絡我們,告知我們。你的期待是我們最大的動力!😄


1. Open Policy Agent
2. Open Policy Agent 的操作簡介