Validating Admission Policy: Магия кастомных политик безопасности Kubernetes

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

00. О чём?

Рассмотрим безобидную, на первый взгляд, ситуацию. Вы развернули новый кубернетес кластер, подключили сетку и стораджи, накатили мониторинги и квоты. Казалось бы, осталось нарезать неймспейсы и передать их в пользование коллегам в разработке. Однако, вы в курсе, что разработчики будут запускать команды через kubectl, а значит, по-хорошему, надо накинуть хотя бы "базовые" ограничения на их команды, ведь только так можно оградить себя от большинства проблем в процессе предстоящей эксплуатации кластера.

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

Конечно вы правы, это будет не то, что бы готовый туториал. Тем не менее, каким бы сложным действием ни казалась настройка кластера, если у вас есть некоторый запас времени, то милости прошу в краткое рассуждение о возможностях кубернетес контроллеров и практических способах применения Validating Admission Policy.

ИНСТРУКЪЦЫЯ ПО НАСТРОЙКЕ КУБЪ-КЛАСТЕРА
...
шаг 998 Подключите Validating Admission Policies
шаг 999 Отдайте, наконецъ, кластеръ в эксплуатацию
...

01. Зачем?

Когда разработчики выполняют kubectl apply -f my-deployment.yaml

  • данная команда направляется в виде реквеста к Kubernetes API серверу

  • если authn / authz пройдены успешно, то реквест форвардит на адмишен контроллеры

  • реквест пройдёт по цепочке все необходимые контроллеры

  • каждый "подходящий" контроллер проведёт свою валидацию

  • если все контроллеры ОК, то, в конце концов, дойдёт до Scheduler

  • Scheduler спланирует ресурсы и запустит создание подов на основе их спецификаций

Когда запрос дойдёт до Scheduler, то спецификации на ресурс будут уже как бы сформированы, а квоты на его создание уже почти как бы выделены. Тут уже "на лету" ничего не поменять, останется только прикрутить что-то дополнительное и запустить в виде нового процесса, что уже само по себе как бы намекает: любое наше начинание на данном этапе вызовет гарантированный оверхэд на ресурсы кластера. Поэтому нам предлагается вмешаться чуть пораньше.

Admission controllers - это важная часть Кубернетес, которая управляет ресурсами и реализует критикал политики безопасности ещё до того, как наступят важные действия и события. Адмишены предназачены:

  • фильтровать создание, изменение ресурсов на этапе реквеста
    // успешно выполнятся только те запросы к API серверу, которые удовлетворяют нашим правилам

  • применять политики безопасности для разных видов ресурсов
    // динамически "на лету" изменять спеки ресурса под нужную специфику (лейблы, аннотации, хелсчеки, инжекторы...)

  • следить за событиями, которые могут зааффектить рантайм кластера
    // "опасные" изменения квот,нод,стораджей,системных сервисов...

02. Но как?

Для этого описываются адмишен правила, в которых указывают, к каким ресурсам следует их применять. Например, команда создать деплоймент задействует цепочку нескольких контроллеров, каждый из которых пройдёт через свои адмишены (которые тоже, в свою очередь, представляют из себя 2 вида контроллеров - mutate и validate):

...
DEPLOYMENT CONTROLLER (mutate, validate, persist to etcd, request to api)
REPLICASET CONTROLLER (mutate, validate, persist to etcd, request to api)
POD CONTROLLER (mutate, validate, persist to etcd, request to api)
...

mutate, validate - это виды адмишен-контроллеров, которые займутся вашим реквестом, если в нём производится тот ЭКШЕН над тем РЕСУРСОМ, которые этот самый контроллер "контролирует" (binding). И именно в такой последовательности:

. mutate веб-хук изменяет манифест из вашего реквеста
// и то, что получится на выходе, оценивает на валидность с Object Schema Validation
// так инжектятся сайдкары, добавляются лейблы, аннотации и т.д.

. validate хуки прогоняют итоговый манифест через свои правила
// реквест отменится, если итогоая версия манифеста не метчит хотя бы с одним из правил,
// хотя, вместо отмены отдельные контроллеры можно скипнуть.

Так работают встроенные (BUILD-IN) адмишены для каждого из контроллеров, которые крутятся в контроллер-менеджере. Они работают по стандартным правилам со стандартными ресурсами кластера, то есть вызывают стандартные веб-хуки. С недавнего времени их список можно посмотреть, подключить, отключить...

kube-apiserver -h | grep enable-admission-plugins
kube-apiserver --enable-admission-plugins=.., .., ...
kube-apiserver --disable-admission-plugins=.., .., ...

А если мы хотим немного расширить список таких правил, скажем, запрещать создание сервисов типа NodePort, или, например, ограничивать создание определённых ресурсов на продовых окружениях по ряду условий?

Чтобы такое реализовать... РАНЬШЕ нужно было использовать Third-party-tool.
Это дорого, но необходимо в случаях, когда важно:
. автоматически инжектить сайдкары для сервис-меш (Linkerd, Istio)
. добавлять аннтоации для обсервабилити (Prometheus-like в специфичных инсталляциях)

Чтобы такое реализовать... ТЕПЕРЬ (начиная с версии 1.26)
. не потребуется Third-party-tool со всеми бонусами
. не придётся ожидать оверхэд, тк не нужно создавать новые веб-хуки
. не придётся возиться с авторизациями, сертами...
. но изучить язык выражений всё же придётся (CEL https://github.com/google/cel-spec)

03. Ну и как?

Максимально кастомизируемо и опционально параметрически. Не сложнее, чем написать правила в Alert Manager.

Для начала проверьте, подключены ли в вашем кластере admission плагины и нужный api
controlplane$ vi /etc/kubernetes/manifests/kube-apiserver.yaml

spec:
  containers:
  - command:
    - kube-apiserver
	- ...
	- --enable-admission-plugins=NodeRestriction              #1
    - --runtime-config=admissionregistration.k8s.io/v1alpha1  #2
    - --feature-gates=ValidatingAdmissionPolicy=true          #3
	- ...

В случае, если API-server устанавливали как systemd сервис, то настройки ожидаемо править в systemd unit файлике.
Итак, плагины подключены и проверены. Теперь вам надо создать как минимум 2 ресурса

1. Validating Admission Policy
Полиси - это по сути список правил, описанных с помощью языка выражений CEL (см.выше)

2. ValidatingAdmissionPolicyBinding
Биндинг - это по сути скоуп ресурсов, на который мы хотим распространить данные правила

3. *
Параметр - это всего лишь опция, но вероятно game-changer кандидат.
не исключено, что однажды вам понадобится избавиться от внешних источников для приложений, например, пошарить стейт занятости вашей GPU между разными сервисами внутри кластера.
Вам понадобится создать отдельный ресурс для хранения нужного GPU стейта в виде параметра и продумать логику - кто, как и при каких условиях будет изменять его значение.
Готово. вы привязали поведение разных сервисов к одному общему параметру внутри кластера

Попробуйте создать тестовые полиси и биндинги, используя официальную доку
https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/

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

Hidden text
// запретить в деплойменте использовать неизвестные адреса
// реджистри для пулла имиджей в кластер
---
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  variables:
  - name: containers
    expression: "object.spec.template.spec.containers"
  validations:
    - expression: "!(variables.containers.filter(c, c.image.contains('company.ru/'))"
      messageExpression: "'only approved company.ru images are allowed'"


// запретить создавать сервисы с типом NodePort
---
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["*"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["services"]
  validations:
    - expression: "object.spec.type == 'NodePort'"
      reason: Invalid


// запретить создание новых джобов в кастомном ресурсе, пока GPU находится в статусе >0
---
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apiextensions.k8s.io"]
      apiVersions: ["v1"]
      operations:  ["CREATE"]
      resources:   ["jobs"]
  validations:
    - expressions: "object.spec.needState < params.stateGPU"
      messageExpression: "'GPU is busy with state ' + string(params.stateGPU)"

Если всё получилось, значит вы уже готовы покрыть политиками безопасности (policy) необходимые вам кейсы и обеспечить защиту вашего кластера. Скорее добавляйте "базовые" полиси и отдавайте уже этот кластер разработчикам, бизнес не ждёт!

Заметьте, вам не пришлось устанавливать third-party-tools и рассчитывать их нагрузку.
А если понадобится накинуть новые ограничения, то вы уже знаете как это делать.

04. И всё?

Постойте... А какие минусы?
На первых этапах, кроме ограничений, которые вам нужны, в принципе, никаких минусов. Но с ростом количества новых полиси, нагрузка на веб-хуки возрастёт, и тогда, скорее всего, вам захочется их масштабировать. Что можно для этого сделать?

  • повысить доступность веб-хуков, задеплоив несколько инстансов webhook server в некий отдельный webhook-namespace

  • обернуть адмишен веб-хуки (точнее, webhook server) в мониторинги для отслеживания их перформанса и доступности

  • продумать чтение и анализ /var/log/webhook-server.log, дабы иметь уверенность в секьюрности использования полиси

  • использовать dry-run валидатор YAML-файлов по адмишен-контроллерам, например, kubeconform

Вам есть, что предложить, добавить, возразить? Милости прошу в комменты, буду рад интересным вариантам из вашего опыта, неожиданным мнениям и фантастическим гипотезам.

gracefull shutdown
gracefull shutdown

Душевное спасибо за ваше внимание, если дочитали до этих строк. Да, и будь то техническая часть в работе компонентов куберенетес, архитектура и безопасность развёртывания приложений в k8s, не стесняйтесь проявлять здоровую критику моих изысканий в комментариях.

P.S. в том числе, не скупитесь на критику в такой непростой области, как орфография текста статьи и корректность изложения сложных понятий на простом русском языке, дабы исключать двусмысленность и мислидинг и помогать делать тексты лучше.

P.P.S. Если у вас уже есть готовый "велосипед" или только идея разработать нечто полезное для работы с кубером, позволяющее упростить работу над конфигурацией куб-приложений, в т.ч расширить возможности куба для специфичных задач ML/AI-operations, in-memory db, кастомных балансировщиков и шедулеров, или просто автоматизировать какую-то часть рутины, то не стесняйтесь писать в личку с предложениями на предмет взаимовыгодного сотрудничества.

Источник: https://habr.com/ru/articles/811075/


Интересные статьи

Интересные статьи

Вторая часть статьи "Наблюдаемость сетевой инфраструктуры Kubernetes" про рассмотрение Observability инструментов.В этой части мы сравним разворачиваемые решения в выбранном сетевом сценарии на основе...
Законы Природы применимы для любой предметной области, в том числе и для информационной безопасности. На протяжении длительного времени можно наблюдать эволюцию и совершенствование технологий и инстру...
27–29 мая пройдёт онлайн-интенсив Kubernetes Мега. Чему учить будем? Мы не сделаем из вас продвинутого специалиста за три дня, а само участие в интенсиве не поднимет вашу зарплату....
И почему не стоит его использовать в автоматическом режиме Вертикальное автомасштабирование подов (Vertical Pod Autoscaling) — одна из крутых функций Kubernetes, которую не достаточно ...
Изображение: Unsplash Как было описано в предыдущей статье про CVE-2019-0726, иногда поиск деталей об уже известной уязвимости приводит к обнаружению новой уязвимости. А в некоторых случая...