服务网格ASM集成了开放策略代理(OPA)插件,通过OPA定义访问控制策略,可以使您的应用实现细粒度的访问控制。ASM支持在控制平面定义OPA策略,然后推送到数据平面集群中。本文介绍如何在ASM定义OPA策略实现访问应用时的权限细粒度控制,包括对请求URL、请求头信息中的Token等访问限制。
前提条件
- 已创建ASM实例,且ASM实例为v1.9.7及以上版本。具体操作,请参见创建ASM实例。
- 已创建ACK集群。具体操作,请参见创建Kubernetes托管版集群。
- 添加集群到ASM实例。具体操作,请参见添加集群到ASM实例。
背景信息

操作步骤
步骤一:启用OPA插件
步骤二:创建OPA策略
在ASM控制平面创建ASMOPAPolicy资源,该资源会被推送到数据平面集群,然后Pod中OPA引擎使用该资源实现细粒度访问控制。
使用ASM控制台创建OPA策略
使用kubectl命令行创建OPA策略
步骤三:注入OPA代理
部署示例应用Bookinfo到ASM实例,确认每个Pod都注入了OPA代理。
- 部署示例应用Bookinfo到ASM实例,请参见部署应用到ASM实例。
- 定义相应的Istio虚拟服务和入口网关,请参见使用Istio资源实现版本流量路由。
- 检查每个应用是否都注入OPA代理。
步骤四:验证使用OPA定义访问控制策略是否成功
- 执行以下命令,可以看到guest1被授予guest角色,并且可以使用带有/productpage的URL访问应用,但不能使用带有/api/v1/products的URL访问应用。
- 使用带有/productpage的URL访问应用。
curl -X GET http://<入口网关服务的IP地址>/productpage --user guest1:password -I
预期输出:
HTTP/1.1 200 OK
- 使用带有/api/v1/products的URL访问应用。
curl -X GET http://<入口网关服务的IP地址>/api/v1/products --user guest1:password -I
预期输出:
HTTP/1.1 403 Forbidden
- 使用带有/productpage的URL访问应用。
- 执行以下命令,可以看到admin1被授予admin角色,并且可以使用带有/productpage和/api/v1/products的URL访问应用。
- 使用带有/productpage的URL访问应用。
curl -X GET http://{{入口网关服务的IP地址}}/productpage --user admin1:password -I
预期输出:
HTTP/1.1 200 OK
- 使用带有/api/v1/products的URL访问应用。
curl -X GET http://<入口网关服务的IP地址>/api/v1/products --user admin1:password -I
预期输出:
HTTP/1.1 200 OK
根据以上结果,可以看到OPA定义访问控制策略是成功的。
- 使用带有/productpage的URL访问应用。
步骤五:动态更新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策略是否成功
执行以下命令,可以看到guest1被授予了admin角色,此时可以使用/productpage和/api/v1/products访问应用。
- 使用带有/productpage的URL访问应用。
curl -X GET http://<入口网关服务的IP地址>/productpage --user guest1:password -I
预期输出:
HTTP/1.1 200 OK
- 使用带有/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的Role
为guest
,userGroup
是visitor
的请求才能访问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进行限制,本文设置
Role
为guest
。 - claims.userGroup:对JWT Token进行限制,本文设置
userGroup
为visitor
。
curl --location --request GET 'http://{入口网关服务的IP地址服务IP}/productpage' \
--header 'Authorization: Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3Vlc3QxIiwiUm9sZSI6Imd1ZXN0IiwidXNlckdyb3VwIjoidmlzaXRvciJ9.44OnUFZwOzSWzC7hyVfcle-uYk8byv7q_BBxS10AEWc'
预期输出:
200
返回200,说明通过get请求的方式,且JWT Token的Role
为guest
,userGroup
是visitor
的请求访问Productpage应用成功。如果您使用错误的JWT Token,或者请求中不包含JWT Token,将会返回403,说明访问Productpage应用失败。
场景二:对HTTP请求的请求体body进行限制
对HTTP请求的请求体body进行限制,只有请求体body与JWT中的Role相同的请求才能访问应用。
以下ASMOPAPolicy定义了只有通过get请求的方式,且请求体body的username
与JWT中的Role
相同,并且userGroup
为manager
的请求才能访问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进行限制,本文设置
userGroup
为manager
。
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中的userGroup
为manager
的请求访问Productpage应用成功。如果您使用错误的JWT Token,或者请求中不包含JWT Token,将会返回403,说明访问Productpage应用失败。
场景三:限制更多上下文信息
在场景二的基础上限制更多上下文信息,限制JWT中的username
信息必须包含在bookinfo_managers
范围内。
以下ASMOPAPolicy定义了只有通过get请求的方式,且请求体body的username
与JWT中的Role
相同,JWT中的username
信息必须包含在bookinfo_managers
范围内,userGroup
为manager
的请求才能访问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进行限制,本文设置
userGroup
为manager
。 - claims.username:对JWT Token进行限制,本文设置
bookinfo_managers[_].name
,限制JWT中的username
信息必须包含在bookinfo_managers
范围内。

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中的userGroup
为manager
的请求访问Productpage应用成功。如果您使用错误的JWT Token,或者请求中不包含JWT Token,将会返回403,说明访问Productpage应用失败。
FAQ
如何查看哪些Pod使用OPA策略?
curl 127.0.0.1:15081/v1/policies
如何对Rego语法进行测试?
OPA Policy Agent官方提供了在线测试工具,您可以使用该工具对Rego编写的策略进行测试。