本文章基于 k8s release-1.17 分支代码,代码位于 plugin/pkg/admission/serviceaccount 目录,代码:admission.go[1] 。
api-server 作为常用的服务端应用,包含认证模块 Authentication、授权模块 Authorization 和准入模块 Admission Plugin(可以理解为请求中间件模块 middleware pipeline),以及存储依赖 Etcd。其中,针对准入插件,在 api-server 进程启动时,启动参数 –enable-admission-plugins 需要包含 ServiceAccount 准入控制器来开启该中间件,可以见官方文档:enable-admission-plugins[2] 。ServiceAccount Admission Plugin 主要作用包含:
- 如果提交的 pod yaml 里没有指定 spec.serviceAccountName 字段值,该插件会添加默认的 default ServiceAccount;
- 判断 spec.serviceAccountName 指定的 service account 是否存在,不存在就拒绝请求;
- 为该 pod 创建个 volume,且该 volume source 是 SecretVolumeSource,该 secret 来自于 service account 对象引用的 secret;
- 如果提交的 pod yaml 里没有指定 spec.ImagePullSecrets 字段值,那就将 service account 对象引用的 ImagePullSecrets 字段值来补位,并且该 volume 会被 mount 到 pod 的 /var/run/secrets/kubernetes.io/serviceaccount 目录中;
比如,往 api-server 进程提交个 pod 对象:
就会看到该 pod 对象被 ServiceAccount Admission Plugin 处理后,spec.serviceAccountName 指定了 default ServiceAccount;增加了个 SecretVolumeSource 的 Volume,volume name 为 ServiceAccount 的 secrets 的 name 值,mount 到 pod 的 /var/run/secrets/kubernetes.io/serviceaccount目录中;以及因为 pod 和 default service account 都没有指定 ImagePullSecrets 值,pod 的 spec.ImagePullSecrets 没有值:

serviceaccount_admission_plugin
并且,volume 指定的 secret name 是 default service account 的 secrets 的 name 值:

serviceaccount_default
那么,有个问题,ServiceAccount Admission Controller 或者说 ServiceAccount 中间件,是如何做到的呢?
就和我们经常见到的一些服务端框架做的 middleware 中间件模块一样,api-server 框架也是用插件化形式来定义一个个准入控制器 Admission Controller,并且会调用该插件的Admit()方法, 来判断当前请求是否通过该准入控制器。
AdmissionController 准入控制器实例化
实例化操作很简单,需要注意的是:MountServiceAccountToken 为 true,表示默认去执行 mount volume 操作,且 mount 到 pod 的默认目录;并且资源操作是 Create 操作时才去执行当前准入控制器。代码见 L103-L121[3]:
Admit 操作
Admit 操作是该中间件的核心逻辑,主要工作上文已经详细描述,这里从代码角度学习下,代码见:L160-L248[4] 。
ServiceAccount 检查
首先是检查 pod yaml 中有没有指定 ServiceAccount,没有指定就设置默认的default ServiceAccount 对象,并且同时检查该 ServiceAccount 在当前 namespace 内是否真的存在:
ServiceAccount 检查逻辑很简单,主要目的是为 pod 填补 ServiceAccount 值,因为服务账号就是给 pod 调用 api-server 进程用的,关于服务账号 ServiceAccount 作用可见官网:用户账号与服务账号[5]
Mount Volume
Mount Volume 核心就是会创建个 volume,并 mount 到 pod 每个容器内指定目录,该目录下包含 ca.crt、namespace和token文件 ,供 pod 调用 api-server 时使用。从源码角度看看如何创建 volume 以及如何 mount 的 L426-L567[6] :
Mount Volume 逻辑也很简单,主要就是为 pod 创建个 volume,并且 mount 到每一个容器的指定路径。该 volume 内包含的数据来自于 ServiceAccount 引用的 secrets 的数据,即 ca.crt、namespace和token 数据文件,这些数据是调用 api-server 时需要的认证数据,且 token 数据已经经过私钥文件签名过了。

那么有个问题,创建 ServiceAccount 时对应的这些 secret 对象是怎么来的呢?secret 里的 token 文件既然已经被私钥签名过,那 api-server 必然需要对应的公钥文件来验证签名才对?至于 secret 对象是怎么来的问题,这是 kube-controller-manager 里的 ServiceAccount 模块的 TokenController 创建的,创建时会用私钥进行签名,所以 kube-controller-manager 启动时必须带上私钥参数 –service-account-private-key-file ,具体可见官网 service-account-private-key-file[7] ;至于 api-server 必须使用对应的公钥来验证签名,同理,kube-apiserver 启动时,也必须带上公钥参数 –service-account-key-file ,具体可见官网 service-account-key-file[8]
本文分析了 ServiceAccount Admission Controller 中间件的主要业务逻辑,如何为 pod 对象补充 serviceAccount、imagePullSecrets 字段数据, 以及创建并挂载 service account volume,供 pod 调用 api-server 使用。总体逻辑比较简单,源码值得学习,供自己二次开发 k8s 时参考学习。
serviceaccounts-controller 源码官网解析[9]
为 Pod 配置服务账户[10]
服务账号令牌 Secret[11]
admission.go[12]
Kubernetes Proposal - Admission Control[13]
参考资料
[1]
admission.go: https://github.com/kubernetes/kubernetes/blob/release-1.17/plugin/pkg/admission/serviceaccount/admission.go
[2]
enable-admission-plugins: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/
[3]
L103-L121: https://github.com/kubernetes/kubernetes/blob/release-1.17/plugin/pkg/admission/serviceaccount/admission.go#L103-L121
[4]
L160-L248: https://github.com/kubernetes/kubernetes/blob/release-1.17/plugin/pkg/admission/serviceaccount/admission.go#L160-L248
[5]
用户账号与服务账号: https://kubernetes.io/zh/docs/reference/access-authn-authz/service-accounts-admin/#user-accounts-versus-service-accounts

[6]
L426-L567: https://github.com/kubernetes/kubernetes/blob/release-1.17/plugin/pkg/admission/serviceaccount/admission.go#L426-L567
[7]
service-account-private-key-file: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/
[8]
service-account-key-file: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/
[9]
serviceaccounts-controller 源码官网解析: https://kubernetes.io/zh/docs/reference/access-authn-authz/service-accounts-admin/
[10]
为 Pod 配置服务账户: https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-service-account/
[11]
服务账号令牌 Secret: https://kubernetes.io/zh/docs/concepts/configuration/secret/#service-account-token-secrets
[12]
admission.go: https://github.com/kubernetes/kubernetes/blob/v1.17.0/plugin/pkg/admission/serviceaccount/admission.go
[13]
Kubernetes Proposal - Admission Control: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/admission_control.md

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/150312.html