Одна статья для понимания контроля доступа K8s (Admission Controller)

задняя часть Go Kubernetes
Одна статья для понимания контроля доступа K8s (Admission Controller)

«Это 8-й день моего участия в ноябрьском испытании обновлений, ознакомьтесь с подробностями события:Вызов последнего обновления 2021 г.".

Всем привет, меня зовут Чжан Цзиньтао.

В моей предыдущей статье «Безопасность образа контейнера в облачную эру» (серия) я упомянул kube-apiserver, основной компонент кластера Kubernetes, который позволяет компонентам от конечных пользователей или кластера взаимодействовать с ним (например, , запрашивать, создавать, изменять или удалять ресурсы Kubernetes).

В этой статье мы сосредоточимся на очень важной части процесса обработки запросов kube-apiserver — контроллере допуска (Admission Controller)

Что такое контроллер допуска для K8s

Процесс обработки запроса в K8s

Прежде чем говорить о том, что такое контроллер допуска K8s, давайте рассмотрим процесс обработки конкретных запросов в Kubernetes API.

img

Рис. 1. Процесс обработки запросов API Kubernetes (процесс от обработчика API до персистентности etcd)

Как показано на рисунке выше, процесс каждого запроса API от получения kube-apiserver до окончательного сохранения в ETCD — это поток обработки запроса API Kubernetes.

Он в основном включает в себя следующие части:

  • API Handler-- В основном отвечает за предоставление услуг и получение запросов.

Для его внутренней реализации запрос идет первымFullHandlerChain(это изDefaultBuildHandlerChainПостроить) этоdirectorобъект

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

directorИнициализировать в соответствии с конфигурацией, еслиgoRestfulContainerRootPath веб-сервисов/apisИли запросите совпадение префикса RootPath, обработка продолжается по ссылке Restful.

  • Authentication- Сертификация процесса.

После установления соединения TLS будет выполнен процесс аутентификации.Если аутентификация запроса не удалась, запрос будет отклонен и будет возвращен код ошибки 401; если аутентификация прошла успешно, будет выполнена часть аутентификации. В настоящее время поддерживается множество методов аутентификации клиентов, таких как: сертификат клиента x509, Bearer Token, аутентификация на основе имени пользователя и пароля, аутентификация OpenID и т. д. Поскольку это содержание не находится в центре внимания этой статьи, мы пока пропустим его, и заинтересованные друзья могут оставить сообщение в области комментариев для обсуждения.

  • Authorization-- Процесс аутентификации.

Для Kubernetes поддерживаются несколько режимов аутентификации, например режим ABAC, режим RBAC и режим Webhook. Когда мы создаем кластер, мы можем напрямую передавать параметры kube-apiserver для настройки, и мы не будем здесь вдаваться в подробности.

  • Mutating Admission-- Относится к контроллеру допуска, который выполняет действие, которое можно использовать для внесения изменений, как подробно описано ниже.

  • Object Schema Validation-- Проверка схемы на объектах ресурсов.

  • Validating Admission- средства для выполнения контроллера приема могут проверять работу, оно будет подробно описано ниже.

  • ETCD- Постоянное хранение ресурсов ETCD.

Выше приведен процесс обработки запроса, главными действующими лицами которого сегодня являются Muting Admission и Validating Admission. Давайте подробно рассмотрим.

Что такое Admission Controller (Контроллер допуска)

Контроллер допуска относится кПосле аутентификации и авторизации запросаНекоторые код или функциональность, которые можно использовать для изменения или проверки операций на нем.

Процесс приемного контроля делится на два этапа:

  • На первом этапе запускается контроллер Muting Admission. Он может изменять принимаемые им объекты, что приводит к его другой роли, изменяя связанные ресурсы в рамках обработки запроса;

  • На втором этапе запустите контроллер Validating Admission. Его можно только проверить, и он не может изменять какие-либо данные ресурса;

Следует отметить, что некоторые контроллеры могут быть как контроллером изменений и контроллером доступа к проверке. Если контроллер приема на любой стадии отклоняет запрос, весь запрос будет немедленно отклонен и вернуть ошибку к конечному пользователю.

Зачем нужен контроллер допуска Контроллер доступа

В основном мы понимаем, зачем нам нужен контроллер допуска, с двух точек зрения:

  • с точки зрения безопасности

    • Нам нужно уточнить, заслуживает ли доверия источник образа, развернутого в кластере Kubernetes, чтобы избежать атаки;
    • В общем, старайтесь не использовать пользователя root в поде или старайтесь не открывать привилегированные контейнеры и т. д.;
  • С точки зрения управления

    • Например, если бизнес/услуга отличается меткой, то контроллер допуска можно использовать для проверки того, имеет ли услуга уже соответствующую метку;
    • Например, добавление ограничений квоты ресурсов, чтобы избежать перепродажи ресурсов и тому подобное;

контроллер допуска

Учитывая, что эти требования более полезны и действительно необходимы, в Kubernetes реализовано множество встроенных контроллеров доступа. Подробный список можно найти в официальной документации:Это особенное.IO/docs/refer E…

Эти встроенные контроллеры доступа созданы как плагины с 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.

Два из многих контроллеров допуска являются специальными, а именноMutatingAdmissionWebhookиValidatingAdmissionWebhook.它们并没有真正执行相应的策略,而是为 kube-apiserver 提供了一种可扩展的方式, 用户可以通过配置MutatingAdmissionWebhookиValidatingAdmissionWebhookС помощью самодельных сервисов, и этот способ не требует компиляции или перезапуска kube-spiserver, он полностью динамичен и очень удобен.

Давайте посмотрим поближе.

Динамический контроллер допуска

с помощью упомянутого вышеMutatingAdmissionWebhookиValidatingAdmissionWebhookДля конфигурации среды выполнения контроллер доступа, вызываемый в форме веб-перехватчика, является контроллером динамического доступа.

Это механизм обратного вызова HTTP для получения и обработки запросов на допуск, который является веб-службой. В настоящее время существует два типа веб-перехватчиков приема:

  • validating admission webhook
  • mutating admission webhook

Изменяющийся веб-перехватчик доступа будет вызываться первым, и в ходе этого процесса можно изменять ресурсы.

Если нам нужно обеспечить конечное состояние объекта для выполнения какого-либо действия, мы должны рассмотреть возможность использования проверяющего веб-перехватчика допуска *, *, поскольку запросы, которые достигают этого этапа, больше не будут изменяться.

Условия использования

  • Убедитесь, что версия кластера Kubernetes не ниже 1.16 (чтобы использоватьadmissionregistration.k8s.io/v1API) или V1.9 (для использованияadmissionregistration.k8s.io/v1beta1API);

  • Убедитесь, что он включенMutatingAdmissionWebhookиValidatingAdmissionWebhookконтроллер допуска;

  • убедитесь, что он включенadmissionregistration.k8s.io/v1beta1илиadmissionregistration.k8s.io/v1 API;

Что такое входной вебхук

Это на самом деле обычный HTTP-сервер, а что нужно обрабатывать, это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
}

Основная логика обработки фактически отправляется при обработке запроса WebhookAdmissionReview, который будет содержать объект ресурса, который мы хотим проверить. Затем мы проверяем или модифицируем объект ресурса в соответствии с фактическими потребностями.

Вот несколько моментов, на которые следует обратить внимание:

  • Обработка Muting Webhook является последовательной, а обработка Validating Webhook — параллельной;

  • Хотя обработка Mutating Webhook является последовательной, она не гарантирует порядок;

  • Обратите внимание на обработку Mutating Webhook для выполнения идемпотентности, поэтому результаты не соответствуют ожиданиям;

  • При запросе обработки будьте осторожны, чтобы обрабатывать все версии API объекта ресурса;

Как развернуть веб-хуки приема

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Настройте конкретную информацию о соединении для правил веб-перехватчика и триггера в файлах .rulesВы можете указать, для какого ресурса действует конкретное поведение.

Суммировать

В этой статье в основном представлены контроллеры доступа в Kubernetes. По умолчанию некоторые из них были скомпилированы с помощью kube-apiserver в виде подключаемых модулей. Кроме того, мы также можем сами написать динамические контроллеры доступа для выполнения соответствующих требований.

Конечно, в экосистеме K8s уже есть много готовых инструментов, которые могут помочь нам сделать эти соответствующие вещи, во многих случаях нет необходимости разрабатывать соответствующие сервисы самостоятельно. Позже я поделюсь с вами некоторыми наиболее распространенными инструментами, которые можно использовать для мутирования и проверки контроля доступа.


Добро пожаловать, чтобы подписаться на мой публичный аккаунт статьи [MoeLove]