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

Kubernetes 1.6: RBAC по умолчанию и etcd3 - мигрируем права без downtime

Kubernetes 1.6 включил RBAC по умолчанию и перешёл на etcd3. Рассказываем как пересматривали все ServiceAccount и ClusterRoleBinding и что стало с audit-логами.

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

Kubernetes 1.6 (март 2017) - RBAC включён по умолчанию, etcd3 как хранилище по умолчанию, расширенный scheduler с приоритетами

Kubernetes 1.6 вышел в конце марта. Для тех, кто уже в продакшне - это не «интересный релиз», это работа: обновление потребовало пройтись по каждому ServiceAccount и каждому ClusterRoleBinding во всех кластерах. Иначе часть сервисов просто перестаёт работать после апгрейда.

Что изменилось и почему это важно

В 1.5 RBAC уже существовал, но был опциональным. Большинство дефолтных установок работали с --authorization-mode=AlwaysAllow, то есть любой под мог делать любые запросы к API-серверу. Это удобно при разработке и опасно в продакшне. В 1.6 флаг сменился на --authorization-mode=RBAC, и теперь это умолчание.

Второе изменение - etcd3 как хранилище по умолчанию. etcd2 никуда не делся, поддержка сохраняется, но если разворачиваешь кластер с нуля через kubeadm, получаешь etcd3. Это другой протокол (gRPC вместо HTTP), другая модель транзакций, другая схема хранения ключей.

Оба изменения одновременно - это не самое удобное сочетание для недели обновлений.

Как выглядел аудит существующих прав

На наших managed-кластерах к моменту 1.6 накопилось несколько паттернов использования ServiceAccount, которые в 1.5 просто работали, а в 1.6 стали требовать явных разрешений.

Первый случай - операторы и контроллеры, написанные своими руками. Если под делал GET/LIST по pods, nodes или endpoints через in-cluster config, он использовал ServiceAccount namespace/default. В 1.5 - работает. В 1.6 без явного RoleBinding к view или кастомной Role - 403.

Второй случай - helm-tiller. Tiller по умолчанию устанавливается в kube-system и работает от ServiceAccount tiller который в 1.5 имел широкий доступ через legacy-привилегии. В 1.6 tiller начинал падать с permission denied при попытке создавать ресурсы в других namespace. Решение - ClusterRoleBinding с ролью cluster-admin для tiller-а, что грубо, но работает. Более аккуратный вариант - отдельная Role на каждый namespace, куда tiller должен деплоить.

Третий случай - приложения, которые сами обращаются к API Kubernetes для service discovery. Это встречается реже, но встречается: сервис читает Endpoints своих зависимостей через kube API вместо DNS. В 1.6 это требует явной роли с правом get/list на endpoints.

Аудит делали в два прохода. Сначала поднимали кластер 1.6 в режиме --authorization-mode=RBAC но с флагом --rbac-error-level=permissive - нарушения логировались, но не блокировались. Это дало список всех 403-запросов которые случились бы при строгом режиме. Потом по этому списку писали Role и RoleBinding.

Миграция без downtime

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

Сложнее было с кластерами, которые обновляли на месте (in-place upgrade). Там алгоритм:

  • Шаг 1. Пока кластер на 1.5, добавить все RBAC-объекты через kubectl apply. В 1.5 RBAC-API уже есть, объекты создаются. Права пока не применяются (AlwaysAllow), но объекты в etcd лежат.
  • Шаг 2. Обновить control plane до 1.6. API-сервер перезапускается с RBAC-режимом. Все RBAC-объекты которые мы создали на шаге 1 - уже действуют.
  • Шаг 3. Обновить ноды по одной через drain/upgrade/uncordon.

Downtime при таком порядке - только время рестарта API-сервера, секунды-десятки секунд. Поды на нодах продолжают работать, новые запросы к API-серверу встают в очередь или получают connection refused, но workload не прерывается.

Один нюанс: если между шагом 1 и шагом 2 прошло время и кто-то успел создать новые ServiceAccount или Deployment без RBAC-объектов - они сломаются после апгрейда. Мы держали окно обновления short и коммуницировали с командой разработки заранее.

etcd2 -> etcd3: отдельная история

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

Kubernetes 1.6 умеет работать с обоими. По умолчанию новые кластеры - etcd3. Существующие с etcd2 продолжают работать с etcd2 пока вы не скажете явно о миграции.

Мы пока не мигрировали существующие кластеры с etcd2 на etcd3. Причина прозаичная: нет давления с точки зрения производительности или возможностей. Новые кластеры разворачиваем на etcd3. Смешивать не получится - это два разных протокола.

Audit-логи стали другими

С RBAC в дефолте audit-логи изменились качественно. Раньше в логах было всё подряд, включая кучу шума от internal-компонентов. Теперь 403 по RBAC генерирует запись с explicit причиной: какой ServiceAccount, к какому ресурсу, какой verb, какого разрешения не хватает.

Это сделало диагностику проблем с правами намного быстрее. Раньше «почему под не работает» превращалось в угадывание. Теперь открываешь kubectl logs kube-apiserver-... -n kube-system, ищешь RBAC, читаешь: User "system:serviceaccount:production:myapp" cannot list pods in the namespace "production". Понятно что делать.

Итог

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

RBAC по умолчанию - давно напрашивавшееся решение. Кластеры с AlwaysAllow в продакшне были техническим долгом которого многие просто не замечали.

Контакт

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

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