Часть 15 цикла статей об изучении k8s!
Мы знаем, что все объекты API в k8s хранятся в Etcd
, распределенной базе данных. Однако операции с этими объектами API должны выполняться путем доступа к kube-apiserver
. Одна из очень важных причин заключается в том, что вам нужен APIServer, чтобы помочь вам с авторизацией.
Это то, на чем я сосредоточусь сегодня, RBAC (управление доступом на основе ролей): механизм, отвечающий за завершение авторизации в k8s.
k8s RBAC
Существует три основных концепции RBAC:
- Роль: на самом деле это набор правил, который определяет набор разрешений на операции с объектами API k8s.
- Тема. Может быть «человеком», «машиной» или «пользователем», определенным вами в k8s.
- 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 для непосредственного использования пользователями:
- администратор кластера
- администратор
- редактировать
- Посмотреть
Роль 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