Часть 15 цикла статей об изучении k8s!

Мы знаем, что все объекты API в k8s хранятся в Etcd, распределенной базе данных. Однако операции с этими объектами API должны выполняться путем доступа к kube-apiserver. Одна из очень важных причин заключается в том, что вам нужен APIServer, чтобы помочь вам с авторизацией.

Это то, на чем я сосредоточусь сегодня, RBAC (управление доступом на основе ролей): механизм, отвечающий за завершение авторизации в k8s.

k8s RBAC

Существует три основных концепции RBAC:

  1. Роль: на самом деле это набор правил, который определяет набор разрешений на операции с объектами API k8s.
  2. Тема. Может быть «человеком», «машиной» или «пользователем», определенным вами в k8s.
  3. RoleBinding: определяет отношение привязки между «субъектом» и «ролью».

Эти три концепции фактически являются ядром всей системы RBAC.

Роль

На самом деле Роль сама по себе является объектом API k8s, определяемым следующим образом:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: testnamespace
  name: test-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Во-первых, объект Роль указывает Namepace, на что он может оказать влияние: testnamespace .

Namespace — это логическая единица управления в проекте k8s. Объекты API разных пространств имен изолированы друг от друга, когда они управляются с помощью команды kubectl. Например:

kubectl get pods -n testnamespace

Конечно, это ограничено логической «изоляцией», а пространство имен не обеспечивает никакой фактической изоляции или возможностей мультиарендности.

Затем поле правил этого объекта Роль представляет собой правила разрешений, которые он определяет. В приведенном выше примере значение этого правила таково: разрешить «субъекту» выполнять операции GET, WATCH и LIST над объектами Pod под testnamespace.

Привязка Ролей

RoleBinding также является объектом API k8s, как показано ниже:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: test-rolebinding
  namespace: testnamespace
subjects:
- kind: User
  name: test-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: test-role
  apiGroup: rbac.authorization.k8s.io

Как видите, в этом объекте RoleBinding определено поле subject. Его тип User, это пользователь в k8s. Имя этого пользователя test-user. Однако в k8s на самом деле нет объекта API с именем «Пользователь». Более того, в предыдущем процессе развертывания с использованием k8s не было создано User.

На самом деле «Пользователь» в k8s — это всего лишь логическое понятие в системе авторизации. Его необходимо предоставить через внешнюю службу проверки подлинности, например Keystone. Или вы можете напрямую назначить файл имени пользователя и пароля для APIServer. Тогда система авторизации k8s сможет найти соответствующего «пользователя» из этого файла.

Далее мы увидим поле roleRef. RoleBinding объект может напрямую ссылаться на объект Роли (тест-роль), который мы определили ранее по имени через это поле. Тем самым устанавливается связь между «Субъектом» и «Ролью».

Следует еще раз напомнить, что объекты Role и RoleBinding являются объектами Namespace, и их правила ограничения разрешений действуют только в их собственном пространстве имен, а roleRef может ссылаться только на объекты Role в текущем Namespace.

КластерРоле

Что делать, если вы хотите использовать Role для объектов без пространства имен (таких как Node)? В это время вы должны использовать комбинацию ClusterRole и ClusterRoleBinding. Использование этих двух объектов API точно такое же, как у Role и RoleBinding. Однако в их определении нет поля Namespace, т.е.:

Кластерная роль:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: test-clusterrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Кластерролебиндинг:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: test-clusterrolebinding
subjects:
- kind: User
  name: test-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: test-clusterrole
  apiGroup: rbac.authorization.k8s.io

ServiceAccount

Как я упоминал ранее, большую часть времени мы используем не «Пользователь», а «встроенных пользователей»: ServiceAccount в k8s.

Чтобы определить ServiceAccount , вам просто нужен следующий YAML:

apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: testnamespace
  name: test-sa

Тогда вам просто нужно определить RoleBinding

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: test-rolebinding
  namespace: testnamespace
subjects:
- kind: ServiceAccount
  name: test-sa
  namespace: testnamespace
roleRef:
  kind: Role
  name: test-role
  apiGroup: rbac.authorization.k8s.io

Как видите, в этом RoleBinding объекте тип поля subject (kind) больше не User, а ServiceAccount с именем test-sa. Объект Role, на который ссылается roleRef, по-прежнему называется test-role.

Давайте на самом деле создадим их в k8s:

$ kubectl create -f service-account.yaml
$ kubectl create -f role-binding.yaml
$ kubectl create -f role.yaml

Затем проверяем созданный ServiceAccount:

$ kubectl get sa -n testnamespace -o yaml
- apiVersion: v1
  kind: ServiceAccount
  metadata:
    creationTimestamp: 2018-09-08T12:59:17Z
    name: test-sa
    namespace: testnamespace
    resourceVersion: "409327"
    ...
  secrets:
  - name: test-sa-token-vmfg6

Как видите, k8s автоматически создаст и назначит объект Secret для этого ServiceAccount. Этот Secret является файлом авторизации, соответствующим этому ServiceAccount и используемому для взаимодействия с APIServer. Обычно мы называем это «Токен». Содержимое файла Token обычно представляет собой сертификат или пароль, который хранится в Etcd как объект Secret.

В этот момент пользователь Pod может использовать ServiceAccount :

apiVersion: v1
kind: Pod
metadata:
  namespace: testnamespace
  name: sa-token-test
spec:
  containers:
  - name: nginx
    image: nginx:1.7.9
  serviceAccountName: test-sa

После запуска Pod мы видим, что токен ServiceAccount, который является объектом Secret, автоматически монтируется Kubernetes в каталог /var/run/secrets/kubernetes.io/serviceaccount контейнера, как показано ниже:

$ kubectl describe pod sa-token-test -n testnamespace
Name:               sa-token-test
Namespace:          testnamespace
...
Containers:
  nginx:
    ...
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from test-sa-token-vmfg6 (ro)

Приложение в контейнере может использовать этот ca.crt для доступа к APIServer. Что еще более важно, в настоящее время он может выполнять только операции GET, WATCH и LIST. Поскольку разрешение ServiceAccount test-sa было ограничено нашей связующей ролью.

Если Pod не объявляет serviceAccountName, k8s автоматически создаст ServiceAccount по умолчанию с именем default в своем пространстве имен и назначит его поду. Но в данном случае этот ServiceAccount по умолчанию не связан ни с одним Role.

В производственной среде я настоятельно рекомендую привязать роль только для чтения к учетной записи ServiceAccount по умолчанию во всех пространствах имен.

Для системы, встроенной в k8, зарезервировано много ClusterRole, и все их имена начинаются с system. Вы можете проверить их через kubectl get clusterroles.

k8s также предоставляет четыре предопределенных ClusterRoles для непосредственного использования пользователями:

  1. администратор кластера
  2. администратор
  3. редактировать
  4. Посмотреть

Роль cluster-admin имеет самые высокие полномочия (verbs=*) во всем проекте k8s, как показано ниже:

$ kubectl describe clusterrole cluster-admin -n kube-system
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate=true
PolicyRule:
  Resources  Non-Resource URLs Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *.*        []                 []              [*]
             [*]                []              [*]

Поэтому будьте очень осторожны при использовании этой роли.

Вывод

В этой статье я в основном объяснил вам управление доступом на основе ролей (RBAC). По сути, теперь вы можете понять, что так называемая роль (Role) на самом деле представляет собой список правил разрешений. Способ, которым мы назначаем эти разрешения, заключается в привязке субъекта к списку разрешений путем создания объекта RoleBinding.

Надеюсь, вам понравилась эта статья, и увидимся в моей следующей!

Дополнительные материалы на plainenglish.io