关于kubernetes:搞懂-Kubernetes-准入控制Admission-Controller

4次阅读

共计 9250 个字符,预计需要花费 24 分钟才能阅读完成。

大家好,我是张晋涛。

在我之前公布的文章《云原生时代下的容器镜像平安》(系列)中,我提到过 Kubernetes 集群的外围组件 — kube-apiserver,它容许来自终端用户或集群的各组件与之进行通信(例如,查问、创立、批改或删除 Kubernetes 资源)。

本篇咱们将聚焦于 kube-apiserver 申请处理过程中一个很重要的局部 — 准入控制器(Admission Controller)

K8s 的准入控制器是什么

K8s 中的申请解决流程

在聊 K8s 准入控制器是什么之前,让咱们先来回顾一下 Kubernetes API 的解决具体申请的过程。

图 1,Kubernetes API 解决申请的过程(从 API Handler 到 etcd 长久化的过程)

如上图所示,每个 API 的申请从开始被 kube-apiserver 接管到最终长久化到 ETCD 的过程,即为 Kubernetes API 的申请解决流程。

它次要蕴含了以下几个局部:

  • API Handler — 次要负责提供服务,接管申请。

对于其外部实现而言,申请会先到 FullHandlerChain(它是由 DefaultBuildHandlerChain 构建进去的)是一个 director 对象

type director struct {
    name               string
    goRestfulContainer *restful.Container
    nonGoRestfulMux    *mux.PathRecorderMux
}

director依据配置进行初始化,如果 goRestfulContainer的 WebServices 的 RootPath 是 /apis,或者申请前缀与 RootPath 匹配,则进入 Restful 解决链路。

  • Authentication — 认证的流程。

在 TLS 连贯建设后,会进行认证解决,如果申请认证失败,会回绝该申请并返回 401 错误码;如果认证胜利,将进行到鉴权的局部。目前反对的客户端认证形式有很多,例如:x509 客户端证书、Bearer Token、基于用户名明码的认证、OpenID 认证等。因为这些内容不是本篇的重点咱们暂且跳过,感兴趣的小伙伴能够在评论区留言探讨。

  • Authorization — 鉴权的流程。

对于 Kubernetes 而言,反对多种的鉴权模式,例如,ABAC 模式,RBAC 模式和 Webhook 模式等。咱们在创立集群时,能够间接为 kube-apiserver 传递参数进行配置,这里也不赘述了。

  • Mutating Admission — 指执行可用于变更操作的准入控制器,下文中会具体介绍。
  • Object Schema Validation — 对资源对象的 schema 校验。
  • Validating Admission — 指执行可用于验证操作的准入控制器,下文中会具体介绍。
  • ETCD — ETCD 实现资源的长久化存储。

下面便是一个申请的解决流程,其中 Mutating Admission 和 Validating Admission 便是咱们明天的配角。咱们来具体的看一看。

什么是准入控制器(Admission Controller)

准入控制器是指在 申请通过认证和受权之后,可用于对其进行变更操作或验证操作的一些代码或性能。

准入管制的过程分为两个阶段:

  • 第一阶段,运行变更准入控制器(Mutating Admission)。它能够批改被它承受的对象,这就引出了它的另一个作用,将相干资源作为申请解决的一部分进行变更;
  • 第二阶段,运行验证准入控制器(Validating Admission)。它只能进行验证,不能进行任何资源数据的批改操作;

须要留神的是,某些控制器能够既是变更准入控制器又是验证准入控制器。如果任一个阶段的准入控制器回绝了该申请,则整个申请将立刻被回绝,并向终端用户返回谬误。

为什么须要准入控制器 Admission Controller

咱们次要从两个角度来了解为什么咱们须要准入控制器:

  • 从平安的角度
    • 咱们须要明确在 Kubernetes 集群中部署的镜像起源是否可信,免得蒙受攻打;
    • 个别状况下,在 Pod 内尽量不应用 root 用户,或者尽量不开启特权容器等;
  • 从治理的角度
    • 比方通过 label 对业务 / 服务进行辨别,那么能够通过 admission controller 校验服务是否曾经有对应的 label 存在之类的;
    • 比方增加资源配额限度,免得呈现资源超卖之类的状况;

准入控制器

思考到这些需要比拟有用 & 的确也比拟须要,所以 Kubernetes 目前曾经实现了很多内置的 Admission Controller。能够参考官网文档来获取具体列表:https://kubernetes.io/docs/re…

这些内置的 Admission Controller 都是以插件的形式与 kube-apiserver 构建到一起的,你能够对其进行启用和关停。比方用如下参数进行管制:

➜  bin ./kube-apiserver --help |grep admission-plugins    
      --admission-control strings              Admission is divided into two phases. In the first phase, only mutating admission plugins run. In the second phase, only validating admission plugins run. The names in the below list may represent a validating plugin, a mutating plugin, or both. The order of plugins in which they are passed to this flag does not matter. Comma-delimited list of: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyServiceExternalIPs, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurity, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. (DEPRECATED: Use --enable-admission-plugins or --disable-admission-plugins instead. Will be removed in a future version.)
      --disable-admission-plugins strings      admission plugins that should be disabled although they are in the default enabled plugins list (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, 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, PodSecurity, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
      --enable-admission-plugins strings       admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, 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, PodSecurity, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.

这么多的准入控制器中有两个比拟特地,别离是 MutatingAdmissionWebhookValidatingAdmissionWebhook。它们并没有真正执行相应的策略,而是为 kube-apiserver 提供了一种可扩大的形式,用户能够通过配置 MutatingAdmissionWebhookValidatingAdmissionWebhook 来应用自构建的服务,而且这种形式是无需对 kube-spiserver 执行编译或者重启,齐全是动静的,十分的不便。

咱们来具体看一下。

动静准入控制器

利用上文中提到的 MutatingAdmissionWebhookValidatingAdmissionWebhook 进行运行时配置的,以 Webhook 模式调用的 Admission Controller 即为动静准入控制器。

它是一种用于接管准入申请并对其进行解决的 HTTP 回调机制,就是一个 Web 服务。以后的两种类型的准入 webhook:

  • validating admission webhook
  • mutating admission webhook

mutating admission webhook 会优先被调用,这个过程中能够对资源进行批改。

如果咱们须要确保对象的最终状态以执行某些操作应该思考应用 validating admission webhook 因为达到这个阶段的申请不会再被批改。

应用条件

  • 确保 Kubernetes 集群版本至多为 v1.16(以便应用 admissionregistration.k8s.io/v1 API)或者 v1.9(以便应用 admissionregistration.k8s.io/v1beta1 API);
  • 确保曾经启用 MutatingAdmissionWebhookValidatingAdmissionWebhook 准入控制器;
  • 确保启用了 admissionregistration.k8s.io/v1beta1 或者 admissionregistration.k8s.io/v1 API;

Admission Webhook 是什么

它其实就是一个一般的 HTTP Server,须要解决的就是 AdmissionReview 类型的资源,咱们来看个示例,比如说要对 Ingress资源进行准入校验:

func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object, error) {review, isV1 := obj.(*admissionv1.AdmissionReview)
    if !isV1 {return nil, fmt.Errorf("request is not of type AdmissionReview v1")
    }

    if !apiequality.Semantic.DeepEqual(review.Request.Kind, ingressResource) {
        return nil, fmt.Errorf("rejecting admission review because the request does not contain an Ingress resource but %s with name %s in namespace %s",
            review.Request.Kind.String(), review.Request.Name, review.Request.Namespace)
    }

    status := &admissionv1.AdmissionResponse{}
    status.UID = review.Request.UID

    ingress := networking.Ingress{}

    codec := json.NewSerializerWithOptions(json.DefaultMetaFactory, scheme, scheme, json.SerializerOptions{Pretty: true,})
    codec.Decode(review.Request.Object.Raw, nil, nil)
    _, _, err := codec.Decode(review.Request.Object.Raw, nil, &ingress)
    if err != nil {klog.ErrorS(err, "failed to decode ingress")
        status.Allowed = false
        status.Result = &metav1.Status{
            Status: metav1.StatusFailure, Code: http.StatusBadRequest, Reason: metav1.StatusReasonBadRequest,
            Message: err.Error(),}

        review.Response = status
        return review, nil
    }

    if err := ia.Checker.CheckIngress(&ingress); err != nil {klog.ErrorS(err, "invalid ingress configuration", "ingress", fmt.Sprintf("%v/%v", review.Request.Name, review.Request.Namespace))
        status.Allowed = false
        status.Result = &metav1.Status{
            Status: metav1.StatusFailure, Code: http.StatusBadRequest, Reason: metav1.StatusReasonBadRequest,
            Message: err.Error(),}

        review.Response = status
        return review, nil
    }

    klog.InfoS("successfully validated configuration, accepting", "ingress", fmt.Sprintf("%v/%v", review.Request.Name, review.Request.Namespace))
    status.Allowed = true
    review.Response = status

    return review, nil
}

外围解决逻辑其实就是解决申请 Webhook 时候发送的 AdmissionReview,它会蕴含着咱们待校验的资源对象。而后咱们就依照理论的须要对资源对象进行校验或者批改了。

这里须要留神几个点:

  • Mutating Webhook 的解决是串行的,而 Validating Webhook 是并行处理的;
  • Mutating Webhook 尽管解决是串行的,然而并不保障程序;
  • 留神对 Mutating Webhook 的解决做到幂等性,免得后果不合乎预期;
  • 申请解决时,留神要解决资源对象的所有 API 版本;

如何部署 Admission Webhook

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  labels:
    app.kubernetes.io/name: ingress-nginx
  name: ingress-nginx-admission
webhooks:
  - name: validate.nginx.ingress.kubernetes.io
    matchPolicy: Equivalent
    rules:
      - apiGroups:
          - networking.k8s.io
        apiVersions:
          - v1
        operations:
          - CREATE
          - UPDATE
        resources:
          - ingresses
    failurePolicy: Fail
    sideEffects: None
    admissionReviewVersions:
      - v1
    clientConfig:
      service:
        namespace: ingress-nginx
        name: ingress-nginx-controller-admission
        path: /networking/v1/ingresses

webhooks 中配置 webhook 的具体连贯信息,以及触发规定。rules中可指定对哪些资源的具体行为失效。

总结

本篇次要介绍了 Kubernetes 中的 Admission Controller,默认状况下有一些曾经以插件模式与 kube-apiserver 编译到了一起,另外咱们也能够通过本人编写动静准入控制器来实现相干的需要。

当然,目前在 K8s 生态中曾经有很多现成的工具能够帮咱们实现对应的这些事件了,很多状况下不须要再自行开发对应的服务了。后续我来为大家分享以后一些比拟支流的,可用于进行 Mutating 和 Validating 准入管制的工具,欢送关注。


欢送订阅我的文章公众号【MoeLove】

正文完
 0