前提條件
開通實例后,系統默認生成OPA相關的ServiceEntry和opa-ext-auth-grpc。
驗證opa-ext-auth-grpc
在服務網格控制臺->網格安全中心->自定義授權服務。
可以看到產生了一個GRPC協議的授權服務,端口為19191。

驗證ServiceEntry
在服務網格控制臺->集群與工作負載->服務條目中,選定istio-system命名空間,可以看到產生了ext-authz,點擊編輯可以查看詳情。

詳情中可以看到端口為19191端口,指向127.0.0.1。

全局放行18181和18282端口
在sidecar管理->sidecar代理配置菜單下選擇命名空間tab,選擇我們驗證功能要用的命名空間,這里選擇default,配置sidecar入流量不攔截18181和18282端口(OPA agent的配置端口和健康檢查端口)。

開啟OPA功能
操作步驟
- 在控制臺->網格管理->OPA功能開關菜單下打開OPA開關,主要是安裝OPA控制面組件。
- 給default命名空間打上標簽,自動注入istio sidecar和OPA sidecar。
kubectl label namespace default opa-istio-injection="enabled"
kubectl label namespace default istio-injection="enabled"
- 部署bookinfo應用和sleep應用,可以看到pod里除了業務容器之外還有兩個容器,分別是istio sidecar和OPA sidecar,OPA sidecar用于實現外部授權服務。

- 定義AuthorizationPolicy授權策略,注意引用的外部授權服務需要和上面定義的外部授權服務名稱一致,可以根據業務的需要執行OPA外部授權策略,如下示例對匹配標簽app: productpage的:
apiVersion: istio.daliqc.cn/v1beta1
kind: AuthorizationPolicy
metadata:
name: ext-authz
spec:
selector:
matchLabels:
app: productpage
action: CUSTOM
provider:
# The provider name must match the extension provider defined in the mesh config.
# You can also replace this with sample-ext-authz-http to test the other external authorizer definition.
name: opa-ext-authz-grpc
rules:
# The rules specify when to trigger the external authorizer.
- to:
- operation:
paths: ["/*"]
- 上面的配置中,我們通過workloadSelector指定對productpage應用進行訪問授權,我們從sleep應用發起請求,訪問productpage,此時采用默認OPA策略,請求總是被拒絕。
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name} -n default) -c istio-proxy -n default -- curl //productpage.default:9080/api/v1/products --user bob:password -o /dev/null -s -w '%{http_code}\n'
403
-
配置OPA策略:以下OPA策略定義了guest和admin角色,guest和admin可以使用GET方法訪問/productpage路徑,admin另外還可以使用GET方法訪問/api/v1/products路徑;外部訪問時會先解析出用戶名,獲取用戶角色,進一步獲取用戶訪問權限,并與請求進行比對,滿足條件則放過,否則攔截。
apiVersion: opacontroller.k8s.io/v1 kind: OpaPolicy metadata: name: object-policy namespace: default spec: policy: |- package istio.authz import input.attributes.request.http as http_request import input.parsed_path 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 = { "alice": ["guest"], "bob": ["admin"] } role_perms = { "guest": [ {"method": "GET", "path": "/productpage"}, ], "admin": [ {"method": "GET", "path": "/productpage"}, {"method": "GET", "path": "/api/v1/products"}, ], } workloadSelector: labels: version: v1 -
驗證
以bob的身份訪問/api/v1/products和/productpage,由于bob是admin權限,兩個路徑都可以訪問,返回200。
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name} -n default) -c istio-proxy -n default -- curl //productpage.default:9080/api/v1/products --user bob:password -o /dev/null -s -w '%{http_code}\
n'
200
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name} -n default) -c istio-proxy -n default -- curl //productpage.default:9080/productpage --user bob:password -o /dev/null -s -w '%{http_code}\n'
200
以alice的身份訪問/api/v1/products和/productpage,由于alice是guest權限,所以對/api/v1/products的訪問會被拒絕,返回403;對/productpage的訪問可以通過,返回200。
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name} -n default) -c istio-proxy -n default -- curl //productpage.default:9080/api/v1/products --user alice:password -o /dev/null -s -w '%{http_code
}\n'
403
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name} -n default) -c istio-proxy -n default -- curl //productpage.default:9080/productpage --user alice:password -o /dev/null -s -w '%{http_code}\n'
200
- 修改OPA策略,給alice加上admin權限。
user_roles = {
"alice": ["guest", "admin"],
"bob": ["admin"]
}
重新驗證以alice身份訪問/api/v1/products,返回200。
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name} -n default) -c istio-proxy -n default -- curl //productpage.default:9080/api/v1/products --user alice:password -o /dev/null -s -w '%{http_code}\n'
200