ADG Оставить заявку
Блог DevOps 5 мин чтения

Kubernetes 1.4 RBAC и Network Policy: включаем многоарендную безопасность кластера

Kubernetes 1.4 перевёл RBAC и Network Policy в beta. Включаем RBAC в тестовом кластере - разграничение прав по неймспейсам оказалось проще ожидаемого, но потребовало ревизии всех сервисных аккаунтов.

Контекст момента

Kubernetes 1.4 добавил Network Policy API и RBAC в статус beta, заложив основу для многоарендной безопасности кластера

В сентябре мы поднимали кластер с kubeadm и радовались, что это стало занимать 20 минут вместо полутора часов. Но тогда оставили за скобками одну вещь: в 1.4 вместе с kubeadm тихо появились RBAC (Role-Based Access Control) и Network Policy API - оба в статусе beta. Пришло время разобраться, что с ними делать.

Контекст такой: у нас тестовый кластер, в котором мы обкатываем несколько проектов для разных заказчиков. Раньше разграничение было условным - разные неймспейсы, разные манифесты, но ничто технически не мешало поду из одного проекта обратиться к API другого или вообще к kube-apiserver напрямую с правами по умолчанию. Это не продакшн, но привычка работать без ограничений на тестовом стенде потом аукается.

Что такое RBAC в kubernetes 1.4

До 1.4 доступ к kube-apiserver контролировался через ABAC (Attribute-Based Access Control) - политики в виде JSON-файла на мастере, которые надо было менять руками и перезапускать apiserver. Неудобно, не динамично, не масштабируется.

RBAC - это Roles, ClusterRoles, RoleBindings и ClusterRoleBindings как обычные объекты kubernetes. Создаёшь через kubectl apply, меняешь без рестарта компонентов, видишь в kubectl get. Логика простая:

  • Role - набор разрешений в рамках одного неймспейса (get pods, list services и т.д.).
  • ClusterRole - то же самое, но для кластерных ресурсов или как шаблон для переиспользования.
  • RoleBinding - привязывает Role к пользователю, группе или ServiceAccount в рамках неймспейса.
  • ClusterRoleBinding - привязывает ClusterRole глобально.

Включаем - и обнаруживаем что сломалось

Включить RBAC в apiserver: добавить --authorization-mode=RBAC в аргументы запуска kube-apiserver. Перезапустили. Кластер поднялся, kubectl get nodes отвечает. Запускаем свои приложения - часть из них перестаёт работать.

Вот тут началось самое образовательное. Несколько наших сервисов использовали клиентскую библиотеку kubernetes для обращения к API прямо из пода - для service discovery, для чтения ConfigMap-ов, для одного самодельного оркестратора. Все они использовали дефолтный ServiceAccount неймспейса, которому по умолчанию при включённом RBAC не дано вообще ничего.

Список пострадавших оказался длиннее, чем мы думали. Это первый практический урок: при включении RBAC нужно сначала пройтись по всем сервисам и понять, какие из них вообще ходят в kube-apiserver. Мы не имели такого списка, потому что раньше это не было важно.

Ревизия сервисных аккаунтов

Потратили несколько часов на аудит. Алгоритм оказался несложным: смотришь в код сервиса или в его зависимости, ищешь инициализацию kubernetes-клиента. Если клиент инициализируется через rest.InClusterConfig() - сервис ходит в API под своим ServiceAccount.

По итогам выяснилось что у нас три категории:

  • Сервисы только для чтения - нужен доступ к pods и endpoints в своём неймспейсе. Создали Role с get, list, watch на нужные ресурсы, привязали к отдельному ServiceAccount через RoleBinding.
  • Оркестратор - нужен доступ к deployments и replicasets для управления. Чуть шире роль, но по-прежнему в рамках одного неймспейса.
  • Сервисы, которым API не нужен - оказалось что два сервиса инициализировали клиент «на всякий случай» из-за общей библиотеки, но реально не использовали. Убрали зависимость.

Создание ролей - дело несложное. Типичная Role выглядит так:

apiVersion: rbac.authorization.k8s.io/v1alpha1
kind: Role
metadata:
  name: pod-reader
  namespace: project-a
rules:
- apiGroups: [""]
  resources: ["pods", "endpoints"]
  verbs: ["get", "list", "watch"]

Привязываем к ServiceAccount, прописываем этот ServiceAccount в spec.serviceAccountName деплоймента - готово. На удивление просто, если знать что делаешь.

Network Policy - пока только посмотрели

Network Policy API - это возможность описать, какой трафик разрешён между подами, в виде объектов kubernetes. Запрещаешь всё по умолчанию, разрешаешь конкретные пути. Выглядит как правильный способ сегментировать сеть без iptables руками.

Проблема: Network Policy работает только если CNI-плагин его поддерживает. Flannel, который мы используем в тестовом кластере, - не поддерживает. Calico или Weave Net - поддерживают, но пересаживаться на другой CNI в середине эксперимента не хотелось.

Поэтому с Network Policy пока только изучили синтаксис, написали несколько манифестов на бумаге. До реального тестирования доберёмся отдельно, когда будет стенд с Calico.

Что получилось

RBAC включён в тестовом кластере и работает уже несколько дней. Ощущение от процесса: сама механика ролей понятная, YAML читается нормально, ошибки доступа видны в логах сервисов с внятными сообщениями. Главный сюрприз - не сложность настройки RBAC, а то сколько сервисов неосознанно полагались на отсутствие ограничений.

Теперь в чеклисте для новых сервисов появился пункт: явно определить нужен ли доступ к kube-apiserver, и если да - какой минимальный. Это правильная привычка вне зависимости от того, включён RBAC или нет.

На продакшн-кластерах заказчиков, которым мы занимаемся администрированием инфраструктуры, RBAC включим после того как пройдём такую же ревизию там. Спешки нет, но откладывать тоже не стоит - с каждым новым сервисом аудит становится дороже.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.