Ограничиваем доступ в Kubernetes: без смс, но с регистрацией
Хабр, привет!
Меня зовут Александр Кузьмин, я старший инженер в КРОК, занимаюсь облачными технологиями, микросервисами и всеми новомодными DevOps-методологиями.
В этом посте хочу поговорить про Kubernetes, а именно — про организацию доступа в кластер. Развернуть кластер несложно, а вот постоянно поддерживать его в рабочем состоянии — это задачка уровнем выше. И здесь не избежать вечного вопроса «как сделать так, чтобы Вася не сломал то, что придумал Петя».
В посте рассказываю, как мы работаем с этим в КРОК: какие механизмы ограничения доступа используем, как их подбираем и какие важные моменты учитываем. Всё в деталях, как мы любим на Хабре — с подробными пошаговыми описаниями, лайфхаками из личного опыта и удобной шпаргалкой в конце. Пост основан на моем докладе на последнем DevOops Conf, так что если видео вам заходит лучше, приглашаю по ссылке.
Зачем ограничивать доступ или «Я что-то нажал, и все исчезло»
Самый простой способ предоставить доступ пользователю в кластер Kubernetes — дать ему готовый конфиг, который был сгенерирован во время создания самого кластера. Можно совсем не заморачиваться и раздать всем полные админские права — тогда головной боли «у вас недостаточно прав на выполнение этого действия» не будет. Звучит вкусно, но в реале вред может перевесить пользу.
У юзера может не быть достаточно навыков, чтобы работать с кластером.
Все мы люди, и изменить состояние кластера сдуру случайно может любой мимокрокодил.
А нужен ли пользователю этот самый «полный доступ»?
Даже на это можно закрыть глаза, если манифесты, из которых деплоится приложение, хранятся в гите. Чересчур активный пользователь внес правки, но их можно откатить и вернуться к «заводским настройкам». Еще вариант — настроен CI/CD, и пользователь вообще не ходит в кластер куба, а просто коммитит новые данные в гит.
Но эти ситуации из вселенной в идеальном вакууме, а мы живем и работаем в реальном мире, где есть ограничения. Поэтому доступ в кластер нужно все-таки разграничивать.
Как работает механизм ограничения доступа в Kubernetes
В кластере Kubernetes доступ ко всему по умолчанию запрещен. Role-Based Access Control или RBAC — это нативный механизм, который разграничивает доступ в Kubernetes.
Глобально он состоит из двух частей:
Role описывает, к каким ресурсам разрешен доступ. Она отвечает за ресурсы какого-то конкретного namespace.
Role Binding отвечает на вопрос, кто может выполнять действия — пользователь/группа/сервис-аккаунт.
Еще один уровень доступа — это:
ClusterRole и ClusterRoleBinding — это ресурсы всего кластера, а Role и RoleBinding — ресурсы конкретного namespace.
Таким образом, доступ в кластер дается только к тем ресурсам, которые прописаны в Role. Если у пользователя несколько ролей, он может делать все, что разрешает ему любая из них.
Вот так схематично выглядят уровни доступа
Создаем Role и RoleBinding
Описываем Role — скрин слева:
В поле metadata namespace не указан, соответственно роль будет создана в namespace default. И все разрешения, которые в ней описаны, будут относится только к этому namespace. Можно указать тот namespace, в который необходимо создать эту роль.
В графе rules мы описываем правила, которые разрешают действия с какими-то определенными сущностями, с ресурсами в кластере. В данном случае мы используем разрешаем доступ ко всем API группам.
В качестве resources в данном примере мы прописываем только pods, но здесь можно использовать любые сущности кластера — deployment, service, job, cronjob и так далее.
В поле verbs мы указываем глаголы, которые определяют то действие, которое пользователь сможет выполнить: get, list, watch, update, create, delete и так далее.
Мы сейчас создали роль, которая называется pod-reader. Она разрешает выполнять действия get, list и watch с сущностями pods. Для пользователя это означает, что других действий он выполнить не сможет — при условии, что у него не будет подключено других ролей.
Скрин справа — это пример манифеста для создания RoleBinding. Он привязывает роль, которая описана слева, с конкретным пользователем.
Здесь мы указываем в поле kind, что это RoleBinding.
Указываем имя и как раз namespace.
Дальше через roleref указываем ссылку на имя той роли, с которой мы хотим ее связать.
В следующем поле subjects мы указываем к какой сущности, то есть к кому мы привязываем эту роль. В этом примере в поле kind у нас указан user, name и apiGroup.
Как я упомянул в начале поста, помимо kind и user можно использовать сервис, аккаунт или группу. Соответственно, если у вас в поле kind будет группа, то все пользователи, которые входят в эту группу будут иметь разрешение на эту роль.
Кратко о способах аутентификации
Один способ — базовая аутентификация, когда через API серверу передается конфигурация: имя пользователя, пароль и так далее. В продакшене этот способ давно не используется.
Другой способ — с помощью клиентского сертификата. Создается запрос на подпись сертификата с заверением его в центре сертификации Kubernetes для получения сертификата пользователя.
Еще один способ — с помощью Bearer-token или JWT (JSON Web Token).
Именно эти два последних способа наиболее распространены и чаще всего используются. Вот о них и поговорим подробнее.
Способ аутентификации через сертификат
Для доступа в кластер с помощью клиентского сертификата нужно пошагово пройти вот такой путь:
Создать закрытый ключ RSA
Создать запрос на подпись сертификата CSR
Подписать CSR в центре сертификации вашего кластера Kubernetes
Сгенерировать kubeconfig для пользователя
Добавить в этот kubeconfig подписанный сертификат
Создать Role/ClusterRole для пользователя и привязать Role/ClusterRole к пользователю, то есть создать Role Binding, либо ClusterRoleBinding.
На первый взгляд, это долго и сложно, но сейчас всё можно автоматизировать — и этот случай не исключение. Берем скрипт на Bash или playbook на Ansible и делаем так, чтобы при передачи определенных данных магия происходила сама.
Плюсы сертификации
При развертывании кластера Kubernetes у вас уже есть набор созданных ролей, например, editor, viewer и т. д. Их можно использовать для предоставления ограниченного доступа как пользователю, так и приложению.
Минусы сертификации
Конечно, они тоже есть. Когда вы создаете kubeconfig на основе клиентского сертификата, вам нужно отдельно контролировать, сколько людей имеют доступ в кластер. Вопрос в том, как вы будете это делать и сколько ресурсов на это потратите. Ещё один вопрос вдогонку — как отозвать сертификат, если пользователь ушел из компании, проекта или просто по каким-то причинам больше не должен иметь доступ в кластер?
Как работает OpenID Connect
Прежде чем говорить о сторонних провайдерах аутентификации, кратко расскажу про сам OpenID Connect (OIDC).
Это механизм, который лежит в основе DEX, Keycloack и других OIDC провайдеров. Он позволяет пользователю, имея одну учетную запись, авторизоваться в других, несвязанных между собой сервисах. Самый яркий пример, знакомый любому — авторизация на GitHub через учетку Gmail.
Алгоритм авторизации в кубере выглядит вот так:
сначала пользователь выполняет вход в identity provider;
после этого identity provider возвращает пользователю access token, id token и refresh token;
пользователь вызывает команду kubectl и передает ей свой id token, который он получил от identity-провайдера;
kubectl выполняет авторизацию в API сервере;
API сервер, в свою очередь, проверяет валиден ли этот токен, его срок действия, выполняет авторизацию пользователя и после этого возвращает ответ в kubectl;
kubectl возвращает результат уже непосредственно пользователю.
Вот таким алгоритмом определяется, может ли пользователь получить доступ в API-сервер в кластере Kubernetes, когда используется OIDC.
Сторонние identity-провайдеры: начнем с DEX
А теперь разберем детальнее конкретных OIDC провайдеров. Для начала — DEX. Он использует OpenID Connect для идентификации других пользователей и умеет работать с большим количеством бэкендов, в том числе LDAP.
DEX прост для освоения, с низким порогом входа, он легко устанавливается и разворачивается. Но есть важный момент — нужно заранее побеспокоиться о создании сертификатов для DEX и Gangway. При этом конфигурации достаточно простые и нативные и не требуют глубокого погружения.
У DEX есть небольшая база данных, в которой он кэширует пользователей. Но при проверки пользователя он обращается к LDAP-серверу, поэтому нельзя сказать, что это полноценная устойчивая БД (в отличие от Keycloack). Для аутентификации и автоматической генерации kube-config используется утилита, которая называется Gangway.
Плюс DEX — простота конфигурации: все данные указываются в configmap, поэтому промежуточный интерфейс не требуется.
Минус — поддерживает не все backend-ы, и подходит не для всех проектов.
Пара слов о связке DEX и Gangway
Общение DEX и Gangway между собой происходит только через TLS. Поэтому, перед тем как разворачивать эти сервисы в любой среде (продуктовой или лабораторной), нужно позаботиться о сертификатах.
Если DEX и Gangway развернуть внутри Kubernetes, для них будут созданы сущности под названием ingress. Они будут иметь свои адреса — например, dex.example.com и gateway.example.com. Для них нужно будет сгенерировать сертификаты TLS и подгрузить их в Kubernetes.
В лабораторной среде вы можете подписать их корневым центром сертификации Kubernetes, который использовался при развертывании кластера.
В продуктивной среде у вас уже есть какой-то центр сертификации, которым вы можете подписать сертификаты.
Не забывайте, что срок действия сертификатов ограничен. Идеально — «повесить» дополнительный мониторинг на сертификаты, чтобы не забыть в определённый момент продлить их. Еще вариант — использовать дополнительный сервис, который будет автоматически продлевать сертификаты.
Таким сервисом может быть cert-manager. С его помощью можно сгенерировать сертификаты, и он сам будет следить, подходит ли срок действия сертификатов к концу. Если их надо обновить, он это сделает за вас.
Одним словом, сроки действия сертификатов — это тонкий момент, и для новых пользователей, которые только начинают знакомиться с внешними системами авторизации в Kubernetes, он добавляет головной боли. Советую решить этот вопрос до того, как ваша связка заработает.
Установка DEX простая — с помощью Helm-Chart. Все конфигурации по настройке DEX и параметров подключения к LDAP-серверу: логин, пароль, адрес и прочие списки групп, в которых нужно искать ваших пользователей — находятся в configmap. Никакого отдельного веб-интерфейса DEX под собой не имеет.
Keycloak — еще один сторонний identity-провайдер
Алгоритм выполнения аутентификации и авторизации пользователя у Keycloak похож на DEX, но с отличием — у Keycloak есть свой веб-интерфейс, через который выполняется конфигурация. По умолчанию у него есть встроенная база данных, но в продуктивной среде вы можете использовать внешнюю — например, Postgres.
Установка Keycloak также несложная — с GitHub клонируется набор манифестов и разворачиваются такие сущности как deployment, services, ingress и т.д.
Плюс Keycloak — поддерживает довольно много провайдеров с точки зрения бэкенда, не только Kubernetes. Его можно использовать в качестве SSO-сервера (Single Sign On), когда нужно организовать доступ одних и тех же пользователей в большое количество разных несвязных между собой сервисов.
Минус — высокий порог вхождения в сравнении с DEX. Этот монструозный комбайн позволяет работать с большим количеством бэкендов, но ради этого придется ознакомится с длинным списком дополнительной литературы, чтобы разобраться, как все должно работать.
Пошаговый алгоритм аутентификации через DEX/Keycloack
Пользователь заходит в Gangway, откуда перенаправляется в DEX и вводит свои учетные данные
DEX отправляет запрос на LDAP сервер для проверки валидности данных (пароль, имя и т.п.).
Если данные валидны, то DEX возвращает в Gangway 3 токена: acsess_token, refresh_token и id_token, которые нужны для аутентификации пользователя. Refresh_token используется для обновления access_token, так как «живет» он по умолчанию 24 часа. Для пользователя процесс незаметный, все выполняется автоматически. В случае с Keycloak обращения требуется не всегда, так как данные хранятся в собственной базе.
После этого Gangway выдает пользователю сгенерированный kubeconfig, который можно скачать, либо выполнить набор команд, для генерации kubeconfig локально.
С помощью полученного kubeconfig пользователь отправляет запрос через kubectl в K8s API сервер, который направляет данные в DEX/Keycloak для проверки валидность токенов.
Если токены верны, то K8s API сервер возвращает пользователю результат.
Что в итоге лучше выбрать
Ниже бонус для тех, кто дочитал до конца — таблица-шпаргалка с кратким описанием перечисленных подходов и их преимуществами.
Способ аутентификации | Когда использовать |
Доступ в кластер с помощью сертификата | Этот вариант подойдет, если у вас небольшой проект с ограниченными ресурсами внутри кластера, и вы не планируете часто добавлять или удалять пользователей — или следить за ними. |
DEX | Хорошее решение, если нужно настроить аутентификацию пользователей через LDAP и при этом нет каких-то особых требований к механизму. Например, нужно настроить только возможность аутентификации пользователей LDAP в k8s, без каких-либо дополнительных бекендов. Либо у вас в проекте уже используется DEX для каких-то других сервисов. |
Keycloack | Используем в проектах, где нужно реализовать Single Sign On — доступ одних и тех же пользователей в большое количество не связанных между собой сервисов. |
Все три подхода, на мой взгляд, имеют право на существование. При выборе лучше всего идти от задачи, а не обрекать себя на упорные, но бесполезные поиски «серебряной пули». В своей практике я использовал все три метода: и нативный, и Keycloack, и DEX.
Не забываем и про «шаг номер ноль» — определитесь, сколько людей будет пользоваться кластером, и есть ли уже в проекте системы авторизации и аутентификации. После этого прогоняем решение через 4 фильтра:
среду, в которой существует проект;
провайдера, с которым работаете;
специфику проекта;
и цели, которые преследуете.
И потом настраиваем все по описанным выше шагам. Тогда вы не оставите никаких шансов чересчур активному Васе «набезобразить» в кубере — доступ разграничен, у каждого своя роль и все, включая Петю, спокойны и счастливы.