Kubernetes RBAC и PodSecurityPolicy: аудит кластера и три недели вычистки cluster-admin
RBAC включён с Kubernetes 1.8 по умолчанию - но ClusterRoleBinding с cluster-admin щедро раздан. Аудит безопасности кластера клиента и три недели замены на минимальные права.
RBAC в Kubernetes стал обязательным по умолчанию с версии 1.8, PodSecurityPolicy в активном использовании
Клиент обратился с задачей: провести аудит безопасности Kubernetes-кластера перед тем, как туда переедет часть продакшн-нагрузки. Кластер уже работал несколько месяцев, деплоили активно, security-настройки откладывали «на потом». «Потом» наступило.
Первое что проверяем в таких случаях - RBAC. С версии 1.8 он включён по умолчанию, и это хорошо. Плохо то, что включить RBAC и настроить RBAC - это разные задачи, и между ними бывает пропасть.
Что нашли при аудите
Пропасть была.
kubectl get clusterrolebindings вернул список, в котором cluster-admin был привязан к нескольким ServiceAccount-ам разных namespace-ов. Часть из них явно создавалась как временное решение («щас быстро подниму Helm, потом разберёмся»), часть - по образцу из статей, где для простоты дают cluster-admin и идут дальше. CI-система деплоила через ServiceAccount с полными правами на кластер. Несколько разработчиков имели cluster-admin через группу.
Это классическая ситуация: RBAC формально включён, аудитору можно показать - смотрите, у нас авторизация есть. Реально cluster-admin на ServiceAccount в том же кластере, где крутятся приложения, означает что скомпрометированный под может делать с кластером что угодно - удалять namespace-ы, читать секреты, деплоить что попало.
С PodSecurityPolicy картина была похожей. PSP-контроллер включён, одна политика есть - privileged, привязана через ClusterRoleBinding к system:authenticated. То есть любой аутентифицированный пользователь мог запустить привилегированный под. Смысл контроллера при такой конфигурации стремится к нулю.
Как чинили
Три недели. Это не потому что всё сложно технически - а потому что надо разобраться кому что реально нужно, прежде чем что-то отключать.
Первая неделя ушла на инвентаризацию. Собрали все ClusterRoleBinding и RoleBinding, составили карту: кто, к чему, зачем. Отдельно - ServiceAccount-ы: какие используются реально, какие болтаются без работы. Выяснилось что несколько ServiceAccount с cluster-admin созданы для приложений, которые давно не работают. Их убрали сразу - это ни на что не влияло.
Вторая неделя - замена cluster-admin на минимально необходимые права для действующих субъектов.
CI/CD. Пайплайн деплоя реально нуждался в: создании/обновлении Deployment, Service, ConfigMap и Secret в конкретных namespace-ах. Написали Role с точным набором ресурсов и глаголов, создали RoleBinding к ServiceAccount пайплайна в каждом namespace-е. Проверили деплой - работает.
Helm (Tiller). Отдельная история. Tiller в Helm работает как сервер внутри кластера, и по умолчанию его обычно запускают с cluster-admin - так показано в большинстве туториалов. Мы ограничили Tiller отдельным ServiceAccount с правами только на namespace-ы, которые он реально обслуживает. Это немного болезненно - пришлось разнести Tiller по namespace-ам, но иначе правильно не сделать.
Разработчики. Часть разработчиков получила cluster-admin «потому что им нужен был доступ смотреть логи». Логи и доступ на чтение Pod, Deployment, Service - это конкретная Role, не cluster-admin. Переделали. Никто не жаловался.
Третья неделя - PodSecurityPolicy. Написали две политики: restricted (без privileged, без hostPath, без hostNetwork, запуск от непривилегированного пользователя) и privileged (для системных компонентов - kube-system, мониторинг). Привязали restricted к всем namespace-ам с приложениями по умолчанию, privileged - точечно к ServiceAccount-ам системных компонентов.
Здесь первые дни были не самые спокойные. Несколько приложений оказались написаны в предположении что можно писать в корневую файловую систему контейнера. Пришлось добавить emptyDir-тома и задокументировать для команды разработки.
Что в итоге
После трёх недель картина стала читаемой: каждый субъект имеет ровно те права, которые ему нужны для работы. Никаких catch-all cluster-admin кроме системных компонентов. PSP реально ограничивает что можно запустить в кластере.
Важный момент который стоит зафиксировать: всё это было технически несложно. Объём работы определялся не сложностью настройки RBAC, а временем на то, чтобы понять что реально происходит в кластере - какие ServiceAccount-ы живые, что деплоят пайплайны, что нужно приложениям. Без этой инвентаризации можно что-то сломать и сделать хаотичный откат.
Ещё одно наблюдение: документация по Kubernetes в части примеров грешит cluster-admin там, где он не нужен. Это работает как пример для копипасты и так разлетается по кластерам. Когда делаете аудит - первым делом смотрите на ClusterRoleBinding, там всё написано.
Подробнее о том, как мы строим аудит безопасности Kubernetes-кластеров - в описании аудита информационной безопасности.