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

Kubernetes 1.7: RBAC в GA - перерабатываем сервисные аккаунты на всех кластерах

Kubernetes 1.7 перевёл RBAC в статус GA. Снимаем оговорку «экспериментально» и переписываем ServiceAccount и роли под финальную спецификацию на всех managed-кластерах.

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

Kubernetes 1.7 (июнь 2017) - RBAC переведён в GA, NetworkPolicy стабилизирован, добавлен API-aggregation layer

Kubernetes 1.7 вышел в конце июня. Главное для нас - RBAC официально переведён в статус GA (Generally Available). Звучит как бюрократия, но практически означает: API rbac.authorization.k8s.io/v1 замораживается, обратная совместимость гарантируется, можно строить на этом без оговорок. Мы этого ждали и сразу взялись за переработку всего что написали в период «ещё beta».

Что изменилось в 1.7 помимо RBAC

Коротко о других вещах которые касаются нашей работы:

  • NetworkPolicy API переведён в networking.k8s.io/v1 - тоже стабилен. Синтаксис немного поменялся относительно beta-версии из 1.3-1.4.
  • API-aggregation layer - новый механизм расширения API-сервера без форка. Сторонние компоненты теперь могут регистрировать собственные API-группы через APIService. Это фундамент для будущих расширений.
  • Secrets шифруются в etcd - наконец-то возможность включить encryption at rest для объектов типа Secret через конфигурацию apiserver. Не включено по умолчанию, но API есть.
  • StatefulSet rolling updates - теперь контроллируемое обновление StatefulSet без ручного вмешательства.

GA RBAC - самое значимое именно для нас, потому что накопили технический долг: несколько кластеров с RBAC-объектами под v1alpha1 и v1beta1, написанными в разное время по разным соображениям.

Что было не так со старыми манифестами

В марте, когда мы переходили на RBAC в 1.6, писали роли под rbac.authorization.k8s.io/v1beta1. Работало. Но за три месяца накопилось несколько проблем.

Первое - непоследовательный стиль. Часть ролей написана наспех «лишь бы заработало», с glob-wildcards (verbs: ["*"]) там где их не должно быть. Часть - наоборот, избыточно детальная. Единого шаблона не было.

Второе - Tiller с cluster-admin. В посте про Helm мы честно написали что Tiller висит с правами cluster-admin и что это неправильно. За два месяца ничего не изменилось - просто не доходили руки. GA-статус RBAC стал поводом наконец разобраться.

Третье - дефолтные ServiceAccount-ы. В нескольких namespace остались деплойменты без явного serviceAccountName, то есть запускающиеся от default. При включённом RBAC это не катастрофа, но это непрозрачно: непонятно что имеет доступ к API, а что нет.

Как проводили ревизию

Взяли список всех namespace на каждом кластере, прошлись kubectl get rolebindings,clusterrolebindings --all-namespaces -o yaml. Выгрузили в файлы, смотрели глазами.

Алгоритм для каждого привязанного субъекта:

  1. Это ServiceAccount или пользователь/группа?
  2. Если ServiceAccount - какой под его использует?
  3. Этот под реально обращается к kube-apiserver? (ищем in-cluster config в коде или зависимостях)
  4. Какой минимальный набор прав достаточен?

Удивительно сколько всего находится когда смотришь систематически. На одном кластере нашли ServiceAccount с ClusterRoleBinding к view - кластерного уровня - который использовался только для чтения ConfigMap-ов в одном namespace. Вместо ClusterRoleBinding хватало RoleBinding в том же namespace. Казалось бы мелочь, но разница: view на уровне кластера позволяет читать ConfigMap-ы, Pod-ы и большинство других объектов во всех namespace, не только в своём.

Tiller: от cluster-admin к ограниченным правам

Это была главная цель. Tiller с cluster-admin - это под который может сделать что угодно в кластере, и он доступен из кода если знать адрес tiller-deploy.kube-system:44134.

Решение которое выбрали: у нас Tiller один на кластер, но каждый проект деплоится в свой namespace. Поэтому создали для Tiller-а отдельный ServiceAccount и набор RoleBinding - по одному на каждый namespace куда он деплоит:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: tiller-deploy
  namespace: project-alpha
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: edit
subjects:
- kind: ServiceAccount
  name: tiller
  namespace: kube-system

ClusterRole edit - встроенная роль, даёт права на большинство объектов в namespace кроме RBAC-объектов самих по себе. Tiller не может выдавать себе права - это важно.

Повторяем RoleBinding для каждого namespace. Да, это несколько файлов. Но теперь Tiller ограничен конкретными namespace и не может трогать kube-system или другие проекты.

После пересборки деплоя Tiller с новым ServiceAccount (helm init --service-account tiller --upgrade) - всё работает. helm upgrade, helm rollback отрабатывают нормально. Единственный момент: при попытке создать namespace через hook chart-а Tiller получает 403 - namespace создаётся заранее через отдельный манифест, не через Helm. Это вполне разумное ограничение.

Переход с v1beta1 на v1

Технически apiserver 1.7 принимает и старые объекты - v1alpha1 и v1beta1 конвертируются автоматически. Но мы переписали все манифесты явно под v1, чтобы не гадать что происходит под капотом.

Разница минимальная: изменился apiVersion, убраны несколько полей которые были в beta но не вошли в GA. Основная механика Role/RoleBinding/ClusterRole/ClusterRoleBinding - без изменений.

Прогнали kubectl apply по всем кластерам. Старые объекты под beta-версией были пересозданы или заменены. Проверили что приложения работают - всё нормально.

NetworkPolicy: теперь по-настоящему включаем

NetworkPolicy API тоже вышел в стабильное состояние, и мы наконец включаем его не только на тестовых стендах. На managed-кластерах под Calico как CNI это работает.

Базовая схема: запрет всего входящего по умолчанию в каждом namespace приложения, явное разрешение только нужных путей.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: project-alpha
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Плюс отдельные политики для конкретных сервисов. Это добавляет работы при настройке нового сервиса, но убирает класс проблем когда один под может обратиться к любому другому в кластере.

Итог

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

GA-статус RBAC снял последнее психологическое препятствие - оговорку «это ещё beta, потом переделаем». Переделали. Теперь это основа, не временное решение.

Контакт

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

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