Привет, Хабр!

Эта статья - расшифровка доклада с QIWI Server Party

Многие знают, что такое микросервисы и как их оркестрировать. А вот как обеспечить их безопасность, это отдельный вопрос, достойный обсуждения. Потому что если достаточно глубоко не разобраться в том, что и как работает в вашей Kubernetes-инфраструктуре, вашим незнанием могут воспользоваться хакеры или недобропорядочные сотрудники. 

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

В основном взломы происходят по недосмотру конфигурации оборудования, операционных систем и ПО. Хакеры, пользуясь случаем, ловят личную информацию и деньги с банковских счетов. Противостоят им добрые дяди из отдела безопасности, которые защищают приложения и кластера. Я бы хотел включиться в роль такого доброго дяди и подробно рассказать, как обеспечить внутреннюю и внешнюю безопасность Kubernetes и приложений, находящихся в нем.

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

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

У Kubernetes есть три основных компонента: Control Plane, Worker Node и Cluster Network. У всего этого около 100-500 ручек. И мы в QIWI сформировали определенное видение и принципы того, как должен работать Kubernetes с учетом требований нашей информационной безопасности. Ими я и хочу поделиться.

Control Plane

Начнем с защиты самого главного — мозга платформы. А именно сервера API, планировщиков и базы данных, которая хранит состояние всего кластера. 

Основа безопасности Control Plane — это кластерные взаимодействия, то есть коммуникации. То, как трафик проходит между служебными компонентами. К ним относятся RBAC — роли и права, плагины встроенные и самостоятельно разрабатываемые, аудит и логи, квоты и лимиты. 

Все коммуникации со всеми компонентами кластера должны проводиться по зашифрованному каналу, HTTPS, с использованием стойких шифров и с валидацией сертификатов. Также запрещен анонимный доступ, иначе злоумышленник, попав в вашу сеть, сможет завладеть или изменить любое состояние кластера и находящиеся в нем приложения, получив тем самым полный доступ к кластеру.

А теперь о каждом компоненте подробнее.

Необходимо использовать ролевую модель управления — RBAC. Она позволяет разграничить пользователей группы кластера и их права. Описывая роль и ее бинд, мы можем указать, какому пользователю, группе пользователей или объекту, например, сервисному аккаунту, можно взаимодействовать с конкретными API-ресурсами (деплойментами, подами, логами и их экзеками, ингресами, неймспейсами) и с какими правами. Права выражаются глаголами действия, например: get, patch, list, delete. 

Не стоит забывать про встроенные плагины API сервера. Их по меньшей мере штук тридцать, но самых основных по безопасности всего четыре. AlwaysPull заставляет использовать самые актуальные образы при запуске пода, чтобы исключить их факт подмены образа при запуске на Worker Node. DenyEscalatingExec запрещает доступ к привилегированным контейнерам. NodeRestriction ограничивает права Worker Node в кластере. Но самый главный — PodSecurityPolicy. Он задает то, с какими правами может запускаться под. 

По сути PodSecurityPolicy — это контроллер, проверяющий спецификацию пода на соответствие определенным требованиям. Эти требования могут ограничивать использование привилегированных контейнеров, доступ к определенным типам хранилищ, а также пользователей или групп, от имени которых будет работать контейнер.

Если запустить ресурс со спецификацией пода, которая не соответствует требованиям политики безопасности, установленной в кластере, запрос на создание или запуск пода будет отклонен. PodSecurityPolicy дает возможность контролировать, какие модули управления доступом к данным будут запланированы в кластере. И таким образом предотвратить возможные уязвимости и эскалацию привилегий.

Также есть множество внешних плагинов по безопасности, например, Anchore Security Scanner - это решение для проверки запускаемых образов на уязвимости, показывает, каким CVE подвержен образ, проверяет цифровую подпись образа и так далее. И на основании этих сканирований контроллер от Anchore может разрешать или запрещать запуск подов с этими образами в кластере.

Также в Kubernetes есть так называемые секреты, в которых можно хранить пароли, сертификаты или другую чувствительную информацию. Но к сожалению, они там хранятся в открытом виде, и шифровать их придется самим. Есть возможность хранить секрет в зашифрованном виде в самой БД, в своей внутренней БД Kubernetes-а. Это делается с помощью включения отдельного ключа в API сервера. Но желательно использовать для хранения секретов специальные решения, например, Vault от Hashicorp.

Для отслеживания всех взаимодействий в кластере нужно включить в API сервера аудит. Это описывается в специальном манифесте, который укажет, какие конкретно действия с каким уровнем логирования куда нужно записывать. Как правило логи удобнее вываливать в stdout API сервера, и дальше собирать их каким нибудь лог демоном, например, Fluentd, и затем отдавать в хранилку по специальному правилу в отдельно стоящий Elastic. После его проанализирует служба безопасности.

Внутренний аудит действий можно расширить с помощью продукта Falco, который будет помогать отслеживать системные вызовы ядра, также он имеет несколько предустановленных правил, таких как - отслеживание запуска контейнеров с HostPid, попытки примонтировать важные системные директории через HostPath, попытка повысить привилегии процессом в контейнере и так далее.

Есть еще такая штука, как лимиты и квоты. Kubernetes прекрасно справляется с обработкой состояния отказа и с планированием подов. Но на практике порой планировщик не может разместить под. Это происходит, если он затрудняется оценить, какое количество ресурсов ему требуется для успешной работы.

Возможны ситуации, когда при неправильной настройке количества реплик или действий злоумышленника все ресурсы кластера исчерпаны. Предотвратить это можно, выставив как минимум на уровне namespace по дефолту все минимальные лимиты ресурсов, которые мог бы употребить каждый под. 

А чтобы не заспамить API сервер запросами на создание ресурсов, нужно устанавливать на них квоты, которые укажут, кому сколько можно иметь в распоряжении, например, по количеству подов, конфиг-мапов, постоянных томов и так далее.

Worker Node

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

Также мы используем последнюю рекомендуемую версию контейнерного движка. В случае с докером, необходимо обновиться до последней для вашей версии Kubernetes пакета docker, у нас это 20 версия, а также запускаться с плагином RootlessDocker. Он заставит принудительно запускать процесс внутри контейнера с ID, отличному от хостовой системы. Если произойдет побег из контейнера, где процесс был запущен от рута, злоумышленник не получит рут на самом хосте.

Для более детального управления действиями контейнера можно использовать встроенные функции безопасности Linux — AppArmor/Seccomp. Эти функции определяются на уровне узла, а затем реализуются с помощью манифеста в самом контейнере. Эти профили ограничивают действия контейнера — чтение, запись, выполнение, или их системные функции, такие как подключение файловых систем. Профиль AppArmor по умолчанию ограничивает доступ к разделам Proc и Sys, а также предоставляет средство для логической изоляции контейнеров.

Cluster Network

Теперь о сети. В Kubernetes ее можно организовать с помощью разных плагинов CNI, то есть Container Network Interface. Нужно заранее продумать архитектуру сети, ее размеры, возможности маршрутизации и сегментации. И, если это возможно, сетевых политик, то есть встроенного фаерволла.

Перед тем, как мы собрались запустить Kubernetes в продакшн в QIWI, мы провели сравнение популярных решений. И полагались, в первую очередь, на скорость обработки запросов, удобство встраивания системы в нашу инфраструктуру возможность использования разных security-фишек, которые считал необходимыми отдел информационной безопасности.

Некоторые из рассматриваемых решений предлагали шифрование трафика между нодами на лету даже в ущерб своей производительности. Но нам это не было нужно. Учтя все критерии, мы выбрали Calico, несмотря на то, что сейчас по количеству установок лидирует Flannel.

И сейчас расскажу, почему.

Calico, как и некоторые плагины, позволяет сегментировать сеть. Каждому приложению или группе приложений можно автоматически назначать ip-пулы, свои кусочки сети, отрезая их от основного большого пула. Из этого пула будут назначаться адреса для подов, с которых будет идти трафик, что позволит отслеживать его за пределами Kubernetes. Благодаря маршрутизации по BGP, мы можем устроить full-mesh топологию сети и принимать или перенаправлять трафик с любой ноды. 

Также при использовании анонсов по BGP вы можете использовать за пределами Kubernetes внешний фаервол, который сможет увидеть все внутренние подсети кластера, это позволит регулировать сетевые доступы как извне, так и изнутри.

Ещё можно использовать встроенные в Kubernetes и поддерживаемые в Calico сетевые политики, так называемые Network Policy, что мы и делаем. С их помощью мы можем описывать через манифесты какому поду или группе подов, сгруппированных по label или namespace, разрешено в каком направлении, по какому порту и по какому типу трафика подключаться. Тем самым мы окружаем наши приложения кластерным фаерволлом, который будет предотвращать нежелательные подключения как извне, так и изнутри. 

Также на Worker Node можно включить логирование сетевых политик и сливать логи в аналитическую систему.

Чтобы упростить написание сетевых политик, наш коллега разработал контроллер и назвал его NPD (Network Policy Definition, это даже стало названием crd, CustomResourceDefinition). Этот контроллер позволяет использовать внутренние регистры — штуки, которые знают о всех хостах в QIWI. Допустим, есть хост с конкретной ролью, Hostname, IP-адресом и назначением. И если в обычных Network Policy мы сможем использовать только компоненты самого Kubernetes, с контроллером нашего коллеги мы можем подключить внешнюю систему и использовать в качестве источника сторонние хосты. 

Выводы 

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

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

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

Комментарии (2)


  1. Xop
    13.11.2021 14:50
    +2

    А можно вопросов?

    • вы как-то защищаете etcd от чтения кем-либо, кроме системных подов control plane?

    • есть ли на уровне сетевых политик запрет на доступ к kubelet и kube-api-server из обычных подов? И если есть - то как реализовывали?

    • пользуетесь ли HostEndpoint и GlobalNetworkPolicy в Calico, чтобы настраивать файрволы на уровне нод? Или это решаете уровнем выше?

    Спасибо, кстати, за статью - было интересно.


    1. dblgrem Автор
      22.11.2021 22:36
      +1

      Конечно!

      • Лучше изолировать etcd от остального control-plane в отдельной подсети, разрешить к нему доступ только из доверенных источников и только при верификации сертификатов. Например у нас есть пайплайн который создает определенные ippools в calico с нужным октетом, для этого с билд-сервера нужна связность до etcd кластера и определенные сертификаты для доступа на чтение или запись.

      • К Kubelet доступ не ограничивается сетевыми политиками (если только к метрикам), а вот к api-server можно и нужно. Для анализа источников запросов можно использовать инструмент https://github.com/kinvolk/inspektor-gadget. Мы проанализировали трафик с кластеров, и оставили доступ к api только тем приложениям, которым он действительно нужен, а для остальных ограничили доступ написав специальный NetworkPolicy

      • Да, чтобы использовать этот функционал мы обновились на свежую версию Calico, сейчас комбинируем как внешние фаервольные решения так и внутренние