函数一开始也是创建了一个authorizers的数组,用于存放启用的授权方式。遍历config.AuthorizationModes,对对应的授权方式进行实例化。最后调用union.New(authorizers...),以一个unionAuthzHandler作为支持的所有授权方式的wrapper返回回去。
授权方式有6种,分别是AlwaysAllow,AlwaysDeny,RBAC,ABAC,Node,Webhook。其中最常用的就是RBAC,k8s里面给sa绑定role和clusterrole进行授权的就是这个RBAC。
授权逻辑跟前文介绍认证一样通过HandlerChain串起来,同样在DefaultBuildHandlerChain函数中被加到HandlerChain中,调用了genericapifilters.WithAuthorization函数,代码位于/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization.go
func WithAuthorization(handler http.Handler, a authorizer.Authorizer, s runtime.NegotiatedSerializer) http.Handler { if a == nil { klog.Warningf("Authorization is disabled") return handler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx := req.Context() ae := request.AuditEventFrom(ctx) attributes, err := GetAuthorizerAttributes(ctx) if err != nil { responsewriters.InternalError(w, req, err) return } authorized, reason, err := a.Authorize(ctx, attributes) // an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here. if authorized == authorizer.DecisionAllow { audit.LogAnnotation(ae, decisionAnnotationKey, decisionAllow) audit.LogAnnotation(ae, reasonAnnotationKey, reason) handler.ServeHTTP(w, req) return } if err != nil { audit.LogAnnotation(ae, reasonAnnotationKey, reasonError) responsewriters.InternalError(w, req, err) return } klog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason) audit.LogAnnotation(ae, decisionAnnotationKey, decisionForbid) audit.LogAnnotation(ae, reasonAnnotationKey, reason) responsewriters.Forbidden(ctx, attributes, w, req, reason, s) }) }处理函数中,先调用GetAuthorizerAttributes获取认证后得到的user信息以及请求资源的相关信息requestInfo,统一放到attributes,再调用授权的方法 a.Authorize。同样它也是一个接口,它与认证时类似,先调用一个unionAuthzHandler的wrapper,在这个wrapper里遍历各个启用的authorizer。只要里面有一个allow或deny的结果就立马返回,代码位于/vendor/k8s.io/apiserver/pkg/authorization/union/union.go
func (authzHandler unionAuthzHandler) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { var ( errlist []error reasonlist []string ) for _, currAuthzHandler := range authzHandler { decision, reason, err := currAuthzHandler.Authorize(ctx, a) if err != nil { errlist = append(errlist, err) } if len(reason) != 0 { reasonlist = append(reasonlist, reason) } switch decision { case authorizer.DecisionAllow, authorizer.DecisionDeny: return decision, reason, err case authorizer.DecisionNoOpinion: // continue to the next authorizer } } return authorizer.DecisionNoOpinion, strings.Join(reasonlist, "\n"), utilerrors.NewAggregate(errlist) } AdmissionWebhook