

Kubernetes: kube-apiserver 之认证 - lubanseven
source link: https://www.cnblogs.com/xingzheanan/p/17818588.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

kubernetes:kube-apiserver
系列文章:
kube-apiserver
不仅负责 RESTful API
路由的建立,也负责请求的认证,授权和准入。如下图所示:

本篇文章将介绍 kube-apiserver
的认证机制。
1. 认证 Authentication
认证是对请求的认证,确认请求是否具有访问 Kubernetes
集群的权限。在 kube-apiserver
中,通过 handler
处理请求的认证,所有请求都将通过认证 handler
进行认证。可以把它理解成 Gin
框架的中间件。
1.1 认证 handler
首先,从认证 handler
的创建过程入手。
# kubernetes/vendor/k8s.io/apiserver/pkg/server/config.go
// 进入 GenericAPIServer 的创建函数 New
func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*GenericAPIServer, error) {
handlerChainBuilder := func(handler http.Handler) http.Handler {
return c.BuildHandlerChainFunc(handler, c.Config)
}
apiServerHandler := NewAPIServerHandler(name, c.Serializer, handlerChainBuilder, delegationTarget.UnprotectedHandler())
...
}
# kubernetes/vendor/k8s.io/apiserver/pkg/server/config.go
func NewAPIServerHandler(name string, s runtime.NegotiatedSerializer, handlerChainBuilder HandlerChainBuilderFn, notFoundHandler http.Handler) *APIServerHandler {
...
director := director{
name: name,
goRestfulContainer: gorestfulContainer,
nonGoRestfulMux: nonGoRestfulMux,
}
return &APIServerHandler{
// 创建 FullHandlerChain
FullHandlerChain: handlerChainBuilder(director),
GoRestfulContainer: gorestfulContainer,
NonGoRestfulMux: nonGoRestfulMux,
Director: director,
}
}
这里 FullHandlerChain
内装有认证 handler
。继续看哪里定义 handlerChainBuilder
函数的。
# kubernetes/vendor/k8s.io/apiserver/pkg/server/config.go
func NewConfig(codecs serializer.CodecFactory) *Config {
return &Config{
...
BuildHandlerChainFunc: DefaultBuildHandlerChain,
}
}
# kubernetes/vendor/k8s.io/apiserver/pkg/server/config.go
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences, c.Authentication.RequestHeaderConfig)
return handler
}
# kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication.go
func WithAuthentication(handler http.Handler, auth authenticator.Request, failed http.Handler, apiAuds authenticator.Audiences, requestHeaderConfig *authenticatorfactory.RequestHeaderConfig) http.Handler {
return withAuthentication(handler, auth, failed, apiAuds, requestHeaderConfig, recordAuthenticationMetrics)
}
在创建配置 Config
时,将 DefaultBuildHandlerChain
赋值给 BuildHandlerChainFunc
。DefaultBuildHandlerChain
内的 genericapifilters.WithAuthentication
创建了认证 handler
。
接着往下走,进入 genericapifilters.WithAuthentication
。
func withAuthentication(handler http.Handler, auth authenticator.Request, failed http.Handler, apiAuds authenticator.Audiences, requestHeaderConfig *authenticatorfactory.RequestHeaderConfig, metrics authenticationRecordMetricsFunc) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
resp, ok, err := auth.AuthenticateRequest(req)
// authorization header is not required anymore in case of a successful authentication.
req.Header.Del("Authorization")
req = req.WithContext(genericapirequest.WithUser(req.Context(), resp.User))
handler.ServeHTTP(w, req)
})
}
type Request interface {
AuthenticateRequest(req *http.Request) (*Response, bool, error)
}
可以看到,认证 handler
中通过 auth.AuthenticateRequest(req)
对 RESTful API
请求进行认证。这里 auth
是一个实现 Request
接口的实例。
那么,auth
实例是在哪里创建的呢,调用的 AuthenticateRequest
方法具体做的是什么呢?带着这个问题我们看下一节认证实例。
1.2 认证实例
通过层层回溯找到调用点。
handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences, c.Authentication.RequestHeaderConfig)
这里 c.Authentication.Authenticator
即为 auth
的实例。我们看 c.Authentication.Authenticator
是在哪里创建的。
# kubernetes/pkg/controlplane/apiserver/config.go
func BuildGenericConfig(
s controlplaneapiserver.CompletedOptions,
schemes []*runtime.Scheme,
getOpenAPIDefinitions func(ref openapicommon.ReferenceCallback) map[string]openapicommon.OpenAPIDefinition,
) (
genericConfig *genericapiserver.Config,
versionedInformers clientgoinformers.SharedInformerFactory,
storageFactory *serverstorage.DefaultStorageFactory,
lastErr error,
) {
// Authentication.ApplyTo requires already applied OpenAPIConfig and EgressSelector if present
if lastErr = s.Authentication.ApplyTo(&genericConfig.Authentication, genericConfig.SecureServing, genericConfig.EgressSelector, genericConfig.OpenAPIConfig, genericConfig.OpenAPIV3Config, clientgoExternalClient, versionedInformers); lastErr != nil {
return
}
}
# kubernetes/pkg/kubeapiserver/options/authentication.go
func (o *BuiltInAuthenticationOptions) ApplyTo(authInfo *genericapiserver.AuthenticationInfo, secureServing *genericapiserver.SecureServingInfo, egressSelector *egressselector.EgressSelector, openAPIConfig *openapicommon.Config, openAPIV3Config *openapicommon.Config, extclient kubernetes.Interface, versionedInformer informers.SharedInformerFactory) error {
authenticatorConfig, err := o.ToAuthenticationConfig()
if err != nil {
return err
}
...
authInfo.Authenticator, openAPIConfig.SecurityDefinitions, err = authenticatorConfig.New()
}
c.Authentication.Authenticator
实际是 authenticatorConfig.New()
创建的 authInfo.Authenticator
认证器。进入 authenticatorConfig.New()
看创建认证器过程。
# kubernetes/pkg/controlplane/apiserver/config.go
func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, error) {
var authenticators []authenticator.Request
var tokenAuthenticators []authenticator.Token
securityDefinitions := spec.SecurityDefinitions{}
// front-proxy, BasicAuth methods, local first, then remote
// Add the front proxy authenticator if requested
if config.RequestHeaderConfig != nil {
requestHeaderAuthenticator := headerrequest.NewDynamicVerifyOptionsSecure(
config.RequestHeaderConfig.CAContentProvider.VerifyOptions,
config.RequestHeaderConfig.AllowedClientNames,
config.RequestHeaderConfig.UsernameHeaders,
config.RequestHeaderConfig.GroupHeaders,
config.RequestHeaderConfig.ExtraHeaderPrefixes,
)
authenticators = append(authenticators, authenticator.WrapAudienceAgnosticRequest(config.APIAudiences, requestHeaderAuthenticator))
}
// X509 methods
if config.ClientCAContentProvider != nil {
certAuth := x509.NewDynamic(config.ClientCAContentProvider.VerifyOptions, x509.CommonNameUserConversion)
authenticators = append(authenticators, certAuth)
}
...
authenticator := union.New(authenticators...)
authenticator = group.NewAuthenticatedGroupAdder(authenticator)
return authenticator, &securityDefinitions, nil
}
# kubernetes/vendor/k8s.io/apiserver/pkg/authentication/request/union/union.go
func New(authRequestHandlers ...authenticator.Request) authenticator.Request {
if len(authRequestHandlers) == 1 {
return authRequestHandlers[0]
}
return &unionAuthRequestHandler{Handlers: authRequestHandlers, FailOnError: false}
}
# kubernetes/vendor/k8s.io/apiserver/pkg/authentication/group/authenticated_group_adder.go
func NewAuthenticatedGroupAdder(auth authenticator.Request) authenticator.Request {
return &AuthenticatedGroupAdder{auth}
}
可以看到,认证器是一系列认证器的组合。每个认证器包括组合的认证器都实现了 authenticator.Request
接口的 AuthenticateRequest
方法。
回头看在 handler
中定义的 auth.AuthenticateRequest(req)
方法,实际执行的是 authenticator.AuthenticateRequest(req)
。
# kubernetes/vendor/k8s.io/apiserver/pkg/authentication/group/authenticated_group_adder.go
func (g *AuthenticatedGroupAdder) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
r, ok, err := g.Authenticator.AuthenticateRequest(req)
if err != nil || !ok {
return nil, ok, err
}
}
# kubernetes/vendor/k8s.io/apiserver/pkg/authentication/request/union/union.go
func (authHandler *unionAuthRequestHandler) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
var errlist []error
for _, currAuthRequestHandler := range authHandler.Handlers {
resp, ok, err := currAuthRequestHandler.AuthenticateRequest(req)
if err != nil {
if authHandler.FailOnError {
return resp, ok, err
}
errlist = append(errlist, err)
continue
}
if ok {
return resp, ok, err
}
}
return nil, false, utilerrors.NewAggregate(errlist)
}
通过层层调用,最终执行到 unionAuthRequestHandler.AuthenticateRequest
。该方法中循环执行各个认证器的 AuthenticateRequest
方法,直到认证成功。
各认证器的认证方式不同,这里就不过多介绍了,具体涉及到各种认证方式的时候可详细看相应认证器的 AuthenticateRequest
方法。
通过本篇文章介绍了 kube-apiserver
中的 Authentication
认证流程,下一篇将继续介绍 kube-apiserver
的 Authorization
授权流程。
Recommend
-
32
本文通过记录kubelet连接apiserver超时问题的原因及修复办法。 上篇文章回顾:一文读懂HBase多租户 背 景 kubernetes是ma...
-
3
字节跳动 kube-apiserver 高可用方案 KubeGateway 2022年10月31日 06:30 · 阅读 756
-
11
Apr 24, 2020 · cloudkube-apiserver启动流程分析kube-apiserver 共由 3 个组件构成(Aggregator. KubeAPIServe...
-
2
Jan 31, 2020 · cloudkube-apiserver认证源码分析kube-apiserver 中与权限相关的主要有三种机制,即认证、鉴权...
-
9
Apr 23, 2020 · cloudkube-apiserver鉴权源码分析kube-apiserver 中与权限相关的主要有三种机制,即认证、鉴权...
-
6
Kubernetes:kube-apiserver 之 scheme(一) 在进入 kube-apiserver 源码分析前,有一...
-
7
kubernetes:kube-apiserver 系列文章: 上一篇文章介绍了 kube-apiserver 的认证机制。这里继续往下走,介绍 kube-apiserver 的鉴权。kube-apiserver 处理认证和鉴权非常类似,建议阅读鉴权机...
-
4
聊聊 Kube-Apiserver 内存优化进阶 作者:Kaku 2023-12-02 20:41:32 Kube-apiserver 内存优化系系列包含前面的铺垫,到此也 6 篇了,如果把这其中涉及到的知识都搞懂了,对 kube-apiserver 的理解一定可以上一个台...
-
8
Kubernetes:kube-scheduler 源码分析 介绍了 kube-scheduler 调度 Pod 的逻辑。文中有一点未提的是,在 Kubernetes 集群中,kube-scheduler...
-
2
在 Kubernetes 架构中,controller manager 是一个永不休止的控制回路组件,其负责控制集群资源的状态。通...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK