服务网格 ASM(Service Mesh)支持完善的认证、授权配置,还提供了灵活的扩展能力,支持对接HTTP协议和gRPC协议的自定义授权服务,并接入网格的鉴权流程。本文介绍如何开发一个基于HTTP协议的自定义授权服务。
背景信息
通过服务网格,您可以在网关上配置JWT认证(RequestAuthentication)完成对请求身份的认证;对于网格内的请求,默认通过网格提供的mTLS证书完成请求身份的认证。确认了请求身份之后,您可以通过授权策略(AuthorizationPolicy)限制请求的行为。在提供了上述标准能力的同时,服务网格还支持接入自定义授权服务。自定义授权服务的整体流程大致如下。
当您配置使用HTTP协议对接自定义授权服务时,网格代理(网关或Sidecar)会将收到的请求信息填充到HTTP协议的鉴权请求中,然后发往自定义授权服务,由自定义授权服务判断是否放行该请求。
自定义授权服务返回200表示通过验证,需要放行请求。
自定义授权服务返回5xx代表授权服务异常,需要根据配置决定放行或拒绝请求。
其他状态码均会被视为验证不通过,需要拒绝该请求。
配置介绍
ASM支持使用界面关联一个自定义授权服务,关联之后您可以在授权策略中配置要使用鉴权服务的网格代理。具体操作,请参见使用HTTP协议对接自定义授权服务。
开发HTTP自定义授权服务
ASM兼容开源Istio服务网格,Istio社区提供了自定义授权服务的开发示例。这部分代码同时实现了HTTP和gRPC两种协议的自定义授权服务。本文涉及的HTTP部分主要逻辑在ServeHTTP
函数中:
// ServeHTTP implements the HTTP check request.
func (s *ExtAuthzServer) ServeHTTP(response http.ResponseWriter, request *http.Request) {
body, err := io.ReadAll(request.Body)
if err != nil {
log.Printf("[HTTP] read body failed: %v", err)
}
l := fmt.Sprintf("%s %s%s, headers: %v, body: [%s]\n", request.Method, request.Host, request.URL, request.Header, returnIfNotTooLong(string(body)))
if allowedValue == request.Header.Get(checkHeader) {
log.Printf("[HTTP][allowed]: %s", l)
response.Header().Set(resultHeader, resultAllowed)
response.Header().Set(overrideHeader, request.Header.Get(overrideHeader))
response.Header().Set(receivedHeader, l)
response.WriteHeader(http.StatusOK)
} else {
log.Printf("[HTTP][denied]: %s", l)
response.Header().Set(resultHeader, resultDenied)
response.Header().Set(overrideHeader, request.Header.Get(overrideHeader))
response.Header().Set(receivedHeader, l)
response.WriteHeader(http.StatusForbidden)
_, _ = response.Write([]byte(denyBody))
}
}
可以看出,此函数对请求的header进行了判断。如果header的值是allowedValue
就返回200(允许通过),其他情况返回403(不允许通过)。
配置自定义授权服务
在ACK集群中部署上一步开发的自定义授权服务后,您可以开始自定义授权服务的接入。具体操作,请参见接入HTTP协议的自定义授权服务。
由于此授权服务中用到了checkHeader
这个变量对应的header,所以您需要在网格中导入自定义授权服务时配置在鉴权请求中携带header配置项,否则无法获取到对应的返回结果。