apiserver源码分析——处理请求

上一篇说道k8s-apiserver如何启动,本篇则介绍apiserver启动后,接收到客户端请求的处理流程。如下图所示

gn="center">avatar


认证与授权一般系统都会使用到,认证是鉴别访问apiserver的请求方是谁,一般情况下服务端是需要知晓客户端是谁方可接受请求,除了允许匿名访问这种场景,同时认证也为后续的授权提供基础。授权是为了判断当前请求的客户端是否具备请求当前资源的权限,具备则放行让其继续往后走,否则拒绝本次请求。准入控制器为请求处理流程提供了一个扩展的口,它提供了两个回调的钩子,能让用户在资源持久化前再额外对资源的值作改动或者验证,如果验证出错同样可以终止整个处理流程。最后对资源的变更会持久化到Etcd。

本篇以创建pod为例,探索apiserver如何处理。

Authentication

请求到达apiserver后第一个是需要进行认证,辨别请求来源的身份。认证方式的配置在上一篇讲述构建genericConfig的时候有提及,在执行buildGenericConfig函数时调用s.Authentication.ApplyTo配置

代码位于/pkg/kubeapiserver/options/authentication.go

func (o *BuiltInAuthenticationOptions) ApplyTo(authInfo *genericapiserver.AuthenticationInfo,.....) error { //创建出authenticatorConfig authenticatorConfig, err := o.ToAuthenticationConfig() //对authenticatorConfig字段进行设置 ... //创建出Authenticator authInfo.Authenticator, openAPIConfig.SecurityDefinitions, err = authenticatorConfig.New() }

ApplyTo先创建出认证相关配置authenticatorConfig,然后初始化部分认证方式的Provider,最终调用authenticatorConfig.New方法将按照认证的配置信息构造出一个Authenticator,传递给authInfo.Authenticator

Authenticator.New方法如下所示,定义了两个数组用于存放启用的authenticators和token类的authenticators,根据Config的配置信息按需启用认证方式,再将token类的authenticators转换成普通的authenticators。最终将这个authenticator传递给一个Wrapper类型UnionAuthenticator返回

代码位于/pkg/kubeapiserver/authenticator/config.go

func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, error) { var authenticators []authenticator.Request var tokenAuthenticators []authenticator.Token //各种认证方式的初始化操作 ... if len(tokenAuthenticators) > 0 { // Union the token authenticators tokenAuth := tokenunion.New(tokenAuthenticators...) // Optionally cache authentication results if config.TokenSuccessCacheTTL > 0 || config.TokenFailureCacheTTL > 0 { tokenAuth = tokencache.New(tokenAuth, true, config.TokenSuccessCacheTTL, config.TokenFailureCacheTTL) } authenticators = append(authenticators, bearertoken.New(tokenAuth), websocket.NewProtocolAuthenticator(tokenAuth)) securityDefinitions["BearerToken"] = &spec.SecurityScheme{ SecuritySchemeProps: spec.SecuritySchemeProps{ Type: "apiKey", Name: "authorization", In: "header", Description: "Bearer Token authentication", }, } } if len(authenticators) == 0 { if config.Anonymous { return anonymous.NewAuthenticator(), &securityDefinitions, nil } return nil, &securityDefinitions, nil } authenticator := union.New(authenticators...) authenticator = group.NewAuthenticatedGroupAdder(authenticator) }

在这里简单列举一下上述提到的多种认证类型,包括9种,分别是:BasicAuth,TokenAuth,BootstrapToken,OIDC,RequesHeader,WebhookTokenAuth,Anonymous,ClientCA,ServiceAccountAuth。鄙人为了方便记忆分别将他们归为3类

token类:TokenAuth,BootstrapToken,WebhookTokenAuth,OIDC

证书类:ClientCA,ServiceAccountAuth

其他类:BasicAuth,RequesHeader,Anonymous

由于篇幅原因各种配置类型的特点则不展开介绍

特别地提及一下,pod里面访问apiserver一般用的是ServiceAccountAuth;在进行apiserver-aggregrate双向认证的时候会用到clientCA;往k8s添加新节点时kubelet会用到BootstrapToken

认证在请求过程是一个HandlerChain串起来的,每个handler函数的构建时都会里层的handler函数,待本层handler处理完毕后才会执行里层的handler,这样一层层执行最后才执行到真正的请求响应逻辑,如Pod创建

回归到上篇介绍的buildGenericConfig函数,一开始调用了 genericapiserver.NewConfig,NewConfig创建Config结构时给BuildHandlerChainFunc字段传入DefaultBuildHandlerChain这个函数

代码位于 /vendor/k8s.io/apiserver/pkg/server/config.go

func NewConfig(codecs serializer.CodecFactory) *Config { return &Config{ Serializer: codecs, BuildHandlerChainFunc: DefaultBuildHandlerChain, ... } } func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler := genericapifilters.WithAuthorization(apiHandler, c.Authorization.Authorizer, c.Serializer) if c.FlowControl != nil { handler = genericfilters.WithPriorityAndFairness(handler, c.LongRunningFunc, c.FlowControl) } else { handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc) } handler = genericapifilters.WithImpersonation(handler, c.Authorization.Authorizer, c.Serializer) handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyChecker, c.LongRunningFunc) failedHandler := genericapifilters.Unauthorized(c.Serializer) failedHandler = genericapifilters.WithFailedAuthenticationAudit(failedHandler, c.AuditBackend, c.AuditPolicyChecker) handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences) handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup) handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver) if c.SecureServing != nil && !c.SecureServing.DisableHTTP2 && c.GoawayChance > 0 { handler = genericfilters.WithProbabilisticGoaway(handler, c.GoawayChance) } handler = genericapifilters.WithAuditAnnotations(handler, c.AuditBackend, c.AuditPolicyChecker) handler = genericapifilters.WithWarningRecorder(handler) handler = genericapifilters.WithCacheControl(handler) handler = genericapifilters.WithRequestReceivedTimestamp(handler) handler = genericfilters.WithPanicRecovery(handler) return handler }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpsds.html