3.7.8.3使用OPA策略引擎实现访问控制
前提条件:
1. 开通云容器引擎
2. 开通服务网格实例
开通实例后,系统默认生成OPA相关的ServiceEntry和opa-ext-auth-grpc
l验证opa-ext-auth-grpc:
在服务网格控制台->网格安全中心->自定义授权服务。
可以看到产生了一个GRPC协议的授权服务,端口为19191
l验证ServiceEntry
在服务网格控制台->集群与工作负载->服务条目中,选定istio-system命名空间,可以看到产生了ext-authz,点击编辑可以查看详情。
详情中可以看到端口为19191端口,指向127.0.0.1
l全局放行18181和18282端口:
在sidecar管理->sidecar代理配置菜单下选择命名空间tab,选择我们验证功能要用的命名空间,这里选择default,配置sidecar入流量不拦截18181和18282端口(OPA agent的配置端口和健康检查端口)
开启OPA功能
操作步骤:
1. 在服务网格控制台->网格管理->OPA功能开关菜单下打开OPA开关,主要是安装OPA控制面组件
2. 给default命名空间打上标签,自动注入istio sidecar和OPA sidecar
kubectl label namespace default opa-istio-injection="enabled"
kubectl label namespace default istio-injection="enabled"
3. 部署bookinfo应用和sleep应用,可以看到pod里除了业务容器之外还有两个容器,分别是istio sidecar和OPA sidecar,OPA sidecar用于实现外部授权服务
4. 定义AuthorizationPolicy授权策略,注意引用的外部授权服务需要和上面定义的外部授权服务名称一致,可以根据业务的需要执行OPA外部授权策略,如下示例对匹配标签app: productpage的:
apiVersion: security.istio.io/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: ["/*"]
5. 上面的配置中,我们通过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 http://productpage.default:9080/api/v1/products --user bob:password -o /dev/null -s -w '%{http_code}\n'
403
6. 配置OPA策略:以下OPA策略定义了guest和admin角色,guest和admin可以使用GET方法访问/productpage路径,admin另外还可以使用GET方法访问/api/v1/products路径;外部访问时会先解析出用户名,获取用户角色,进一步获取用户访问权限,并与请求进行比对,满足条件则放过,否则拦截
apiVersion: istio.ctyun.cn/v1beta1
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
7. 验证
以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 http://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 http://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 http://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 http://productpage.default:9080/productpage --user alice:password -o /dev/null -s -w '%{http_code}\n'
200
8. 修改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 http://productpage.default:9080/api/v1/products --user alice:password -o /dev/null -s -w '%{http_code}\n'
200