Разбираемся в Gatekeeper: что это за инструмент, как его используют VK Cloud и как он помогает клиентам компании работать в своих кластерах.

 
Для повышения безопасности VK Cloud используют Gatekeeper (гейткипер). Это удобный контроллер, который помогает создать ограничения и контролировать их выполнение. Как и любой инструмент, Gatekeeper обладает сильными сторонами и особенностями работы. Например, часто пользователи сталкиваются с некорректным распределением ресурсов. 

В статье рассмотрим опыт VK Cloud в работе с Gatekeeper, как он помогает в эксплуатации Kubernetes-кластеров и какие проблемы могут встретиться при интеграции Gatekeeper в продакшен-среду. 

Что делает работу с кластерами безопасной

Компании применяют разные политики безопасности. Но у большинства из них есть схожие требования:

  1. Запрет на доступ к системным ресурсам, таким как hostPID и hostIPC. Это помогает предотвратить несанкционированный доступ и обеспечивает изоляцию контейнеров.
  2. Использование надежных образов из проверенных источников. Такие образы обычно имеют меньше уязвимостей и обеспечивают более высокую безопасность.
  3. Запрет использовать тег Latest в образах. Это позволяет обеспечить более предсказуемое и контролируемое развертывание образов.
  4. Обязательное указание лимитов и запросов ресурсов. Это позволяет эффективно управлять ресурсами, предотвращать их истощение и конфликты между контейнерами.
  5. Ограничение запуска привилегированных контейнеров. Они обладают расширенными правами доступа и могут представлять потенциальную угрозу.
  6. Политика защиты от сетевых атак (в том числе DDoS protection) и план действий на случай их возникновения.

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

Мы искали универсальный инструмент, который обезопасит работу с кластерами для наших клиентов, — под наши требования подошел Gatekeeper.

Как работают OPA (Open Policy Agent) и Gatekeeper (гейткипер)

Open Policy Agent (OPA) — универсальный инструмент для управления политиками и контролем доступа. Он может быть интегрирован с различными сервисами и приложениями.

Взаимодействие apiserver, Gatekeeper и Kubernetes

Что такое Gatekeeper? Это специальная версия OPA, созданная для управления безопасностью в системе Kubernetes. Это своего рода «сторож» между сервером управления Kubernetes и Open Policy Agent. Он принимает запросы, которые приходят в кластер Kubernetes и касаются создания каких-либо объектов (например, контейнеров или сервисов) от компонента kube-apiserver.

Алгоритм работы со встроенным Gatekeeper

Если говорить о встроенном Gatekeeper, то алгоритм работы с ним выглядит так.

  1. Когда в системе Kubernetes создается что-то новое, запрос с данными попадает в KubeAPI.
  2. Система проверяет, какие права есть у отправителя. Для этого выполняется аутентификация и авторизация.
  3. После успешной проверки личности и разрешений информация о создаваемом объекте может быть изменена: новые данные могут быть добавлены или изменены.
  4. Объект проверяется на соответствие заданным правилам и структуре данных. Например, есть ли все необходимые ключи и правильны ли значения.
  5. Этап проверки с использованием правил Gatekeeper, которые заданы пользователем. Например, запрещено ли создавать контейнеры с особыми правами доступа или использовать устаревшие версии образов.
  6. Если объект успешно прошел проверки и соответствует правилам, он сохраняется в специальном хранилище (etcd). Там им можно в дальнейшем управлять.

Gatekeeper (гейткипер) универсален и справляется с основной задачей — следить за соблюдением политик безопасности. Однако есть нюансы, которые стоит учитывать. Разберем их.

Почему важно соблюдать практику limits/requests

До внедрения Gatekeeper в Kubernetes от VK Cloud у наших пользователей были определенные проблемы. Например, нагрузки на ноды в кластерах распределялась неравномерно. Пользователи запускали приоритетные поды на определенных узлах, но со временем они «выселялись» на другие узлы. Это проблема, ведь для клиента важно контролировать, что и где работает. 

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

В Kubernetes есть компонент KubeScheduler. Он решает, какой сервер (нод) в кластере будет размещать контейнеры (поды). Он делает это с помощью определенного метода, который включает три шага.

  1. KubeScheduler находит список доступных нодов, у которых достаточно ресурсов для запуска нужного пода.
  2. Затем KubeScheduler ранжирует ноды на основе количества доступных ресурсов. Ноды с большими свободными ресурсами получают больше «очков».
  3. Новый под размещается на ноде с наибольшим количеством «очков».
Как работает ранжирование подов в зависимости от лимитов и запросов

Стоит понимать, что KubeScheduler получает информацию о загрузке нодов из специального хранилища данных — etcd. Это хранилище содержит информацию о том, сколько ресурсов используют другие контейнеры на каждом ноде.

Если не указаны лимиты и ограничения ресурсов для подов, то KubeScheduler не будет знать, сколько ресурсов им нужно. Следовательно, размещение работает «на ощупь», что может привести к неравномерной загрузке нодов и, следовательно, к проблемам.

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

Почему Pod Quality of Service не решил наши запросы

В Kubernetes существуют три класса контейнеров Pod Quality of Service.

1. Гарантированный класс (Guaranteed). Обеспечивает наивысшее качество и надежность. Поды, у которых указаны лимиты и реквесты по CPU и памяти, относятся к этому классу. Это означает, что им гарантированы определенные ресурсы.

2. Класс с возможностью масштабирования (Burstable). Этот класс подходит для подов, где указаны реквесты и лимиты по ресурсам, но реквесты ниже лимитов. В этом случае поды могут использовать больше ресурсов, чем указано в реквестах, но только до уровня лимитов. 

3. Класс «наилучшие усилия» (Best Effort). Этот класс присваивается подам, в которых не указаны ограничения ресурсов limits/requests. Эти поды могут использовать доступные ресурсы на уровне, доступном в данный момент. Это самый уязвимый класс.

Три класса контейнеров Pod Quality of Service

Если не установить ограничения ресурсов для подов, их могут отнести к классу «наилучшие усилия». Они будут работать, но лишатся ресурсов при первой возможности. Иными словами, ограничения необходимы, чтобы нод функционировал корректно.

Соблюдение практики установки ограничений и запросов имеет несколько важных преимуществ, которые следует учесть:

  • распределение нагрузки по нодам происходит равномерно, ресурсы расходуются предсказуемо;
  • нет проблемы «выселения» подов с высоким приоритетом;
  • автомасштабирование кластера (Cluster autoscaler) может более точно определить необходимые ресурсы для размещения нода.

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

Мы не могли внедрить обязательную политику для установки лимитов и реквестов. Вместо этого решили использовать стандартный механизм в Kubernetes, называемый LimitRange (пределы лимитов).
Pod Quality of Service удобен, но требователен к просчету ресурсов. Когда проект развивается динамично, на это просто нет времени.

Чем удобны LimitRange и Shell-operator

LimitRange — это способ ограничивать и устанавливать стандартные значения для использования ресурсов (например, CPU и памяти) в Kubernetes. Позволяет выставить настройки для разных типов объектов, таких как поды или запросы на постоянное хранилище (PersistentVolumeClaim), внутри определенного пространства имен.

Так выглядят лимиты использования CPU и памяти

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

В нашем случае после применения правила LimitRange в неймспейсе значения лимитов и реквестов автоматически добавляются в контейнеры пользователей, даже если они сами не указывают эти значения. Это сделало процесс работы более простым, но только в пределах одного неймспейса.

Чтобы динамически применять настройки LimitRange для всех возможных неймспейсов, которые могут быть созданы клиентами, мы использовали инструмент с названием Shell-operator от компании «Флант». Shell-operator позволяет нам следить за событиями в Kubernetes и запускать специальные скрипты, такие как хуки, в ответ на эти события. Мы настроили скрипт, который автоматически применяет настройки LimitRange к каждому созданному пространству имен.

LimitRange и Shell-operator проще в использовании. Клиентам удобнее выставлять лимиты на ресурсы, а не высчитывать их до байта.

Дополнительные меры безопасности

Мы использовали Gatekeeper для централизованного внедрения политик безопасности, а кроме того, он помог закрыть некоторые уязвимости в базовой системе Kubernetes. К примеру, существует опасная директива под названием hostPath, через которую злоумышленники могли бы реализовать различные угрозы:

  • монтировать сокеты Docker или CRI-O в поды и получать доступ ко всем контейнерам, выполнять различные действия с ними;
  • найти файл kuberconfig с административными правами на кластер и использовать его для своих целей;
  • смонтировать собственный файл с ключами, что предоставляло бы им неограниченный доступ к кластеру. Даже монтирование файла /etc/shadow могло привести к взлому хешей паролей.

Для устранения всех этих уязвимостей мы применили политику Gatekeeper под названием hostfilesystem. Она позволила нам указать, какие директории можно монтировать, и установить правила доступа к ним.

Кроме того, мы ограничили настройки hostPID и hostIPC в наших кластерах. Эти настройки могли быть использованы злоумышленниками для доступа к процессам на хосте, просмотра переменных окружения подов и даже просмотра файловых дескрипторов.

Исправление некоторых уязвимостей Kubernetes решается буквально одной строкой

Благодаря Gatekeeper больше не стоит беспокоиться из-за уязвимости hostPID и hostIPC. Следует отметить, что Gatekeeper предлагает широкий спектр политик, которые можно применять в различных кластерах, а также настраивать под конкретные потребности, добавляя всего одну строку кода.

В нашем случае защита от DDoS-атак строится на внутренних инструментах VK Cloud. Они доступны и для клиентов компании. DDoS-защита позволяет распознать вредоносный трафик с точностью не менее 99,95%.

Неочевидные проблемы Gatekeeper

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

  1. Внедрение политик без должной подготовки может нарушить работоспособность Kubernetes-среды. Например, внедрение обязательного указания лимитов и запросов для ресурсов сказалось на доступности узлов для клиентов. Многие пользователи также не могли оперативно и корректно указать эти ограничения. Чтобы избежать озвученных проблем, рекомендуется внедрять политики постепенно или искать гибкие альтернативные методы.
  2. Install job часто использует директиву hostPath и монтирует файлы в свои контейнеры для развертывания Helm-чартов. Однако это иногда может не сочетаться с применяемыми политиками безопасности.

    Например, после внедрения политики hostPath у нас возникли проблемы с работой всех Helm-чартов, особенно Install job, из-за несовместимости. Для решения этой проблемы мы вынесли Helm-чарты Install job в отдельный неймспейс KubeSystem.
  3. Нельзя применять политики к неймспейсу KubeSystem и включать валидацию для него с помощью Gatekeeper. Мы были осведомлены о данном ограничении и не применяли его в продакшен-среде, но провели небольшой тест. 

    При включенной валидации и наличии сетевого плагина CNI-плагин Calico последний не мог провалидировать свои действия, так как apiserver поднимался позднее. Это приводило к тому, что Calico ждал, когда Gatekeeper стартует, а Gatekeeper, в свою очередь, ждал, когда стартует Calico, что могло вызвать проблемы и блокировку кластера. Чтобы избежать таких ситуаций, мы отключили валидацию и политики для пространства имен KubeSystem.

То есть простое копирование политики с репозитория скорее создает больше проблем. Политика всегда адаптируется под нужды компании.

Выводы из нашего опыта

  1. Настройка кластеров для обеспечения безопасности — обязательное требование в проектах на любом уровне. Kubernetes по умолчанию имеет некоторые уязвимости, и нужны меры для их устранения.
  2. Когда вы работаете с Kubernetes, важно придерживаться лучших практик. Их игнорирование может стоить компании много времени и ресурсов на то, чтобы привести кластер в соответствие с правилами безопасности.
  3. При настройке Gatekeeper (гейткипера) важно отключить валидацию для неймспейса KubeSystem, иначе это может вызвать проблемы с запуском кластера.
  4. При внедрении политик безопасности обратите внимание на Helm-чарты и их тип. При некорректной настройке политики Gatekeeper они могут влиять на работу Helm-чартов, что приведет к ошибкам. Также стоит предусмотреть защиту от DDoS-атак: их число и интенсивность только растут.