当您需要对使用gRPC协议通信的服务进行细粒度的访问控制时,可以使用自定义授权服务功能,根据特定业务需求定制授权机制,在服务间互相通信时加入鉴权流程,确保只有经过认证和授权的请求才能访问相应的服务资源,提高服务间通信的安全性。本文以httpbin应用和sleep应用为例,介绍如何实现接入gRPC协议的自定义授权服务。
步骤一:部署自定义授权服务
在集群中部署自定义授服务。该服务需遵循Istio自定义鉴权服务接口规范,支持HTTP和gRPC协议,用于实现自定义鉴权逻辑。本文使用的示例服务要求请求必须带有x-ext-authz: allow
请求头,才能通过鉴权访问成功。
说明 本文提供了自定义授权服务示例。您也可以参考本示例应用的代码,创建自己的自定义授权服务。具体内容,请参见自定义授权。
使用以下内容,创建ext-authz.yaml。
展开查看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连接集群,执行以下命令,在集群中部署自定义授权服务。
关于如何通过kubectl连接集群,请参见获取集群KubeConfig并通过kubectl工具连接集群。
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
预期输出:
2023/12/20 08:15:39 Starting gRPC server at [::]:9000
2023/12/20 08:15:39 Starting HTTP server at [::]:8000
返回以上结果,说明自定义授权服务部署成功。
获取ext-authz应用的gRPC协议端口。
登录容器服务管理控制台,在左侧导航栏选择集群。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择。
在服务页面,单击ext-authz。
在端点区域,可以看到gRPC协议的端口为9000。
步骤二:部署示例应用
使用以下内容,创建httpbin.yaml。
展开查看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。
展开查看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
步骤三:使用gRPC协议对接自定义授权服务
您需要将步骤一部署的服务声明到服务网格中,使服务网格可以使用该服务进行鉴权。
登录ASM控制台,在左侧导航栏,选择。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择,然后单击关联自定义授权服务。
在关联自定义授权服务页面,单击基于envoy.ext_authz实现的自定义授权服务(HTTP或gRPC协议)页签,进行相关配置,然后单击创建。
类型 | 配置项 | 说明 |
必选参数 | 协议 | 选择自定义授权应用的协议。本文选择GRPC。 |
名称 | 自定义授权服务名称。本文设置为test。 |
服务地址 | 输入自定义授权应用的服务地址<应用名称>.<命名空间名称>.svc.<集群域名> 。本文设置为ext-authz.default.svc.cluster.local。 |
服务端口 | 输入自定义授权应用的服务端口。本文设置为9000。 |
超时时间 | 如果鉴权应用未在该时间内返回,则认为鉴权服务不可用。本文设置为10秒。 |
可选参数 | 鉴权服务不可用时放行请求 | 是否在鉴权服务不可用时放行请求。若启用该选项,则鉴权服务不可用时请求被放行。 |
鉴权服务不可用自定义错误码 | 该选项仅在关闭鉴权服务不可用时放行请求时可选。若启用该选项,需填写错误码,在鉴权服务不可用时,该错误码将被返回至调用端。 |
在鉴权请求中携带请求Body | 启用该选项后,需填写鉴权请求携带Body的最大长度。若启用允许将不完整消息发往鉴权服务,当被鉴权请求Body大于设置的最大长度时,从最大长度处截取,并将截取后的Body发往鉴权服务。 |
步骤四:创建授权策略
您需要创建授权策略来配置需要鉴权的请求操作。
登录ASM控制台,在左侧导航栏,选择。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择,然后单击创建。
在创建页面,进行相关配置,然后单击创建。
配置项 | 说明 |
名称 | 自定义授权策略名称,本文设置为test1。 |
策略类型 | 选择自定义授权服务。 |
自定义授权服务 | 选择grpcextauth-test(GRPC)。 |
命名空间 | 在工作负载生效页签,选择default命名空间。 |
生效范围 | 选择Service。 |
工作负载 | 选择httpbin。 |
请求匹配规则 | 在添加请求目标区域,打开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.default:8000",
"User-Agent": "curl/8.5.0",
"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=c3e5364e87add0f4f69e6b0d029f5961b404c8f209bf9004b3d21a82cf67****;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep"
}
}
预期输出表明触发鉴权,并且鉴权通过。访问httpbin.default:8000/headers
时,请求中必须带有x-ext-authz: allow
才能访问成功,说明自定义授权成功。