在雲端原生架構下,傳統的 RBAC 顯得力不從心,ABAC 根據屬性的彈性控制更能滿足複雜的存取需求。本文將探討如何結合 OPA 和 Rego 語言,構建更精細、動態的 ABAC 系統。文章將涵蓋 Rego 語言的例項解析,並剖析其如何處理使用者、資源和環境屬性,以及如何設計資料模型來支援策略評估。此外,文章也將探討 OPA Bundle 伺服器的搭建、組態和測試流程,並提出大規模 Bundle 管理的策略,以確保策略的版本控制和一致性。最後,文章將提供最佳實踐和注意事項,協助讀者構建安全可靠的 ABAC 系統。

深入解析根據屬性的存取控制(ABAC)與開放策略代理(OPA)

前言

在現代化的雲端運算環境中,存取控制是資訊安全的重要一環。根據屬性的存取控制(Attribute-Based Access Control, ABAC)提供了一種比傳統根據角色的存取控制(Role-Based Access Control, RBAC)更為靈活的存取控制機制。本文將探討ABAC的實作原理,並以開放策略代理(Open Policy Agent, OPA)為例,展示如何使用Rego語言編寫存取控制策略。

ABAC與RBAC的比較

RBAC主要根據使用者的角色來決定其對資源的存取許可權。相較之下,ABAC則是根據使用者、資源以及環境的多種屬性來動態決定存取許可權。這種機制使得ABAC在複雜的雲端環境中更具彈性。

RBAC的侷限性

  1. 角色定義僵化:當系統複雜度增加時,角色定義可能無法滿足多變的存取需求。
  2. 許可權管理困難:隨著角色數量的增加,許可權管理變得更加複雜。

ABAC的優勢

  1. 動態許可權控制:根據實時屬性進行存取控制。
  2. 更高的靈活性:能夠適應複雜多變的存取需求。
  3. 細粒度控制:能夠對資源進行精細的存取控制。

OPA與Rego語言

OPA是一種開源的策略引擎,用於統一管理跨多個系統的存取控制策略。OPA使用Rego語言來編寫策略,這是一種專為策略定義設計的宣告式語言。

Rego語言範例解析

allow if {
    user_is_employee
    user_is_senior
    action_is_update
    user_is_on_shift
}

allow if {
    user_is_customer
    action_is_read
    not pet_is_adopted
}

user_is_owner if data.user_attributes[input.user].title == "owner"
user_is_employee if data.user_attributes[input.user].title == "employee"
user_is_customer if data.user_attributes[input.user].title == "customer"
user_is_senior if data.user_attributes[input.user].tenure > 8

action_is_read if input.action == "read"
action_is_update if input.action == "update"

pet_is_adopted if data.pet_attributes[input.resource].adopted == true

# 時間處理邏輯
tz := "America/New_York"
now := time.now_ns()
clock := time.clock([now, tz])
day := time.weekday(now)
shift := data.user_attributes[input.user].shift

user_is_on_shift if {
    is_weekday
    is_valid_time
}

is_valid_time if {
    clock[0] >= data.shifts[shift].start
    clock[0] < data.shifts[shift].end
}

is_valid_time if {
    clock[0] >= data.shifts[shift].start
    clock[0] == data.shifts[shift].end
    clock[1] == 0
    clock[2] == 0
}

is_weekday if day in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

#### 內容解密:

此Rego程式碼定義了根據屬性的存取控制規則。主要包含以下幾個方面:

  1. 允許條件:定義了兩種允許存取的情況:員工在班且為高階員工時可進行更新操作;客戶可讀取未被領養的寵物資訊。
  2. 使用者屬性判斷:根據使用者的屬性(如職稱、任職時間)來判斷其角色和資歷。
  3. 動作判斷:判斷使用者的操作是讀取還是更新。
  4. 資源屬性判斷:判斷寵物是否已被領養。
  5. 時間處理邏輯:根據員工的班次和當前時間判斷員工是否在班。

資料模型解析

OPA使用JSON格式儲存相關屬性資料,如下所示:

{
    "user_attributes": {
        "alice": {
            "tenure": 20,
            "title": "owner",
            "shift": "D"
        },
        "bob": {
            "tenure": 15,
            "title": "employee",
            "shift": "N"
        }
    },
    "shifts": {
        "D": {
            "start": 9,
            "end": 17
        },
        "N": {
            "start": 15,
            "end": 23
        }
    },
    "pet_attributes": {
        "dog123": {
            "adopted": true,
            "age": 2,
            "breed": "terrier",
            "name": "toto"
        }
    }
}

#### 內容解密:

此JSON資料結構儲存了使用者屬性、班次資訊和寵物屬性。這些資料被OPA用於評估存取控制策略。

  1. 使用者屬性:包含使用者的任職時間、職稱和班次等資訊。
  2. 班次資訊:定義了不同班次的起始和結束時間。
  3. 寵物屬性:記錄了寵物的領養狀態、年齡、品種和名稱等資訊。

ABAC的實作與優勢

透過OPA和Rego語言,我們可以實作根據屬性的動態存取控制。這種方法相較於傳統的RBAC具有更高的靈活性,能夠更好地適應複雜的雲端環境。

ABAC在雲端環境中的實作要點

  1. 標籤和標記的管理:在雲端環境中,通常使用標籤和標記來為資源新增中繼資料。這些標籤和標記會被ABAC策略評估,因此必須嚴格控制誰可以建立或修改它們。
  2. 與現有系統整合:ABAC可以與人力資源系統、資產管理系統等現有系統整合,實作動態的屬性更新。

策略自動化與管理

為了有效地管理跨多個系統的存取控制策略,需要實作策略自動化。這包括:

  1. 策略封裝與分發:使用OPA的bundle機制,將策略封裝並分發到各個OPA例項。
  2. Bundle伺服器:建立一個bundle伺服器來託管和分發策略包。

使用Golang建立Bundle伺服器範例

// 使用gorilla/mux建立HTTP路由器和處理器
package main

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/bundles/{bundle_name}", getBundle).Methods("GET")
    log.Fatal(http.ListenAndServe(":8080", router))
}

func getBundle(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    bundleName := vars["bundle_name"]
    // 邏輯:根據bundleName提供對應的bundle
}

#### 內容解密:

此Golang程式碼片段展示瞭如何使用gorilla/mux套件建立一個簡單的HTTP伺服器,用於提供OPA的bundle。

  1. 路由器設定:使用mux.NewRouter()建立路由器,並定義了一個處理GET請求的路由,用於提供bundle。
  2. 處理函式:getBundle函式根據請求中的bundle_name引數提供對應的bundle。

OPA Bundle 伺服器設定與測試流程詳解

伺服器啟動與基本測試

當伺服器以偵錯模式啟動時,它會監聽在 10.0.2.2:8443 這個 socket 上,並產生以下啟動日誌:

{"level":"info","time":"2022-12-11T20:05:26.159931-05:00","message":"Service started successfully."}
{"level":"info","time":"2022-12-11T20:05:26.16005-05:00","message":"Flags: map[], Args: [./main.bin]"}
{"level":"info","time":"2022-12-11T20:05:26.163098-05:00","message":"Listening on socket 10.0.2.2:8443"}

使用 10.0.2.2 這個迴路位址別名是為了讓在 Docker 中執行的 OPA 伺服器能夠連線到在 Docker 外部的本地 HTTPS 伺服器。這是因為在 Docker 虛擬機器和桌面環境中,localhost127.0.0.1 的上下文是不同的。

測試伺服器連線

首先,使用 curl 命令來測試伺服器的 info 端點,傳送一個帶有 Bearer Token 的 HTTPS GET 請求:

$ TOKEN=`cat token`
$ curl -k -H 'Accept: application/json' -H "Authorization: Bearer ${TOKEN}" https://10.0.2.2:8443/info
{"service-name":"opa-bundle-api","service-id":"078f5...d2954"}

這裡使用了 -k 引數來忽略自簽署的 TLS 憑證組態。

接著,測試 bundle 下載功能,同樣使用 -k 引數:

$ TOKEN=`cat token`
$ curl -k -H "Authorization: Bearer ${TOKEN}" https://10.0.2.2:8443/bundles/signed-main.tar.gz -o signed-main.tar.gz

成功下載檔案後,我們可以開始組態 OPA 伺服器來連線到 bundle 伺服器。

組態 OPA 伺服器連線 Bundle 伺服器

以下是 OPA 伺服器連線 bundle 伺服器的組態檔案內容:

keys:
  project-bundle-key:
    key: |
      -----BEGIN PUBLIC KEY-----
      <PUBLIC_KEY>
      -----END PUBLIC KEY-----
services:
  - name: opa-bundle-api
    url: https://10.0.2.2:8443/v1/bundles
    allow_insecure_tls: true
    credentials:
      bearer:
        token: "eyJ..."
bundles:
  project:
    service: opa-bundle-api
    resource: signed-main.tar.gz
    persist: true
polling:
  min_delay_seconds: 10
  max_delay_seconds: 20
signing:
  keyid: project-bundle-key

使用以下命令啟動 OPA 伺服器並載入組態檔案:

$ opa run -s --config-file opa-conf.yaml

或者,可以使用 --set-file 引數在啟動時直接從檔案載入公鑰:

$ opa run -s --config-file opa-conf.yaml --set-file "keys.project-bundle-key.key=keys/key.pem.pub"

Docker 中的 OPA 伺服器執行

在 Docker 中執行 OPA 伺服器時,需要對映兩個卷來提供組態檔案和 bundle 儲存:

$ docker run -it --rm -p 8181:8181 -v $(pwd):/config -v $(pwd)/.opa:/.opa --platform linux/amd64 openpolicyagent/opa:0.62.0 run -s --config-file=config/opa-conf.yaml

OPA 伺服器啟動日誌分析

OPA 伺服器啟動後的日誌輸出如下:

{"addrs":[":8181"],"diagnostic-addrs":[],"level":"info","msg":"Initializing server.","time":"2022-11-25T23:32:17-05:00"}
{"level":"info","msg":"Starting bundle loader.","name":"project","plugin":"bundle","time":"2022-11-25T23:32:17-05:00"}
{"level":"info","msg":"Bundle loaded and activated successfully. Etag updated to 6...c.","name":"project","plugin":"bundle","time":"2022-11-25T23:32:17-05:00"}

從日誌中可以看到,bundle 設定成功,bundle 被下載並啟用,且 ETag 被更新。

Bundle 請求處理流程

在 bundle 伺服器的日誌中(偵錯模式),可以看到 OPA 的 bundle 請求被處理的記錄:

{"level":"debug","time":"2022-11-25T23:50:54.627103-05:00","message":"HTTP request URI: /v1/bundles/signed-main.tar.gz, HTTP request headers: map[Accept-Encoding:[gzip] Authorization:[Bearer eyJ...] If-None-Match:[6...c] Prefer:[modes=snapshot,delta] User-Agent:[Open Policy Agent/0.46.1 (darwin, arm64)]]"}

ETag 的作用機制

ETag(Entity Tag)用於減少伺服器的頻寬需求,透過檢查快取內容是否有變更來決定是否需要重新下載。更多關於 ETag 的資訊可以參考 Mozilla 開發者檔案。

大規模 Bundle 管理方案探討

雖然 bundle 伺服器和 OPA 的 bundle 組態能夠有效地提供策略和資料,但手動管理和分發策略在大規模系統中難以擴充套件。因此,需要更完善的解決方案來實作策略的集中管理和安全分發。

可擴充套件的工具和服務

後續章節將介紹四種解決方案,以幫助擴充套件 bundle 管理和交付。這些工具和服務各有其優缺點,有些提供企業級支援和成熟的管理工具,有些則是開源軟體,需要更多的自定義工作。選擇合適的工具時,需要考慮其是否符合需求以及願意接受的權衡。

程式碼解析:OPA 組態檔案結構說明

以下是一個典型的 OPA 組態檔案範例,展示瞭如何組態服務、bundle 和驗證金鑰:

services:
  - name: opa-bundle-api
    url: https://example.com/v1/bundles
    allow_insecure_tls: true
    credentials:
      bearer:
        token: "your_bearer_token"
bundles:
  project:
    service: opa-bundle-api
    resource: signed-main.tar.gz
    persist: true
signing:
  keyid: project-bundle-key

組態檔案重點解析

  1. 服務定義:定義了名為 opa-bundle-api 的服務,指定了 URL 和認證方式。
  2. Bundle 組態:指定了要下載的 bundle 名稱和儲存方式。
  3. 簽名驗證:定義了用於驗證 bundle 簽名的金鑰 ID。

詳細步驟說明

  1. services 部分定義遠端服務的 URL 和認證資訊。
  2. bundles 部分指定要使用的服務和資源名稱。
  3. 設定 persisttrue 以儲存下載的 bundle。
  4. signing 部分指定用於驗證的金鑰 ID。

圖表說明:OPA 工作流程示意圖

  graph LR
    A[OPA Server] -->|下載 Bundle| B[Bundle Server]
    B -->|傳回 Bundle| A
    A -->|驗證簽名| C[驗證成功]
    C -->|載入策略| D[更新策略]
    D -->|生效| E[應用策略]

圖表翻譯: 此圖示展示了 OPA Server 與 Bundle Server 的互動流程:

  1. OPA Server 向 Bundle Server 發起下載請求。
  2. Bundle Server 傳回所需的 Bundle。
  3. OPA Server 對收到的 Bundle 進行簽名驗證。
  4. 驗證成功後,載入並更新內部策略。
  5. 最終應用新的策略組態。

最佳實踐與注意事項

  1. 安全組態:確保使用安全的連線方式(HTTPS)並正確組態認證資訊。
  2. 定期更新:設定合理的輪詢間隔以保持策略的即時更新。
  3. 日誌監控:定期檢查 OPA 和 Bundle Server 的日誌以發現潛在問題。
  4. 備份機制:確保對關鍵組態和資料進行適當備份。

詳細實作建議

  1. 在生產環境中使用有效的 TLS 證書。
  2. 使用安全的 Token 管理機制。
  3. 組態適當的日誌記錄和監控告警機制。
  4. 建立完善的變更管理和稽核流程。