首页 > 其他分享 >Kubernetes: kube-apiserver 之认证

Kubernetes: kube-apiserver 之认证

时间:2023-11-08 23:23:53浏览次数:42  
标签:authenticator http Kubernetes 认证 apiserver handler return kube


kubernetes:kube-apiserver 系列文章:

0. 前言

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

image

本篇文章将介绍 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 赋值给 BuildHandlerChainFuncDefaultBuildHandlerChain 内的 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 方法。

2. 总结

通过本篇文章介绍了 kube-apiserver 中的 Authentication 认证流程,下一篇将继续介绍 kube-apiserverAuthorization 授权流程。


标签:authenticator,http,Kubernetes,认证,apiserver,handler,return,kube
From: https://www.cnblogs.com/xingzheanan/p/17818588.html

相关文章

  • 【Kubernetes】Calico CrossSubnet 模式实
    网络环境主机名宿主机IP地址k8s-master1192.168.3.241k8s-master2192.168.3.242k8s-master3192.168.3.243k8s-node1192.168.32.105注意:k8s-node1是32.0/24网段,跟其他三个节点不同网段。部署VxlanCroossSubnet修改calico.yaml,将CALICO_IPV4POOL_I......
  • 一、minikube部署单机k8s环境
    一、minikube部署单机k8s环境注意:此处为方便测试,使用minikube部署单机k8s环境,生产环境请根据实际情况操作1.安装docker-ce依赖安装:yuminstall-yyum-utilsdevice-mapper-persistent-datalvm2wget添加docker软件源:yum-config-manager--add-repohttps://mirrors.aliyun.co......
  • kubeasz搭建k8s高可用集群
     kubeasz致力于快速部署高可用k8s集群的工具,同时也努力成为k8s实践、使用的参考书;基于二进制方式部署和ansible-playbook实现自动化;既提供一键安装脚本,可以刻根据安装指南分布执行安装各个组件。 Kubeasz从每一个单独部件组装到完整的集群,提供最灵活的配置能力,几乎可以设置任......
  • 基于k8s安装kubesphere:镜像prometheus-k8s-0一直处于Init
    系统Centos7k8s版本v.1.28.0(自签证书)kubesphere版本v3.4.0问题:Output:mount.nfs:mounting192.168.2.21:/data/kubesphere-monitoring-system-prometheus-k8s-db-prometheus-k8s-0-pvc-c69f1491-3980-4cdf-abcb-6e05843f0b9bfailed,reasongivenbyser......
  • kubernetes最新版部署
    部署最新1.28.2-0版本kuberneteskubernetes集群规划主机名IP地址备注k8s-master1192.168.2.24master1k8s-master2192.168.2.25master2k8s-master3192.168.2.26master3k8s-master-lb192.168.2.36keepalived虚拟IPk8s-node1192.168.2.27node1k......
  • KubeZoo协议转换
    目的KubeZoo基于协议转换核心理念实现控制面多租户功能,通过在资源的name/namespace等字段上增加租户的唯一标识,解决不同租户的同名资源在同一个上游k8s集群命名冲突的问题。架构KubeZoo:由无状态的kubezoo-server和Etcd组成。K8SMasterMaster:apiserver/scheduler/controller......
  • 云原生架构实战06 Kubernetes的核心概念
    一、有状态和无状态二、对象规约和状态spec是规约规格的意思,描述了对象的期望状态--希望对象所具有的特征,当创建Kubernetes对象是,必须提供兑现对象的规约,用来描述该对象的期望状态,以及关于对象的一些基本信息(名称)状态status:表示对象的实际状态,该属性由k8s自己维护,会通过一系列......
  • Kubernetes:kube-apiserver 和 etcd 的交互
    kubernetes:kube-apiserver系列文章:Kubernetes:kube-apiserver之scheme(一)Kubernetes:kube-apiserver之scheme(二)Kubernetes:kube-apiserver之启动流程(一)Kubernetes:kube-apiserver之启动流程(二)0.前言上几篇文章介绍了kubernetes的核心数据结构scheme......
  • kubernetes驱逐机制总结
    概述k8s的驱逐机制是指在某些场景下,如node节点notReady、node节点压力较大等,将pod从某个node节点驱逐掉,让pod的上层控制器重新创建出新的pod来重新调度到其他node节点。这里也将kube-scheduler的抢占调度纳入到了驱逐的讨论范围内,因为当调度高优先级的pod时发现资源不足,会驱逐掉n......
  • Kubernetes:kube-apiserver 之启动流程(二)
    接着Kubernetes:kube-apiserver之启动流程(一)加以介绍。1.2.2创建APIExtensionsServer创建完通用APIServer后继续创建APIExtensionsServer。func(ccompletedConfig)New(delegationTargetgenericapiserver.DelegationTarget)(*CustomResourceDefinitions,erro......