接入gRPC协议的自定义授权服务
ASM提供了自定义授权服务,在服务间互相通信时加入鉴权流程,以确保只有得到授权的情况下,才能访问关键服务。本文以httpbin应用和sleep应用为例,介绍如何实现接入gRPC协议的自定义授权服务。
前提条件
配置流程

步骤一:部署自定义授权服务
在集群中部署自定义授服务。该服务需遵循Istio自定义鉴权服务接口规范,支持HTTP和gRPC协议,用于实现自定义鉴权逻辑。本文使用的示例服务要求请求必须带有x-ext-authz: allow
请求头,才能通过鉴权访问成功。
本文提供了自定义授权服务示例。您也可以参考本示例应用的代码,创建自己的自定义授权服务。具体内容,请参见自定义授权。
使用以下内容,创建ext-authz.yaml。
# Copyright Istio Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Example configurations for deploying ext-authz server separately in the mesh. apiVersion: v1 kind: Service metadata: name: ext-authz labels: app: ext-authz spec: ports: - name: http port: 8000 targetPort: 8000 - name: grpc port: 9000 targetPort: 9000 selector: app: ext-authz --- apiVersion: apps/v1 kind: Deployment metadata: name: ext-authz spec: replicas: 1 selector: matchLabels: app: ext-authz template: metadata: labels: app: ext-authz spec: containers: - image: istio/ext-authz:0.6 imagePullPolicy: IfNotPresent name: ext-authz ports: - containerPort: 8000 - containerPort: 9000 ---
执行以下命令,在集群中部署自定义授权服务。
kubectl apply -f ext-authz.yaml
预期输出:
service/ext-authz created deployment.apps/ext-authz created
执行以下命令, 验证应用是否正常工作。
kubectl logs "$(kubectl get pod -l app=ext-authz -n default -o jsonpath={.items..metadata.name})" -n default -c ext-authz
预期输出:
2021/01/07 22:55:47 Starting HTTP server at [::]:8000 2021/01/07 22:55:47 Starting gRPC server at [::]:9000
返回以上结果,说明自定义授权服务部署成功。
获取ext-authz应用的gRPC协议端口。
- 登录容器服务管理控制台,在左侧导航栏选择集群。
- 在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
在服务页面,单击ext-authz。
在端点区域,可以看到gRPC协议的端口为9000。
步骤二:部署示例应用
使用以下内容,创建httpbin.yaml。
# Copyright Istio Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################################################################## # httpbin service ################################################################################################## apiVersion: v1 kind: ServiceAccount metadata: name: httpbin --- apiVersion: v1 kind: Service metadata: name: httpbin labels: app: httpbin service: httpbin spec: ports: - name: http port: 8000 targetPort: 80 selector: app: httpbin --- apiVersion: apps/v1 kind: Deployment metadata: name: httpbin spec: replicas: 1 selector: matchLabels: app: httpbin version: v1 template: metadata: labels: app: httpbin version: v1 spec: serviceAccountName: httpbin containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 80
执行以下命令,在集群中部署httpbin应用。
kubectl apply -f httpbin.yaml
使用以下内容,创建sleep.yaml。
# Copyright Istio Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################################################################## # Sleep service ################################################################################################## apiVersion: v1 kind: ServiceAccount metadata: name: sleep --- apiVersion: v1 kind: Service metadata: name: sleep labels: app: sleep service: sleep spec: ports: - port: 80 name: http selector: app: sleep --- apiVersion: apps/v1 kind: Deployment metadata: name: sleep spec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep spec: terminationGracePeriodSeconds: 0 serviceAccountName: sleep containers: - name: sleep image: curlimages/curl command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /etc/sleep/tls name: secret-volume volumes: - name: secret-volume secret: secretName: sleep-secret optional: true ---
执行以下命令,在集群中部署sleep应用。
kubectl apply -f sleep.yaml
步骤三:管理自定义授权服务
您需要将步骤一部署的服务声明到服务网格中,使服务网格可以使用该服务进行鉴权。
- 登录ASM控制台,在左侧导航栏,选择 。
- 在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 。
在自定义授权服务页面,单击关联自定义授权服务。
在关联自定义授权服务页面,单击基于envoy.ext_authz实现的自定义授权服务(HTTP或gRPC协议)页签,进行相关配置,然后单击创建。
类型
配置项
说明
必选参数
协议
选择自定义授权应用的协议。本文选择GRPC。
名称
自定义授权服务名称。本文设置为test。
服务地址
输入自定义授权应用的服务地址
<应用名称>.<命名空间名称>.svc.<集群域名>
。本文设置为ext-authz.default.svc.cluster.local。服务端口
输入自定义授权应用的服务端口。本文设置为9000。
超时时间
如果鉴权应用未在该时间内返回,则认为鉴权服务不可用。本文设置为10秒。
可选参数
鉴权服务不可用时放行请求
是否在鉴权服务不可用时放行请求。若启用该选项,则鉴权服务不可用时请求被放行。
鉴权服务不可用自定义错误码
该选项仅在关闭鉴权服务不可用时放行请求时可选。若启用该选项,需填写错误码,在鉴权服务不可用时,该错误码将被返回至调用端。
在鉴权请求中携带请求Body
启用该选项后,需填写鉴权请求携带Body的最大长度。若启用允许将不完整消息发往鉴权服务,当被鉴权请求Body大于设置的最大长度时,从最大长度处截取,并将截取后的Body发往鉴权服务。
步骤四:创建授权策略
您需要创建授权策略来配置需要鉴权的请求操作。
- 登录ASM控制台,在左侧导航栏,选择 。
- 在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 ,然后单击创建。
在创建页面,进行相关配置,然后单击创建。
配置项
说明
名称
自定义授权策略名称,本文设置为test1。
策略类型
设置策略类型为自定义授权服务。
自定义授权服务
设置自定义授权服务。本文设置为test。
命名空间
设置命名空间。本文设置为default。
生效范围
选择生效范围为Service。
工作负载
设置工作负载。本文设置为httpbin。
添加请求目标
设置HTTP路径。
打开HTTP路径(Paths)开关,设置值为/headers。
步骤五:验证自定义授权是否成功
执行以下命令,访问
httpbin.default:8000/ip
。kubectl exec "$(kubectl get pod -l app=sleep -n default -o jsonpath={.items..metadata.name})" -c sleep -n default -- curl "http://httpbin.default:8000/ip" -s -o /dev/null -w "%{http_code}\n"
预期输出:
200
返回以上结果,说明没有触发鉴权。
执行以下命令,带有
x-ext-authz: deny
请求头访问httpbin.default:8000/headers
。kubectl exec "$(kubectl get pod -l app=sleep -n default -o jsonpath={.items..metadata.name})" -c sleep -ndefault -- curl "http://httpbin.default:8000/headers" -H "x-ext-authz: deny" -s
预期输出:
denied by ext_authz for not found header `x-ext-authz: allow` in the request
返回以上结果,说明触发鉴权,但是鉴权未通过。
执行以下命令,带有
x-ext-authz: allow
请求头访问httpbin.default:8000/headers
。kubectl exec "$(kubectl get pod -l app=sleep -n default -o jsonpath={.items..metadata.name})" -c sleep -n default -- curl "http://httpbin.default:8000/headers" -H "x-ext-authz: allow" -s
预期输出:
{ "headers": { "Accept": "*/*", "Host": "httpbin:8000", "User-Agent": "curl/7.76.0-DEV", "X-B3-Parentspanid": "430f770aeb7ef215", "X-B3-Sampled": "0", "X-B3-Spanid": "60ff95c5acdf5288", "X-B3-Traceid": "fba72bb5765daf5a430f770aeb7e****", "X-Envoy-Attempt-Count": "1", "X-Ext-Authz": "allow", "X-Ext-Authz-Check-Result": "allowed", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=e5178ee79066bfbafb1d98044fcd0cf80db76be8714c7a4b630c7922df520bf2;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep" } }
返回以上结果,说明触发鉴权,并且鉴权通过。
根据以上结果,可以看到访问
httpbin.default:8000/headers
时,请求中必须带有x-ext-authz: allow
才能访问成功,说明自定义授权成功。