全部產品
Search
文件中心

Alibaba Cloud Service Mesh:使用OPA策略實現細粒度存取控制

更新時間:Jun 30, 2024

Service MeshASM整合了開放策略代理(OPA)外掛程式,通過OPA定義存取控制策略,可以使您的應用實現細粒度的存取控制。ASM支援在控制平面定義OPA策略,然後推送到資料平面叢集中。本文介紹如何在ASM定義OPA策略實現訪問應用時的許可權細粒度控制,包括對請求URL、要求標頭資訊中的Token等訪問限制。

前提條件

背景資訊

作為由CNCF託管的一個孵化專案,開放策略代理(OPA)是一個策略引擎,可用於為您的應用程式實現細粒度的存取控制。OPA作為通用策略引擎,可以與微服務一起部署為獨立服務。為了保護應用程式,必須先授權對微服務的每個請求,然後才能對其進行處理。為了檢查授權,微服務對OPA進行API調用,以確定請求是否被授權。OPA

步驟一:啟用OPA外掛程式和注入範圍控制

  1. 登入ASM控制台,在左側導覽列,選擇服務網格 > 網格管理

  2. 網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇網格資訊安全中心 > OPA策略

  3. OPA策略頁面,選中啟用開放策略代理OPA外掛程式啟用OPA注入範圍控制,單擊開啟OPA功能,在提示對話方塊,單擊確定

步驟二:建立OPA策略

在ASM控制平面建立ASMOPAPolicy資源,該資源會被推送到資料平面叢集,然後Pod中OPA引擎使用該資源實現細粒度存取控制。

方式一:通過ASM控制台建立OPA策略

  1. 登入ASM控制台,在左側導覽列,選擇服務網格 > 網格管理

  2. 網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇網格資訊安全中心 > OPA策略

  3. OPA策略頁面,單擊建立,選擇default命名空間,設定OPA策略的名稱bookinfo-opa,單擊新增匹配標籤,設定名稱versionv1,將以下Rego規則複製到文字框,然後單擊建立

    展開查看Rego規則

    package istio.authz
    import input.attributes.request.http as http_request
    allow {
        roles_for_user[r]
        required_roles[r]
    }
    roles_for_user[r] {
        r := user_roles[user_name][_]
    }
    required_roles[r] {
        perm := role_perms[r][_]
        perm.method = http_request.method
        perm.path = http_request.path
    }
    user_name = parsed {
        [_, encoded] := split(http_request.headers.authorization, " ")
        [parsed, _] := split(base64url.decode(encoded), ":")
    }
    user_roles = {
        "guest1": ["guest"],
        "admin1": ["admin"]
    }
    role_perms = {
        "guest": [
            {"method": "GET",  "path": "/productpage"},
        ],
        "admin": [
            {"method": "GET",  "path": "/productpage"},
            {"method": "GET",  "path": "/api/v1/products"},
        ],
    }

方式二:使用kubectl命令列建立OPA策略

  1. 使用以下內容,建立opa.yaml

    展開查看opa.yaml

    apiVersion: istio.alibabacloud.com/v1beta1
    kind: ASMOPAPolicy
    metadata:
      name: bookinfo-opa
      namespace: default
    spec:
      workloadSelector: 
         labels: 
           version: v1
      policy: |
        package istio.authz
        import input.attributes.request.http as http_request
        allow {
            roles_for_user[r]
            required_roles[r]
        }
        roles_for_user[r] {
            r := user_roles[user_name][_]
        }
        required_roles[r] {
            perm := role_perms[r][_]
            perm.method = http_request.method
            perm.path = http_request.path
        }
        user_name = parsed {
            [_, encoded] := split(http_request.headers.authorization, " ")
            [parsed, _] := split(base64url.decode(encoded), ":")
        }
        user_roles = {
            "guest1": ["guest"],
            "admin1": ["admin"]
        }
        role_perms = {
            "guest": [
                {"method": "GET",  "path": "/productpage"},
            ],
            "admin": [
                {"method": "GET",  "path": "/productpage"},
                {"method": "GET",  "path": "/api/v1/products"},
            ],
        }
    說明
    • OPA定義一個Pod的OPA策略時,只允許有一條default allow欄位。如果多個OPA策略生效於一個Pod,且每個策略中都定義了default allow欄位,則多條default allow欄位會導致動態更新失敗。

    • 設定OPA策略時,建議通過標籤控制策略生效的範圍,不恰當的Rego規則會導致無法訪問服務。

    • OPA執行引擎和業務容器在一個Pod中,需要佔用15081和9191連接埠。

    • OPA Policy中已經預設設定default allow = false ,不可以再重複設定default allow,否則會導致衝突。

    欄位

    說明

    spec

    使用Rego文法表述的具體規則。關於Rego文法的更多資訊,請參見Rego

    workloadSelector

    設定該OPA策略在此命名空間生效範圍,如果不設定,預設在全部Pod中生效,設定後只生效於符合標籤條件的Pod。

    user_roles

    為使用者授予角色許可權。本例設定guest1擁有guest角色許可權,admin1擁有admin角色許可權。

    role_perms

    設定角色擁有的許可權。本文設定guest角色可以通過/productpage訪問應用,admin角色可以通過/productpage/api/v1/products訪問應用。

  2. 執行以下命令,建立OPA策略。

    關於如何通過kubectl串連ASM執行個體,請參見通過控制面kubectl訪問Istio資源

    kubectl apply -f opa.yaml

步驟三:注入OPA代理

部署樣本應用Bookinfo到ASM執行個體,確認每個Pod都注入了OPA代理。

  1. 部署樣本應用Bookinfo到ASM執行個體。具體操作,請參見在ASM執行個體關聯的叢集中部署應用

  2. 建立入口網關、網關規則和虛擬服務。具體操作,請參見使用Istio資源實現版本流量路由

  3. 檢查每個應用是否都注入OPA代理。

    1. 登入Container Service管理主控台,在左側導覽列選擇叢集

    2. 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇工作負載 > 容器組

    3. 容器組頁面,從命名空間下拉式清單中選擇default,單擊目標應用程式容器組的名稱。

      容器頁簽下可以看到容器被注入了Sidecar代理(istio-proxy)和OPA代理(opa-istio)。依次檢查每個應用的容器,確保每個容器都被注入了Sidecar代理和OPA代理。注入OPA代理

步驟四:驗證使用OPA定義存取控制策略是否成功

  1. 執行以下命令,使用帶有/productpage的URL訪問應用。

    curl -X GET http://<入口網關的IP地址>/productpage --user guest1:password -I

    預期輸出:

    HTTP/1.1 200 OK
  2. 執行以下命令,使用帶有/api/v1/products的URL訪問應用。

    curl -X GET http://<入口網關的IP地址>/api/v1/products --user guest1:password -I

    預期輸出:

    HTTP/1.1 403 Forbidden

    可以看到guest1被授予guest角色,並且可以使用帶有/productpage的URL訪問應用,但不能使用帶有/api/v1/products的URL訪問應用。

  3. 執行以下命令,使用帶有/productpage的URL訪問應用。

    curl -X GET http://{{入口網關的IP地址}}/productpage --user admin1:password -I

    預期輸出:

    HTTP/1.1 200 OK
  4. 執行以下命令,使用帶有/api/v1/products的URL訪問應用。

    curl -X GET http://<入口網關服務的IP地址>/api/v1/products --user admin1:password -I

    預期輸出:

    HTTP/1.1 200 OK

    可以看到admin1被授予admin角色,並且可以使用帶有/productpage/api/v1/products的URL訪問應用。以上結果表明使用OPA定義存取控制策略成功。

步驟五:動態更新OPA策略

執行以下命令,修改OPA策略。

kubectl edit asmopapolicy bookinfo-opa -n default 

在返回結果中編輯OPA策略,使guest1同時用於guest和admin許可權。

apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
  name: bookinfo-opa
  namespace: default
spec:
  policy: |
    package istio.authz
    import input.attributes.request.http as http_request
    allow {
        roles_for_user[r]
        required_roles[r]
    }
    roles_for_user[r] {
        r := user_roles[user_name][_]
    }
    required_roles[r] {
        perm := role_perms[r][_]
        perm.method = http_request.method
        perm.path = http_request.path
    }
    user_name = parsed {
        [_, encoded] := split(http_request.headers.authorization, " ")
        [parsed, _] := split(base64url.decode(encoded), ":")
    }
    user_roles = {
        "guest1": ["guest", "admin"],
        "admin1": ["admin"]
    }
    role_perms = {
        "guest": [
            {"method": "GET",  "path": "/productpage"},
        ],
        "admin": [
            {"method": "GET",  "path": "/productpage"},
            {"method": "GET",  "path": "/api/v1/products"},
        ],
    }
  • user_roles:為使用者授予角色許可權。本例設定guest1同時擁有guest和admin角色許可權,admin1擁有admin角色許可權。

  • role_perms:設定角色擁有的許可權。本例設定guest角色可以通過/productpage訪問應用,admin角色可以通過/productpage/api/v1/products訪問應用。

步驟六:驗證動態更新OPA策略是否成功

  1. 執行以下命令,使用帶有/productpage的URL訪問應用。

    curl -X GET http://<入口網關服務的IP地址>/productpage --user guest1:password -I

    預期輸出:

    HTTP/1.1 200 OK
  2. 執行以下命令,使用帶有/api/v1/products的URL訪問應用。

    curl -X GET http://<入口網關服務的IP地址>/api/v1/products --user guest1:password -I

    預期輸出:

    HTTP/1.1 200 OK

    在沒有更新OPA策略之前,guest1隻能使用帶有/productpage的URL訪問應用,但不能使用帶有/api/v1/products的URL訪問應用。更新OPA策略之後,guest1可以使用帶有/productpage和/api/v1/products的URL訪問應用。說明動態更新OPA策略成功。

情境樣本

情境一:JWT請求授權

在接收使用者請求時,認證要求標頭資訊中的JWT Token是否可信,只有符合要求的請求才能訪問到應用。

以下ASMOPAPolicy定義了只有通過get請求的方式,且JWT Token的RoleguestuserGroupvisitor的請求才能訪問Productpage應用。

apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
  name: policy-jwt
  namespace: default
spec:
  policy: |
    package istio.authz

    allow {
      input.attributes.request.http.method == "GET"
      input.parsed_path[0] == "productpage"
      # set certificate 'B41BD5F462719C6D6118E673A2389'
      io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
      claims.Role == "guest"
      claims.userGroup == "visitor"
    }
    claims := payload {
       [_, payload, _] := io.jwt.decode(bearer_token)
    }
    bearer_token := t {
      v := input.attributes.request.http.headers.authorization
      startswith(v, "Bearer ")
      t := substring(v, count("Bearer "), -1)
    }
  • input.attributes.request.http.method:要求方法,本文設定為GET

  • input.parsed_path[0]:訪問的應用。

  • claims.Role:對JWT Token進行限制,本文設定Roleguest

  • claims.userGroup:對JWT Token進行限制,本文設定userGroupvisitor

使用JWT工具將RoleuserGroup等請求資訊編碼成JWT字串。請求授權

執行以下命令,訪問Productpage應用。

curl --location --request GET 'http://{入口網關服務的IP地址服務IP}/productpage' \
--header 'Authorization: Bearer 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3Vlc3QxIiwiUm9sZSI6Imd1ZXN0IiwidXNlckdyb3VwIjoidmlzaXRvciJ9.44OnUFZwOzSWzC7hyVfcle-uYk8byv7q_BBxS10AEWc'

預期輸出:

200

返回200,說明通過get請求的方式,且JWT Token的RoleguestuserGroupvisitor的請求訪問Productpage應用成功。如果您使用錯誤的JWT Token,或者請求中不包含JWT Token,將會返回403,說明訪問Productpage應用失敗。

情境二:對HTTP請求的請求體body進行限制

對HTTP請求的請求體body進行限制,只有請求體body與JWT中的Role相同的請求才能訪問應用。

以下ASMOPAPolicy定義了只有通過get請求的方式,且請求體body的username與JWT中的Role相同,並且userGroupmanager的請求才能訪問Productpage應用。

apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
  name: policy-body
  namespace: default
spec:
  policy: |
    package istio.authz

    allow {
      input.attributes.request.http.method == "GET"
      input.parsed_path[0] == "productpage"
      io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
      claims.Role == input.parsed_body.username
      claims.userGroup == "manager"
    }
    claims := payload {
       [_, payload, _] := io.jwt.decode(bearer_token)
    }
    bearer_token := t {
      v := input.attributes.request.http.headers.authorization
      startswith(v, "Bearer ")
      t := substring(v, count("Bearer "), -1)
    }
  • input.attributes.request.http.method:要求方法,本文設定為GET

  • input.parsed_path[0]:訪問的應用。

  • claims.Role:對JWT Token進行限制,本文設定input.parsed_body.username,限制請求體body的username與JWT中的Role必須相同。

  • claims.userGroup:對JWT Token進行限制,本文設定userGroupmanager

使用JWT工具將RoleuserGroup等請求資訊編碼成JWT字串。body

執行以下命令,訪問Productpage應用。

curl --location --request GET 'http://{入口網關服務的IP地址}/productpage' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3Vlc3QxIiwiUm9sZSI6ImFkbWluIiwidXNlckdyb3VwIjoibWFuYWdlciJ9.pAUvTeONHF-i5Ps-EUYYXk-hnaz-j-ZgP_wXJZMBiR0' \
--header 'Content-Type: application/json' \
--header 'Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.YRz90g.GT34_5BqlFTwGqabZk_qGZzxYQ0' \
--data-raw '{
    "username":"admin",
    "password":"12****"
                

預期輸出:

200

返回200,說明通過get請求的方式,請求體body的username與JWT中的Role相同,並且JWT Token中的userGroupmanager的請求訪問Productpage應用成功。如果您使用錯誤的JWT Token,或者請求中不包含JWT Token,將會返回403,說明訪問Productpage應用失敗。

情境三:限制更多上下文資訊

在情境二的基礎上限制更多上下文資訊,限制JWT中的username資訊必須包含在bookinfo_managers範圍內。

以下ASMOPAPolicy定義了只有通過get請求的方式,且請求體body的username與JWT中的Role相同,JWT中的username資訊必須包含在bookinfo_managers範圍內,userGroupmanager的請求才能訪問Productpage。

apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
  name: policy-range
  namespace: default
spec:
  policy: |
    package istio.authz
    bookinfo_managers = [{"name": "user1"}, {"name": "user2"}, {"name": "user3"}]

    allow {
      input.attributes.request.http.method == "GET"
      input.parsed_path[0] == "productpage"
      io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
      claims.Role == input.parsed_body.username
      claims.userGroup == "manager"
      claims.username == bookinfo_managers[_].name
    }
    claims := payload {
       [_, payload, _] := io.jwt.decode(bearer_token)
    }
    bearer_token := t {
      v := input.attributes.request.http.headers.authorization
      startswith(v, "Bearer ")
      t := substring(v, count("Bearer "), -1)
    }
  • input.attributes.request.http.method:要求方法,本文設定為GET

  • input.parsed_path[0]:訪問的應用。

  • claims.Role:對JWT Token進行限制,本文設定input.parsed_body.username,限制請求體body的username與JWT中的Role必須相同。

  • claims.userGroup:對JWT Token進行限制,本文設定userGroupmanager

  • claims.username:對JWT Token進行限制,本文設定bookinfo_managers[_].name,限制JWT中的username資訊必須包含在bookinfo_managers範圍內。

使用JWT工具將請求資訊編碼成JWT字串。上下文

執行以下命令,訪問productpage應用。

curl --location --request GET 'http://{入口網關服務的IP地址}/productpage' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiUm9sZSI6ImFkbWluIiwidXNlckdyb3VwIjoibWFuYWdlciJ9.2X0Fmb96jBexLcVm_55t8ZY6XveSxUAsQ1j3ar5dI_g' \
--header 'Content-Type: application/json' \
--header 'Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.YRz90g.GT34_5BqlFTwGqabZk_qGZzxYQ0' \
--data-raw '{
    "username":"admin",
    "password":"12****"
}'

預期輸出:

200

返回200,說明通過get請求的方式,請求體body的username與JWT中的Role相同,JWT中的username資訊必須包含在bookinfo_managers範圍內。並且JWT Token中的userGroupmanager的請求訪問Productpage應用成功。如果您使用錯誤的JWT Token,或者請求中不包含JWT Token,將會返回403,說明訪問Productpage應用失敗。

FAQ

如何查看哪些Pod使用OPA策略?

OPA的執行引擎以Sidecar的方式和業務容器部署在同一個Pod中。您需要進入到Pod中,執行以下命令,可以看到應用在Pod上的全部OPA策略。

curl 127.0.0.1:15081/v1/policies

如何對Rego文法進行測試?

OPA Policy Agent官方提供了線上測試載入器,您可以使用該工具對Rego編寫的策略進行測試。

相關文檔

如果您之前使用的是Configmap配置OPA策略,您可以參考以下文檔: