Kong 閘道器 是一個開源的 API 閘道器,它確保只有正確的請求被接纳,同時管理等安全、速率限制、記錄等功能。 OPA (開源策略代理) 是一個開源策略引擎,它掌控你的安全和訪問決策。你可以把它想像成將策略實施與你的應用程序解耦的思維,所以你的服務不需要擔心實施規則。取而代之的是,OPA 使用其 Rego 語言進行思考,並在 API、微服務甚至是 Kubernetes 上評估策略。它靈活、安全,並且使更新策略變得簡單。OPA 通過評估三個關鍵因素來工作:輸入(如請求的實時數據)、數據(如用戶角色的外部信息)和策略(在 Rego 中決定是否“允許”或“拒絕”的邏輯)。一起,這些組件讓 OPA 能在保持 安裝 強大的同時,也让事情變得簡單和一致。
我們正在尋求實現或解決什麼問題?
通常,OPA中的數據就像一個可靠的旧朋友——静态或緩慢地變化。它與不斷變化的輸入數據一同使用,以作出明智的決定。但是,想像一個具有广阔的微服務网格、大量用戶和像PostgreSQL這樣的巨大數據庫的系統。這個系統每秒處理大量的交易,並且需要保持速度和吞吐量,而不會出汗。
在這樣的系統中实施細粒度的訪問控制是棘手的,但借助OPA,您可以將繁重的任務從您的微服務卸載,並在网關層面處理。通過與Kong API Gateway和OPA合作,您將獲得一流的吞吐量和精確的訪問控制。
您如何在不放慢速度的情況下維護準確的用戶數據?不斷地向PostgreSQL數據庫索取數百万條記錄既昂貴又緩慢。要在準確性和速度之間達到平衡通常需要妥協。讓我們通過開發一個自定義插件(在網關層面)來尋找實際的平衡,該插件經常加載並为本地的OPA緩存數據,以評估其策略。
示例
為示範用途,我已在 PostgreSQL 中設定了一個範例數據,包含用戶的姓名、電子郵件和角色等資訊。當用戶嘗試通過特定 URL 存取服務時,OPA 將評估該請求是否被允許。Rego 策略會檢查請求的 URL(資源)、方法以及用戶的角色,然後根據規則返回真或假。如果是真,則允許請求通過;如果是假,則拒絕存取。到目前为止,這個設定非常直觀。讓我們繼續深入了解自訂插件。為了更清楚地了解其實現方式,請參考以下 diagram。
當請求通過 Kong 代理時,Kong的自訂插件會被觸發。插件會獲取必要的數據,並與輸入/查詢一同傳遞給 OPA。此數據獲取有两个部分:一個是查詢 Redis 以尋找所需的值,如果找到,則傳遞給 OPA;如果找不到,則進一步查詢 Postgres 並將數據存取到 Redis 然後傳遞給 OPA。我們可以在下一節運行命令時重新查看此部分,並觀察日誌。OPA根據策略、輸入和數據做出決定,如果被允許,Kong 將將該請求傳送到 API。使用這種方法,對 Postgres 的查詢數量顯著減少,同時確保 OPA 可用的數據相對準確,並保留了低延遲。
開始建立自訂插件時,需要一個 handler.lua
文件,該文件實現在插件的core logic,以及一個 schema.lua
文件,該文件如名稱所示,為插件的配置定義架构。如果您開始學習為Kong撰寫自訂插件,請參考 這個鏈接 獲取更多信息。 文档還解釋了如何打包和安裝插件。讓我們繼續了解這個插件的邏輯。
示例的第一步是在您的本地環境或任何雲環境中安裝OPA、Kong、Postgres 和 Redis。請將仓库克隆到 這個倉庫。
查看docker-compose.yaml文件,該文件有上文提到的四個服務的配置定義。觀察Kong環境變量,以了解如何加載自訂插件。
運行以下命令來部署服務:
docker-compose build
docker-compose up
一旦我們確認容器的運行情況,Kong管理器和OPA將分别在以下端點上可用:https://localhost:8002 和 https://localhost:8181,如下所示:
使用以下命令創建一個測試服務、路徑,並將我們自訂的Kong插件添加到此路徑:
curl -X POST http://localhost:8001/config -F config=@config.yaml
在 authopa.rego 文件中定義的OPA策略,使用以下命令发布並更新到OPA服務:
curl -X PUT http://localhost:8181/v1/policies/mypolicyId -H "Content-Type: application/json" --data-binary @authopa.rego
此示例政策僅在用戶使用 /demo 路徑並使用 GET
方法,以及具有 "Moderator"
角色時,才授予用戶請求的訪問權。根據不同條件量身定制訪問控制,可以根據需要添加其他規則。
opa_policy = [
{
"path": "/demo",
"method": "GET",
"allowed_roles": ["Moderator"]
}
]
現在設定已完成,但在測試之前,我們需要在 Postgres 中添加一些測試數據。我為幾名員工添加了一些示例數據(名稱、電子郵件和角色),如下所示(請參照 PostgresReadme)。
以下是一個失敗和成功的請求示例:
現在,為了測試這個自訂插件的核心功能,讓我們連續送出兩個請求,並檢查日志以了解數據吸取的過程。
這裡是日志:
2024/09/13 14:05:05 [error] 2535#0: *10309 [kong] redis.lua:19 [authopa] No data found in Redis for key: [email protected], client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "ebbb8b5b57ff4601ff194907e35a3002"
2024/09/13 14:05:05 [info] 2535#0: *10309 [kong] handler.lua:25 [authopa] Fetching roles from PostgreSQL for email: [email protected], client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "ebbb8b5b57ff4601ff194907e35a3002"
2024/09/13 14:05:05 [info] 2535#0: *10309 [kong] postgres.lua:43 [authopa] Fetched roles: Moderator, client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "ebbb8b5b57ff4601ff194907e35a3002"
2024/09/13 14:05:05 [info] 2535#0: *10309 [kong] handler.lua:29 [authopa] Caching user roles in Redis, client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "ebbb8b5b57ff4601ff194907e35a3002"
2024/09/13 14:05:05 [info] 2535#0: *10309 [kong] redis.lua:46 [authopa] Data successfully cached in Redis, client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "ebbb8b5b57ff4601ff194907e35a3002"
2024/09/13 14:05:05 [info] 2535#0: *10309 [kong] opa.lua:37 [authopa] Is Allowed by OPA: true, client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "ebbb8b5b57ff4601ff194907e35a3002"
2024/09/13 14:05:05 [info] 2535#0: *10309 client 192.168.96.1 closed keepalive connection
------------------------------------------------------------------------------------------------------------------------
2024/09/13 14:05:07 [info] 2535#0: *10320 [kong] redis.lua:23 [authopa] Redis result: {"roles":["Moderator"],"email":"[email protected]"}, client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "75bf7a4dbe686d0f95e14621b89aba12"
2024/09/13 14:05:07 [info] 2535#0: *10320 [kong] opa.lua:37 [authopa] Is Allowed by OPA: true, client: 192.168.96.1, server: kong, request: "GET /demo HTTP/1.1", host: "localhost:8000", request_id: "75bf7a4dbe686d0f95e14621b89aba12"
日志顯示,對於第一次請求,當 Redis 內無數據時,會從 Postgres 吸取數據並儲存在 Redis 中,然後將其傳送給 OPA 進行評估。在隨後的請求中,由於數據已在 Redis 中,因此響應將更快。
結論
結論而言,通過結合 Kong Gateway、OPA 並實施帶有 Redis 快取的自訂插件,我們在高一吞吐量環境中有效地平衡了訪問控制的準確性和速度。插件通過在初次查詢後將用戶角色快取在 Redis 中,最小化了成本高昂的 Postgres 查詢次數。在隨後的請求中,數據從 Redis 取出,顯著減少延遲,同時維持 OPA 策略評估中準確和最新的用戶資訊。這種方法確保了細粒度訪問控制在网关層面有效地處理,而不會犧牲性能或安全性,使其成為擴展微服務並強制實施精確訪問策略的理想解決方案。
Source:
https://dzone.com/articles/enhanced-api-security-fine-grained-access-control