Хабр, привет!

Меня зовут Александр Кузьмин, я старший инженер в КРОК, занимаюсь облачными технологиями, микросервисами и всеми новомодными DevOps-методологиями. 

В этом посте хочу поговорить про Kubernetes, а именно — про организацию доступа в кластер. Развернуть кластер несложно, а вот постоянно поддерживать его в рабочем состоянии — это задачка уровнем выше. И здесь не избежать вечного вопроса «как сделать так, чтобы Вася не сломал то, что придумал Петя».

В посте рассказываю, как мы работаем с этим в КРОК: какие механизмы ограничения доступа используем, как их подбираем и какие важные моменты учитываем. Всё в деталях, как мы любим на Хабре — с подробными пошаговыми описаниями, лайфхаками из личного опыта и удобной шпаргалкой в конце. Пост основан на моем докладе на последнем DevOops Conf, так что если видео вам заходит лучше, приглашаю по ссылке.

Зачем ограничивать доступ или «Я что-то нажал, и все исчезло»

Самый простой способ предоставить доступ пользователю в кластер Kubernetes — дать ему готовый конфиг, который был сгенерирован во время создания самого кластера. Можно совсем не заморачиваться и раздать всем полные админские права — тогда головной боли «у вас недостаточно прав на выполнение этого действия» не будет. Звучит вкусно, но в реале вред может перевесить пользу.

  • У юзера может не быть достаточно навыков, чтобы работать с кластером.

  • Все мы люди, и изменить состояние кластера сдуру случайно может любой мимокрокодил.

  • А нужен ли пользователю этот самый «полный доступ»?

Даже на это можно закрыть глаза, если манифесты, из которых деплоится приложение, хранятся в гите. Чересчур активный пользователь внес правки, но их можно откатить и вернуться к «заводским настройкам». Еще вариант — настроен CI/CD, и пользователь вообще не ходит в кластер куба, а просто коммитит новые данные в гит. 

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

Как работает механизм ограничения доступа в Kubernetes

В кластере Kubernetes доступ ко всему по умолчанию запрещен. Role-Based Access Control или RBAC — это нативный механизм, который разграничивает доступ в Kubernetes.

Глобально он состоит из двух частей:

  • Role описывает, к каким ресурсам разрешен доступ. Она отвечает за ресурсы какого-то конкретного namespace. 

  • Role Binding отвечает на вопрос, кто может выполнять действия — пользователь/группа/сервис-аккаунт.

Еще один уровень доступа — это: 

  • Role и Cluster Role

  • Role Binding и ClusterRole Binding.

ClusterRole и ClusterRoleBinding — это ресурсы всего кластера, а Role и RoleBinding — ресурсы конкретного namespace. 

Таким образом, доступ в кластер дается только к тем ресурсам, которые прописаны в Role. Если у пользователя несколько ролей, он может делать все, что разрешает ему любая из них.

Вот так схематично выглядят уровни доступа
Вот так схематично выглядят уровни доступа

Создаем Role и RoleBinding

Описываем Role — скрин слева: 

  1. В поле metadata namespace не указан, соответственно роль будет создана в namespace default. И все разрешения, которые в ней описаны, будут относится только к этому namespace. Можно указать тот namespace, в который необходимо создать эту роль.

  2. В графе rules мы описываем правила, которые разрешают действия с какими-то определенными сущностями, с ресурсами в кластере. В данном случае мы используем разрешаем доступ ко всем API группам. 

  3. В качестве resources в данном примере мы прописываем только pods, но здесь можно использовать любые сущности кластера — deployment, service, job, cronjob и так далее.

  4. В поле verbs мы указываем глаголы, которые определяют то действие, которое пользователь сможет выполнить: get, list, watch, update, create, delete и так далее.

Мы сейчас создали роль, которая называется pod-reader. Она разрешает выполнять действия get, list и watch с сущностями pods. Для пользователя это означает, что других действий он выполнить не сможет — при условии, что у него не будет подключено других ролей. 

Скрин справа — это пример манифеста для создания RoleBinding. Он привязывает роль, которая описана слева, с конкретным пользователем. 

  1. Здесь мы указываем в поле kind, что это RoleBinding.

  2. Указываем имя и как раз namespace. 

  3. Дальше через roleref указываем ссылку на имя той роли, с которой мы хотим ее связать. 

  4. В следующем поле subjects мы указываем к какой сущности, то есть к кому мы привязываем эту роль. В этом примере в поле kind у нас указан user, name и apiGroup. 

Как я упомянул в начале поста, помимо kind и user можно использовать сервис, аккаунт или группу. Соответственно, если у вас в поле kind будет группа, то все пользователи, которые входят в эту группу будут иметь разрешение на эту роль. 

Кратко о способах аутентификации

Один способ — базовая аутентификация, когда через API серверу передается конфигурация: имя пользователя, пароль и так далее. В продакшене этот способ давно не используется.

Другой способ — с помощью клиентского сертификата. Создается запрос на подпись сертификата с заверением его в центре сертификации Kubernetes для получения сертификата пользователя. 

Еще один способ – с помощью Bearer-token или JWT (JSON Web Token).

Именно эти два последних способа наиболее распространены и чаще всего используются. Вот о них и поговорим подробнее.

Способ аутентификации через сертификат 

Для доступа в кластер с помощью клиентского сертификата нужно пошагово пройти вот такой путь:

  1. Создать закрытый ключ RSA

  2. Создать запрос на подпись сертификата CSR

  3. Подписать CSR в центре сертификации вашего кластера Kubernetes

  4. Сгенерировать kubeconfig для пользователя

  5. Добавить в этот kubeconfig подписанный сертификат

  6. Создать 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.
Вот таким алгоритмом определяется, может ли пользователь получить доступ в 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 

  1. Пользователь заходит в Gangway, откуда перенаправляется в DEX и вводит свои учетные данные

  2. DEX отправляет запрос на LDAP сервер для проверки валидности данных (пароль, имя и т.п.).

  3. Если данные валидны, то DEX возвращает в Gangway 3 токена: acsess_token, refresh_token и id_token, которые нужны для аутентификации пользователя. Refresh_token используется для обновления access_token, так как «живет» он по умолчанию 24 часа. Для пользователя процесс незаметный, все выполняется автоматически. В случае с Keycloak обращения требуется не всегда, так как данные хранятся в собственной базе. 

  4. После этого Gangway выдает пользователю сгенерированный kubeconfig, который можно скачать, либо выполнить набор команд, для генерации kubeconfig локально.

  1. С помощью полученного kubeconfig пользователь отправляет запрос через kubectl в K8s API сервер, который направляет данные в DEX/Keycloak для проверки валидность токенов.

  2. Если токены верны, то K8s API сервер возвращает пользователю результат.

Что в итоге лучше выбрать

Ниже бонус для тех, кто дочитал до конца — таблица-шпаргалка с кратким описанием перечисленных подходов и их преимуществами.

Способ аутентификации

Когда использовать

Доступ в кластер с помощью сертификата

Этот вариант подойдет, если у вас небольшой проект с ограниченными ресурсами внутри кластера, и вы не планируете часто добавлять или удалять пользователей — или следить за ними.

DEX

Хорошее решение, если нужно настроить аутентификацию пользователей через LDAP и при этом нет каких-то особых требований к механизму. Например, нужно настроить только возможность аутентификации пользователей LDAP в k8s, без каких-либо дополнительных бекендов. Либо у вас в проекте уже используется DEX для каких-то других сервисов.

Keycloack

Используем в проектах, где нужно реализовать Single Sign On — доступ одних и тех же пользователей в большое количество не связанных между собой сервисов.

Все три подхода, на мой взгляд, имеют право на существование. При выборе лучше всего идти от задачи, а не обрекать себя на упорные, но бесполезные поиски «серебряной пули». В своей практике я использовал все три метода: и нативный, и Keycloack, и DEX. 

Не забываем и про «шаг номер ноль» — определитесь, сколько людей будет пользоваться кластером, и есть ли уже в проекте системы авторизации и аутентификации. После этого прогоняем решение через 4 фильтра: 

  • среду, в которой существует проект;

  • провайдера, с которым работаете;

  • специфику проекта;

  • и цели, которые преследуете.

И потом настраиваем все по описанным выше шагам. Тогда вы не оставите никаких шансов чересчур активному Васе «набезобразить» в кубере — доступ разграничен, у каждого своя роль и все, включая Петю, спокойны и счастливы.

Комментарии (0)