写点什么

浅识 k8s 中的准入控制器

作者:火线安全
  • 2022 年 7 月 04 日
  • 本文字数:2174 字

    阅读完需:约 7 分钟

浅识k8s中的准入控制器

背景

k8s中各组件和kube apiserver通信时的认证和鉴权 中提到"NodeRestriction 准入插件",实际上它是一个"准入控制器"。


"准入控制器"是一个重要的概念,在 istio、apisix、某些安全产品中都有用到。


本文简要记录一下以下内容:


  • "准入控制器"是什么

  • 怎么开启"准入控制器"

  • 从源码浅析"准入控制器"


本文使用的 k8s 集群是用kubekey搭建,命令是./kk create cluster --with-kubernetes v1.21.5 --with-kubesphere v3.2.1

分析

"准入控制器"是什么?

它有点类似"插件",为 apiserver 提供了很好的"可扩展性"。


请求 apiserver 时,通过认证、鉴权后、持久化("api 对象"保存到 etcd)前,会经过"准入控制器",让它可以做"变更和验证"。


"变更"可以修改"api 对象",比如 istio 用来实现 pod 注入。"验证"可以用来校验"api 对象",比如 校验当前集群是否有足够多的资源满足"api 对象"、校验当前提交的"pod 对象"是否合法。

怎么开启"准入控制器"?

root@ip-172-31-14-33:~/kubernetes-1.21.5/_output/bin# ./kube-apiserver --help |grep admission-plugins    ...    --enable-admission-plugins strings       admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyServiceExternalIPs, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
复制代码


根据命令行帮助可以知道,默认会开启 17 个"准入控制器"。


>>> a="NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota">>> len(a.split(","))17
复制代码


也可以用--enable-admission-plugins 开启额外的"准入控制器"。


这些"准入控制器"介绍可以查看 使用准入控制器 文档。在我的实验环境中,可以看到额外开启了NodeRestriction准入控制器,它实现了 apiserver 对 kubelet 请求的权限控制。


root@ip-172-31-14-33:~# ps aux|grep kube-apisroot      9567  4.8  7.8 1381988 613048 ?      Ssl  03:49  17:48 kube-apiserver ... --enable-admission-plugins=NodeRestriction ...
复制代码

从源码浅析"准入控制器"

我们可以通过"断点调试"结合源码分析,验证前面说的两个结论:


  • 请求先经过认证、鉴权,然后经过"准入控制器"

  • 默认开启 17 个"准入控制器";加上 NodeRestriction 就是 18 个


"认证、日志审计、鉴权"在 apiserver 中都是以 filter 的形式存在,而"准入控制器"有点像包装了一层 servlet。


func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {  handler := filterlatency.TrackCompleted(apiHandler)  handler = genericapifilters.WithAuthorization(handler, c.Authorization.Authorizer, c.Serializer) // 鉴权  ...  handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyChecker, c.LongRunningFunc)  // 日志审计  ...  handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences) // 认证  ...  return handler}
复制代码


finishRequest 函数中会开 goroutine 调用"准入控制器"



可以看到 admissionHandler 切片长度是 18,17 个"默认开启的准入控制器"加上 NodeRestriction



部分控制器代码在 plugin/pkg/admission 目录中,会实现 Admit 接口


总结

  • 请求先经过认证、鉴权,然后经过"准入控制器"

  • 默认开启 17 个"准入控制器";NodeRestriction 不是默认开启的


默认开启的"准入控制器"中有两个很特殊的,ValidatingAdmissionWebhook 和 MutatingAdmissionWebhook。这两个控制器让 apiserver 有了更多的可扩展性,实现了"动态准入控制"。


文章首发于火线 Zone:https://zone.huoxian.cn/d/1255-k8s作者:leveryd

用户头像

火线安全

关注

还未添加个人签名 2021.10.22 加入

持续分享云安全相关干货内容,欢迎安全圈的朋友一起交流!

评论

发布
暂无评论
浅识k8s中的准入控制器_云安全_火线安全_InfoQ写作社区