kubernetes:kube-apiserver 系列文章:

0. 前言

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 赋值给 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 授权流程。


Kubernetes: kube-apiserver 之认证的更多相关文章

  1. Kubernetes 学习17 dashboard认证及分级授权

    一.概述 1.我们前面介绍了kubernetes的两个东西,认证和授权 2.在kubernetes中我们对API server的一次访问大概会包含哪些信息?简单来讲它是restfule风格接口,也就是 ...

  2. kubernetes集群的认证、授权、准入控制

    一.kubernetes集群安全架构 用户使用kubectl.客户机或通过REST请求访问API.可以授权用户和Kubernetes服务帐户进行API访问.当一个请求到达API时,它会经历几个阶段,如 ...

  3. kubernetes 身份与权限认证 (ServiceAccount && RBAC)

    Kubernetes中提供了良好的多租户认证管理机制,如RBAC.ServiceAccount还有各种Policy等.   ServiceAccount Service Account为Pod中的进程 ...

  4. 浅入Kubernetes(6):CKAD认证中的部署教程

    目录 预设网络 kubeadm 安装 k8s 配置 calico 自动补全工具 状态描述 目前为止,笔者已经写了 5 篇关于 k8s 的文章,这一篇笔者将介绍 CKAD 认证官方课程中,如何部署 k8 ...

  5. kubernetes的apiserver

    1. API Server简介 k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心. ...

  6. Kubernetes Dashboard 安装与认证

    1.安装dashboard $ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/ ...

  7. 【云原生 · Kubernetes】apiserver高可用

    个人名片: 因为云计算成为了监控工程师‍ 个人博客:念舒_C.ying CSDN主页️:念舒_C.ying 7.1 高可用选型 ipvs+keepalived nginx+keepalived hap ...

  8. kubernetes认证和serviceaccount

    Service Account 为 Pod 提供必要的身份认证.所有的 kubernetes 集群中账户分为两类,Kubernetes 管理的 serviceaccount(服务账户) 和 usera ...

  9. kubernetes Dashboard 使用RBAC 权限认证控制

    kubernetes RBAC实战 环境准备 先用kubeadm安装好kubernetes集群,[包地址在此](https://market.aliyun.com/products/56014009/ ...

  10. kubernetes对接第三方认证

    kubernetes对接第三方认证 kubernetes离线安装包地址 概述 本文介绍如何使用github账户去关联自己kubernetes账户.达到如下效果: 使用github用户email作为ku ...

随机推荐

  1. 进程相关API

    ID与句柄 如果我们成功创建一个进程,CreateProcess函数会给我们返回一个结构体,包括四个数 据:进程编号(ID).进程句柄.线程编号(ID).线程句柄. 进程ID其实我们早见过了,通常我们 ...

  2. K8S | Deployment应用编排

    目录 一.背景 二.Deployment组件 1.简介 2.语法说明 三.基础用例 1.创建操作 2.查看信息 3.更新操作 4.删除操作 四.进阶用例 1.回滚操作 2.伸缩操作 3.暂停与恢复 五 ...

  3. Linux 脚本:shell

    # 以脚本所在目录作为脚本执行时的当前路径. -P 选项寻找物理上的地址,忽略软连接. SCRIPT_DIR=$(cd $(dirname $0); pwd -P) # 在任意位置执行自己的可执行程序 ...

  4. 何为DDD

    从这一刻开始,请大家忘记自己是一名技术人员,用业务的角度来思考问题. 1.什么是DDD DDD(Domain-driven design,领域驱动设计),是一个很好的应用于微服务架构的方法论 DDD要 ...

  5. 使用gulp.js打包layuiAdmin

    安装nvm 在nvm目录下,找到settings.txt,追加以下两行加速nvm(淘宝镜像)node_mirror: https://npm.taobao.org/mirrors/node/npm_m ...

  6. VScode 中golang 基准测试 go test -bench .

    目的:基准测试的主要目的是比较不同实现方式之间的性能差异,找出性能瓶颈. 1 准备以_test.go结尾文件和导入testing包 在命名文件时需要让文件必须以_test结尾,在文件中导入testin ...

  7. C++ 核心指南之 C++ 哲学/基本理念(下)

    C++ 核心指南(C++ Core Guidelines)是由 Bjarne Stroustrup.Herb Sutter 等顶尖 C+ 专家创建的一份 C++ 指南.规则及最佳实践.旨在帮助大家正确 ...

  8. Html+JavaScript实现手写签名

    前言 Hello各位,本葡萄又来啦,今天遇到的场景是这样的:在日常业务流程中,经常需要某一流程环节中相关责任人员进行审批签字,早期许多公司为了省事就直接会把这位负责人的签名以键盘打字(楷体)的形式打印 ...

  9. PHP上传文件$_FILES, $_POST为空 empty 时, 文件上传大小限制

    原因 今天在使用ci upload库时, 上传mp4发现表单为空, 上传png等类型却可以正常. 折腾一番后才恍然, PHP上传大小限制的问题. Make一下. 真是失策啊, 一开始我还不相信到处瞎折 ...

  10. 研发效能|DevOps 是运维还是开发?

    DevOps 到底是 Dev还是Ops?答:属于研发工程师序列,偏向研发域,而不是运维域. DevOps是研发工程师 DevOps 主要服务的对象就是所有产研团队的人员,与产研团队打交道比较多,相互配 ...