Всем известно: предоставление привилегий — это всегда баланс между безопасностью, удобством использования и трудоемкостью обслуживания. Если разрешения предоставляются очень щедро, усилия очень малы и редко возникают какие-либо препятствия для использования; однако безопасность оказывается под угрозой. Если разрешения предоставляются экономно, безопасность выше, но есть дорогостоящие процессы и много административных накладных расходов.
Kubernetes предлагает множество возможностей с его управлением доступом на основе ролей (RBAC), которые также подробно документированы (https://kubernetes.io/docs/reference/access-authn-authz/rbac/). Однако, к сожалению, практических советов по реальной реализации не так много. Чтобы выйти из этого затруднительного положения, мы написали плагины, которые позволяют использовать контекст Kubernetes-sudo для получения простой, но эффективной точки входа для управления разрешениями. При этом в данной статье блога показано, как установить плагины и настроить кластер на примере управляемого Kubernetes из Google Cloud Platform.
- Разрешения разработчиков в кластере
- Реализация подхода с наименьшими привилегиями с помощью sudo-context
- Настройка функции impersonate
- Плагин kubectl-sudo
- Плагин helm-sudo
- Контекст sudo для других инструментов
- Настройка локальных инструментов
- Техническая реализация авторизации
- RBAC
- Облачная платформа Google (GCP)
- Заключение
Разрешения разработчиков в кластере
Представленное здесь решение относится к разрешениям людей, поскольку приложения в основном должны иметь доступ только для чтения к своим собственным секретам и конфигурационной карте в кластере. Таким образом, с точки зрения назначения разрешений все просто. Однако когда речь заходит о разрешениях для разработчиков, все становится гораздо сложнее, поскольку задачи и роли людей могут меняться со временем, а разрешения могут использоваться для защиты людей от неосторожных ошибок. Это приводит к большим усилиям по обслуживанию, о которых говорилось в начале.
Решение с минимальными затратами на обслуживание заключается в предоставлении всем разработчикам одинаковых, обширных полномочий. Однако это создает риск того, что вредные изменения могут быть случайно внесены в любое время. Особенно в производственных средах это может привести к критическим простоям и даже потере данных.
Именно поэтому мы решили использовать подход, при котором для выполнения команд кратковременно используются дополнительные привилегии, подобно команде sudo в Linux.
Реализация подхода с наименьшими привилегиями с помощью sudo-context
Чтобы реализовать разрешения в стиле sudo, необходимо выполнить следующие действия:
- Использование функции impersonate в Kubernetes
- Настройка контекста sudo
- Предоставление разрешений в кластере
Сейчас мы подробно опишем эти шаги.
Настройка функции impersonate
Функция sudo — это внутренняя функция Kubernetes API «impersonate». Она позволяет выполнять команды от имени другого пользователя, группы или учетной записи службы. Первым шагом является включение функции sudo в кластере. Существуют различные способы сделать это в зависимости от сценария использования. Ниже описано, как они устанавливаются и настраиваются на стороне клиента и кластера.
Плагин kubectl-sudo
С помощью плагина kubectl-sudo команды kubectl, требующие более широких прав, могут выполняться явно членом группы администраторов. Это снижает вероятность случайного изменения или удаления ресурсов на кластере, например, при запуске скриптов или при нахождении в неправильном пространстве имен.
Плагин работает только для kubectl, другие инструменты, использующие kubeconfig (helmet, fluxctl, k9s и т.д.), не могут его использовать. Вот простой пример использования плагина kubectl sudo get pod
.
Плагин helm-sudo
В среде Kubernetes графики Helm очень важны. Поэтому, чтобы иметь возможность использовать функциональность и для Helm, мы разработали соответствующий плагин, который можно использовать аналогично kubectl-sudo. По аналогии с использованием плагина kubectl-sudo, вот пример для плагина helm helm sudo list
.
Контекст sudo для других инструментов
В качестве альтернативы и для всех других инструментов, таких как fluxctl или k9s, есть возможность создать sudo контекст в kubeconfig. Его можно использовать следующим образом:
kubectl --context SUDO-mycontext # alternative to kubectl-sudo
kgpo --context SUDO-mycontext # also works with aliases!
helm --kube-context SUDO-mycontext
fluxctl --context SUDO-mycontext
k9s --context SUDO-mycontext # Changes also in k9s possible ":ctx"
Если для некоторых инструментов были установлены функции автозавершения, они будут автоматически определять доступные контексты и могут быть выбраны с помощью Tab
.
Внимание: При использовании контекста sudo всегда указывайте пространство имен, в котором будет выполняться команда. По умолчанию при настройке контекста в kubeconfig сохраняется только текущее пространство имен. Если команда должна быть выполнена в другом пространстве имен, это должно быть явно указано в параметре: kubectl --context SUDO-mycontext --namespace mynamespace get secret
.
Контекст sudo должен передаваться только в качестве параметра. Он никогда не должен быть установлен в качестве активного контекста, так как это предоставит постоянные права администратора и тем самым подорвет защиту от случайных изменений. Это аналогично команде sudo su
в Linux, с помощью которой пользователь получает все права и не лишается возможности выполнять рискованные действия.
Однако и kubectl sudo
, и helm sudo
не требуют каждый раз указывать пространство имен. Здесь команды всегда выполняются в текущем пространстве имен текущего контекста. Поэтому для helm и kubectl предпочтительнее использовать плагины sudo.
Настройка локальных инструментов
Для создания sudo контекста можно воспользоваться этим скриптом: wget -P /tmp/ "https://raw.githubusercontent.com/cloudogu/sudo-kubeconfig/0.1.0/create-sudo-kubeconfig.sh"
.
С его помощью необходимо выполнить только следующие шаги для интерактивного создания kubeconfig для текущего выбранного контекста:
chmod +x /tmp/create-sudo-kubeconfig.sh
/tmp/create-sudo-kubeconfig.sh
kubectl --context SUDO-mycontext get pod
При необходимости, два уже упомянутых плагина, kubectl-sudo и helm-sudo, могут быть установлены через bash:
Дополнительно: install kubectl-sudo
sudo bash -c 'curl -fSL https://raw.githubusercontent.com/postfinance/kubectl-sudo/master/bash/kubectl-sudo -o /usr/bin/kubectl-sudo && chmod a+x /usr/bin/kubectl-sudo'
kubectl sudo get pod
Дополнительно: install helm-sudo
helm plugin install https://github.com/cloudogu/helm-sudo --version=0.0.2
helm sudo list
Техническая реализация авторизации
Теперь, когда на локальном компьютере созданы все необходимые условия для использования функции sudo, необходимо настроить авторизацию. Мы покажем шаги по технической реализации на примере управляемого Kubernetes облачной платформы Google.
RBAC
С помощью функции sudo мы можем входить в роли пользователей, групп и учетных записей служб для выполнения команд (impersonate). Чтобы мы могли получить более широкие права через «impersonate», они должны быть авторизованы с помощью ролевого управления доступом Kubernetes (RBAC).
«Имперсонат» реализуется следующим образом:
- kubectl-sudo:
kubectl --as=$USER --as-group=system:masters "$@"
. - helm-sudo:
helm --kube-as-user ${USER} --kube-as-group system:masters "$@"
- и create-sudo-kubeconfig.sh:
as-groups: [ system:masters ]
.
В существующем кластере k8s необходимо создать два ресурса, чтобы предоставить пользователям доступ к функции impersonate:
- ClusterRole, который позволяет использовать функцию impersonate.
- ClusterRoleBinding, позволяющий отдельным пользователям или группам использовать ранее созданную ClusterRole.
# sudoer.yaml
# Creates a ClusterRole which allows to impersonate users,
# groups and serviceaccounts
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: sudoer
rules:
- apiGroups: [""]
verbs: ["impersonate"]
resources: ["users", "groups", "serviceaccounts"]
# cluster-sudoers.yaml
# Allows users to use kubectl sudo on all resources in the cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-sudoers
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: sudoer
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: admins@email.com
- apiGroup: rbac.authorization.k8s.io
kind: User
name: user1@email.com
В текущей привязке ClusterRoleBinding все указанные в ней пользователи имеют права sudo во всех пространствах имен. Также можно использовать несколько привязок ClusterRoleBindings и, таким образом, иметь разрешения только для определенных пространств имен. Это хороший подход, если, например, разные команды имеют отдельные пространства имен. Для этого используется другой атрибут namespace: namespace: namespace-name
должен быть перечислен в ClusterRoleBinding в разделе metadata
.
На первый взгляд может показаться, что анонимные изменения в кластере теперь возможны, поскольку принята другая роль. Однако в журналах аудита в Google Cloud Platform можно увидеть фактическое имя пользователя, который внес изменения. Это означает, что можно отследить, какой пользователь внес изменения. Аналогичным образом это работает в управляемых кластерах других облачных провайдеров.
Облачная платформа Google (GCP)
Для того чтобы RBAC и только что описанные корректировки были эффективны в GCP, необходимо сначала обойти первоначальную авторизацию в Google Cloud. Людям, имеющим роли Owner
, Editor
или Kubernetes Engine Admin
в GCP, обычно разрешено выполнять все в кластере, даже если они не имеют явного разрешения RBAC.
Поэтому в IAM необходимо один раз создать в GCP пользовательскую роль, которая разрешает аутентификацию только для кластера Kubernetes. Этой роли, которую мы называем «Kubernetes Engine Authentication», назначаются следующие разрешения:
- container.apiServices.get
- container.apiServices.list
- container.clusters.get
- container.clusters.getCredentials
Теперь эта роль назначается всем пользователям, которым необходим доступ к кластеру. Другие разрешения затем назначаются RBAC в кластере. Роль также может быть назначена целым группам. Управление группами снова осуществляется через группы GSuite. Однако для этого распространение групп должно быть включено при создании кластера (Google Groups for RBAC). К сожалению, этот параметр нельзя активировать задним числом для уже существующего кластера. Для этого он должен быть создан заново.
Заключение
Благодаря использованию RBAC и контекста sudo, усилия по поддержанию разрешений и безопасности находятся в хорошем балансе. С одной стороны, нет необходимости поддерживать разрешения для каждого человека, а с другой стороны, значительно снижается риск нежелательных изменений, например, из-за того, что человек находится в неправильном пространстве имен.
Рассмотрим следующий сценарий: Разработчик тестирует изменения в развертывании в своем локальном кластере dev. В течение рабочего дня мелкие работы выполняются на продуктивном кластере в GCP. Теперь разработчик забывает переключиться обратно на локальный контекст и хочет удалить тестовое развертывание в конце дня. Подобное, конечно, уже случалось с некоторыми людьми. Это может привести к простою или, в худшем случае, к потере данных.
Однако если изменения могут быть применены к производственному кластеру только с использованием контекста sudo или плагина SUDO, случайное удаление будет неудачным, и разработчик заметит свою ошибку. Таким образом, уязвимость к случайным ошибкам становится меньше при сохранении простоты использования, легкости внедрения и высокой безопасности. С тех пор как мы сами используем RBAC и связанный с ним контекст sudo в Cloudogu, мы стали гораздо более безопасно работать на наших кластерах Kubernetes.