Понимаем RBAC в Kubernetes

https://www.cncf.io/blog/2018/08/01/demystifying-rbac-in-kubernetes/
  • Перевод
Прим. перев.: Статья написана Javier Salmeron — инженером из хорошо известной в Kubernetes-сообществе компании Bitnami — и была опубликована в блоге CNCF в начале августа. Автор рассказывает о самых основах механизма RBAC (управление доступом на основе ролей), появившегося в Kubernetes полтора года назад. Материал будет особенно полезным для тех, кто знакомится с устройством ключевых компонентов K8s (ссылки на другие подобные статьи см. в конце).


Слайд из презентации, сделанной сотрудником Google по случаю релиза Kubernetes 1.6

Многие опытные пользователи Kubernetes могут вспомнить релиз Kubernetes 1.6, когда авторизация на основе Role-Based Access Control (RBAC) получила статус бета-версии. Так появился альтернативный механизм аутентификации, который дополнил уже существующий, но трудный в управлении и понимании, — Attribute-Based Access Control (ABAC). Все с восторгом приветствовали новую фичу, однако в то же время бесчисленное число пользователей были разочарованы. StackOverflow и GitHub изобиловали сообщениями об ограничениях RBAC, потому что большая часть документации и примеров не учитывали RBAC (но сейчас уже всё в порядке). Эталонным примером стал Helm: простой запуск helm init + helm install больше не работал. Внезапно нам потребовалось добавлять «странные» элементы вроде ServiceAccounts или RoleBindings ещё до того, как разворачивать чарт с WordPress или Redis (подробнее об этом см. в инструкции).

Оставив же эти неудачные первые попытки в стороне, нельзя отрицать тот огромный вклад, что внёс RBAC в превращение Kubernetes в готовую к production платформу. Многие из нас успели поиграть с Kubernetes с полными привилегиями администратора, и мы прекрасно понимаем, что в реальном окружении необходимо:

  • Иметь множество пользователей с разными свойствами, обеспечивающими нужный механизм аутентификации.
  • Иметь полный контроль над тем, какие операции может исполнять каждый пользователь или группа пользователей.
  • Иметь полный контроль над тем, какие операции может исполнять каждый процесс в поде.
  • Ограничивать видимость определённых ресурсов в пространствах имён.

И в этом отношении RBAC — ключевой элемент, предоставляющий столь необходимые возможности. В статье мы быстро пройдёмся по основам (для подробностей смотрите это видео; по ссылке 1-часовой вебинар от Bitnami на английском языке — прим. перев.) и немного углубимся в самые запутанные моменты.

Ключ к пониманию RBAC в Kubernetes


Чтобы полностью осознать идею RBAC, нужно понимать, что к ней причастны три элемента:

  • Subjects (субъекты) — совокупность пользователей и процессов, которые хотят иметь доступ в Kubernetes API;
  • Resources (ресурсы) — совокупность объектов Kubernetes API, доступных в кластере. Их примерами (среди прочих) являются Pods, Deployments, Services, Nodes, PersistentVolumes;
  • Verbs (глаголы) — совокупность операций, которые могут быть выполнены над ресурсами. Существуют различные verbs (get, watch, create, delete и т.п.), но все они в конечном счёте являются операциями из разряда CRUD (Create, Read, Update, Delete).



Если помнить об этих трёх элементах, ключевая идея RBAC звучит так:

— Мы хотим соединить субъекты, ресурсы API и операции. Другими словами, мы хотим указать для заданного пользователя, какие операции могут быть исполнены на множестве ресурсов.

Разбираемся с объектами RBAC в API


В соединении этих трёх типов сущностей становятся понятными и доступные в Kubernetes API объекты RBAC:

  • Roles соединяют ресурсы и глаголы. Они могут повторно использоваться для разных субъектов. Привязаны к одному пространству имён (мы не можем использовать шаблоны, представляющие более одного [пространства имён], зато можем деплоить один и тот же объект роли в разные пространства имён). Если вы хотите применить роль ко всему кластеру, есть аналогичный объект ClusterRoles.
  • RoleBindings соединяют оставшиеся сущности-субъекты. Указав роль, которая уже связывает объекты API с глаголами, теперь мы выбираем субъекты, которые могут их использовать. Эквивалентом для уровня кластера (т.е. без привязки к пространствам имён) является ClusterRoleBindings.

В примере ниже мы выдаём пользователю jsalmeron право на чтение, получение списка и создание подов в пространстве имён test. Это означает, что jsalmeron сможет выполнять такие команды:

kubectl get pods --namespace test
kubectl describe pod --namespace test pod-name
kubectl create --namespace test -f pod.yaml # в этом файле описание пода

… но не такие:

kubectl get pods --namespace kube-system # другое пространство имён
kubectl get pods --namespace test -w # требует также глагола watch



Примеры YAML-файлов:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: pod-read-create
  namespace: test
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "create"]

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: salme-pods
  namespace: test
subjects:
- kind: User
  name: jsalmeron
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-read-create
  apiGroup: rbac.authorization.k8s.io

Другой интересный момент в следующем: теперь, когда пользователь может создавать поды, можем ли мы ограничить, как много? Для этого потребуются другие объекты, не относящиеся напрямую к спецификации RBAC и позволяющие настраивать ограничения по количеству ресурсов: ResourceQuota и LimitRanges. Их определённо стоит изучить при конфигурации столь важной составляющей кластера [как создание подов].

Субъекты: пользователи и… ServiceAccounts?


Одной из сложностей, с которой сталкиваются многие пользователи Kubernetes в контексте субъектов, является различие между обычными пользователями и ServiceAccounts. В теории всё просто:

  • Users — глобальные пользователи, предназначены для людей или процессов, живущих вне кластера;
  • ServiceAccounts — ограниченные пространством имён и предназначенные для процессов внутри кластера, запущенных на подах.

Сходство обоих типов заключается в необходимости аутентифицироваться в API для исполнения определённых операций над множеством ресурсов, и их предметные области выглядят весьма конкретными. Они также могут относиться к группам, поэтому RoleBinding позволяет привязывать более одного субъекта (хотя для ServiceAccounts допустима лишь одна группа — system:serviceaccounts). Тем не менее, основное отличие и есть причина головной боли: у пользователей нет соответствующих им объектов в Kubernetes API. Получается, что такая операция существует:

kubectl create serviceaccount test-service-account # OK

… но вот такой уже нет:

kubectl create user jsalmeron # Ошибка!

У этой ситуации серьёзное последствие: если кластер не будет хранить информацию о пользователях, администратору придётся управлять учётными записями вне кластера. Здесь есть разные способы решения проблемы: TLS-сертификаты, токены, OAuth2 и т.п.

Вдобавок, потребуется создать контексты kubectl, чтобы мы могли получить доступ к кластеру через эти новые учётные записи. Чтобы создать файлы с ними, можно воспользоваться командами kubectl config (что не требуют доступа к Kubernetes API, поэтому могут исполняться любым пользователем). В приведённом выше видео есть пример по созданию пользователя с TLS-сертификатами.

RBAC в Deployments: пример


Мы видели пример, в котором указанному пользователю выдаются права на операции в кластере. Но что насчёт Deployments, требующих доступа к Kubernetes API? Рассмотрим конкретный сценарий, чтобы разобраться получше.

Возьмём для примера популярное инфраструктурное приложение — RabbitMQ. Будем использовать Helm-чарт для RabbitMQ от Bitnami (из официального репозитория helm/charts), который использует контейнер bitnami/rabbitmq. В контейнер встроен плагин для Kubernetes, отвечающий за обнаружение других членов кластера RabbitMQ. Из-за этого процесс внутри контейнера требует доступа к Kubernetes API, и нам потребуется настроить ServiceAccount с правильными RBAC-привилегиями.

Когда речь заходит о ServiceAccounts, следуйте этой хорошей практике:

— Настраивайте ServiceAccounts для каждого Deployment с минимальным набором привилегий.

В случае приложений, требующих доступа к Kubernetes API, у вас может возникнуть соблазн создать некий «привилегированный ServiceAccount», который сможет делать в кластере практически всё. Хотя это кажется более простым решением, в конечном счёте оно может привести к уязвимости в безопасности, позволяющей выполнять нежелательные операции. (В видео рассматривается пример Tiller [компонента Helm] и последствий наличия ServiceAccounts с большими привилегиями.)

Вдобавок, у разных Deployments будут разные потребности в смысле доступа к API, поэтому для каждого Deployment разумно иметь разные ServiceAccounts.

Не забывая об этом, посмотрим, какая конфигурация RBAC будет правильной для случая Deployment'а с RabbitMQ.

В документации плагина и его исходном коде можно увидеть, что он запрашивает у Kubernetes API список Endpoints. Так и происходит обнаружение остальных членов кластера RabbitMQ. Поэтому чарт RabbitMQ от Bitnami создаёт:

  • ServiceAccount для подов с RabbitMQ:

    {{- if .Values.rbacEnabled }}
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: {{ template "rabbitmq.fullname" . }}
      labels:
        app: {{ template "rabbitmq.name" . }}
        chart: {{ template "rabbitmq.chart" .  }}
        release: "{{ .Release.Name }}"
        heritage: "{{ .Release.Service }}"
    {{- end }}
  • Role (мы предполагаем, что весь кластер RabbitMQ разворачивается в едином пространстве имён), разрешающую глагол get для ресурса Endpoint:

    {{- if .Values.rbacEnabled }}
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: {{ template "rabbitmq.fullname" . }}-endpoint-reader
      labels:
        app: {{ template "rabbitmq.name" . }}
        chart: {{ template "rabbitmq.chart" .  }}
        release: "{{ .Release.Name }}"
        heritage: "{{ .Release.Service }}"
    rules:
    - apiGroups: [""]
      resources: ["endpoints"]
      verbs: ["get"]
    {{- end }}
  • RoleBinding, соединяющую ServiceAccount с ролью:

    {{- if .Values.rbacEnabled }}
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: {{ template "rabbitmq.fullname" . }}-endpoint-reader
      labels:
        app: {{ template "rabbitmq.name" . }}
        chart: {{ template "rabbitmq.chart" .  }}
        release: "{{ .Release.Name }}"
        heritage: "{{ .Release.Service }}"
    subjects:
    - kind: ServiceAccount
      name: {{ template "rabbitmq.fullname" . }}
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: {{ template "rabbitmq.fullname" . }}-endpoint-reader
    {{- end }}



Схема показывает, что мы разрешили процессам, запущенным в подах RabbitMQ, исполнять операции get над объектами Endpoint. Это минимальный набор операций, который требуется для того, чтобы всё работало. В то же время мы знаем, что развёрнутый чарт безопасен и не выполнит нежелательных действий внутри кластера Kubernetes.

Заключительные мысли


Чтобы работать с Kubernetes в production, политики RBAC не являются опциональными. Их нельзя рассматривать как набор объектов API, который должны знать только администраторы. Они на самом деле нужны разработчикам для развёртывания безопасных приложений и полного использования потенциала, предлагаемого Kubernetes API для облачных (cloud native) приложений. Больше информации по RBAC можно получить по этим ссылкам:


P.S. от переводчика


Читайте также в нашем блоге:

  • +29
  • 6,9k
  • 8
Флант
265,00
Специалисты по DevOps и высоким нагрузкам в вебе
Поделиться публикацией

Комментарии 8

    0
    Часто в примерах настройки доступа разработчикам к API с помощью RBAC используют ServiceAccount.
    А как делаете вы?
      0

      Разработчикам — это юзерам или их подам?

        0
        юзерам -)
          0
          ServiceAccount
      0
      Вот тут ещё на днях появилась статья «Testing Kubernetes RBAC»:

      [..] this post will focus on how to ensure your business’s compliance and requirements are actually being adhered to and to ensure that we need to test our applied RBAC objects, to ensure they do what we intend them to do.
        +1
        Если я все правильно понимаю — у Вас в описании RoleBinding вкралась ошибка — Вы ссылаетесь не на ту роль
          0
          Ошибка перекочевала из оригинала, который переводили… Спасибо, исправил!
          0
          непонятно. если нельзя сделать kubectl create user
          то как вообще пользователи в кластере появляются? и как их создавать и манагерить правильно? LDAP?

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое