apiserver分析(一)-authenticator-v1.5.2
什么是Authenticator
Authenticator负责Kubernetes中对请求进行认证,只有通过认证的请求才会被执行。在Kubernetes中,有BasicAuth, Keystone, X509, Token, ServiceAccount, OIDCIssuer, WebhookToken, AnyToken等认证器。本次分析将介绍Kubernetes是如何管理认证器的,及如何对请求进行认证。
认证器的生成
认证器的生成在/cmd/kube-apiserver/app/server.go的Run()函数中:
|
|
所以,接下来看authenticator.New(),定义在/pkg/apiserver/authenticator/authn.go中:
|
|
New()会根据kube-apiserver的参数来生成各个认证器,并把认证器放在authenticators变量中。比如,如果指定了–experimental-keystone-url,则就会生成keystoneAuthenticator。这里要强调的是unionAuthenticator可以封装多个认证器,关于unionAuthenticator,稍后分析。
这里还要涉及到一个概念,GroupAdder,封装了authenticator,定义在/pkg/auth/group/group_adder.go中:
|
|
New()会根据kube-apiserver的参数来生成各个认证器,并把认证器放在authenticators变量中。比如,如果指定了–experimental-keystone-url,则就会生成keystoneAuthenticator。这里要强调的是unionAuthenticator可以封装多个认证器,关于unionAuthenticator,稍后分析。
这里还要涉及到一个概念,GroupAdder,封装了authenticator,定义在/pkg/auth/group/group_adder.go中:
|
|
所以,kube-apiserver的认证器就一个GroupAdder,GroupAdder定义有认证的入口:
|
|
GroupAdder的AuthenticateRequest()会调用unionAuthenticator的AuthenticateRequest()对请求进行认证,得到user信息之后返回。
关于Group,定义在/pkg/auth/user/user.go中,authenticator.New()传入的是AllAuthenticated,估计是为了把该用户标记为已经通过认证。但现在还不知道user为什么要这么分类。
|
|
unionAuthenticator
unionAuthenticator定义在/plugin/pkg/auth/authenticator/request/union/union.go:
|
|
unionAuthenticator的AuthenticateRequest()方法定义如下:
|
|
AuthenticateRequest()会轮询每一个authenticator,如果有一个authenticator认证成功,则直接返回认证成功。
keystoneAuthenticator
接下来回到/pkg/apiserver/authenticator/authn.go的New()中。New()调用newAuthenticatorFromKeystoneURL()生成keystoneAuthenticator。newAuthenticatorFromKeystoneURL()定义如下:
|
|
其中,basicAuthenticator封装了keystoneAuthenticator的AuthenticatePassword()方法,定义在/plugin/pkg/auth/authenticator/request/basicauth/basicauth.go中:
|
|
可以看出,basicAuthenticator实现了AuthenticateRequest(),该方法会从请求中获取用户名和密码,然后调用所封装的认证器的AuthenticatePassword()方法进行认证。
回到正题来看keystoneAuthenticator。keystoneAuthenticator实现了authenticatePassword()方法。keystoneAuthenticator定义在/pkg/auth/authenticator/password/keystone/keystone.go中:
|
|
再来看下authenticatePassword()方法:
|
|
实现也很简单,生成openstack client,然后去认证用户名和密码,最后返回的是user。
对请求进行认证
现在来看下如何对请求进行处理。
在GenericAPIServer结构体(定义在/pkg/genericapiserver/genericapiserver.go中)中,有HandlerContainer和Handler两个字段。其中HandlerContainer封装了所有的API处理函数,具体如何封装以后分析;而Handler在HandlerContainer的基础上还封装了授权,认证等处理函数。详见/pkg/genericapiserver/config.go:
|
|
以WithAuthentication()为例来看下是如何对handler进行层层封装的。WithAuthentication()定义在/pkg/auth/handlers/handlers.go中:
|
|
其中,http.HandlerFunc本身就是一个handler。所以WithAuthentication()先调用auth.AuthenticateRequest()对请求进行验证,然后调用前handler的ServeHTTP()对请求接着作处理,以达到在处理前进行认证的目的。
回到DefaultBuildHandlerChain(),调用DefaultBuildHandlerChain()函数的地方在/pkg/genericapiserver/config.go中的New()方法中:
|
|
其中,BuildHandlerChainsFunc就是DefaultBuildHandlerChain。可见,Handler是在handlerContainer的基础上封装了protect和generic;InsecureHandler是在handlerContainer的基础上封装了audit和generic。
那么,是怎样关联server和handler呢?
来看/pkg/genericapiserver/genericapiserver.go中preparedGenericAPIServer的Run()方法:
|
|
在Run()方法中,有serveSecurely()和serveInsecuurely()两个函数调用,这两个函数定义在/pkg/genericapiserver/serve.go中:
|
|
可以看出,这两个函数中的server的Handler分别为s.Handler和s.InsecureHandler。在来看下runServer():
|
|
runServer()中会开始监听端口,并把请求交给Handler或InsecureHandler进行处理。