Задача 18. RBAC: кто здесь и что ему можно

Под ходит в API и получает Forbidden, хотя роль создана. Разбираем разницу Role и ClusterRole, зачем нужен RoleBinding, почему у каждого пода есть ServiceAccount и как право на создание подов равно правам администратора.
Опубликовано:

Задача

Приложение в поде читает список сервисов через Kubernetes API. Создана роль:

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: service-reader
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "list", "watch"]
Нажмите, чтобы развернуть и увидеть больше

Приложение стабильно получает 403 Forbidden.

Вопрос: чего не хватает и от чьего имени вообще ходит под?

Что кажется очевидным

«Роль создана, права выданы — должно работать». Здесь и кроется путаница: создать роль ≠ выдать права.

Как это работает на самом деле

RBAC в Kubernetes состоит из двух половин, и обе обязательны:

  1. Role / ClusterRoleчто можно делать. Это просто описание набора разрешений; сама по себе роль никому ничего не даёт.
  2. RoleBinding / ClusterRoleBindingкому это можно. Связывает роль с субъектом.

Без второй половины роль — мёртвый объект. Именно этого и не хватает в задаче.

От чьего имени ходит под

У каждого пода есть ServiceAccount. Если не указан явно — это ServiceAccount default того namespace, где под запущен. Его токен монтируется в под:

PLAINTEXT
/var/run/secrets/kubernetes.io/serviceaccount/token
Нажмите, чтобы развернуть и увидеть больше

У default по умолчанию почти нет прав — это правильно. Поэтому первый вопрос при 403: под каким аккаунтом идёт запрос?

Role против ClusterRole

Область действия
RoleРесурсы в одном namespace
ClusterRoleВесь кластер, плюс cluster-scoped ресурсы (ноды, PV, namespace’ы, CRD)

И для привязок:

Что делает
RoleBindingДаёт права в своём namespace — может ссылаться и на Role, и на ClusterRole
ClusterRoleBindingДаёт права во всём кластере

Полезный приём: RoleBinding, ссылающийся на ClusterRole, даёт права этой роли только в пределах своего namespace. Так одну общую роль («читатель») переиспользуют во многих namespace’ах, не давая доступа ко всему кластеру.

Ответ

Не хватает RoleBinding, связывающего роль с ServiceAccount пода:

YAML
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
  namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-app-service-reader
  namespace: production
subjects:
  - kind: ServiceAccount
    name: my-app
    namespace: production
roleRef:
  kind: Role
  name: service-reader
  apiGroup: rbac.authorization.k8s.io
Нажмите, чтобы развернуть и увидеть больше

И под должен использовать именно этот аккаунт:

YAML
spec:
  serviceAccountName: my-app
Нажмите, чтобы развернуть и увидеть больше

Без последней строки под продолжит ходить от default — и права так и не применятся.

Что с этим делать

Проверка прав

Самый быстрый инструмент — auth can-i с подстановкой субъекта:

BASH
# Может ли конкретный ServiceAccount читать сервисы
kubectl auth can-i list services \
  --as=system:serviceaccount:production:my-app \
  -n production

# Полный список того, что ему разрешено
kubectl auth can-i --list \
  --as=system:serviceaccount:production:my-app \
  -n production
Нажмите, чтобы развернуть и увидеть больше

Это избавляет от гаданий: команда отвечает ровно то же, что ответит API server приложению.

Опасные разрешения

Некоторые права выглядят безобидно, но фактически означают полный контроль:

Отсюда практическое правило: раздавая доступ «только на деплой», вы фактически раздаёте очень много. Отделяйте namespace’ы и используйте Pod Security Admission.

Гигиена

Токены

Современные токены ServiceAccount — короткоживущие и привязанные к поду: они выдаются через projected volume, автоматически ротируются и становятся недействительными при удалении пода. Старая модель с «вечным» токеном в Secret устарела; если в кластере остались такие Secret’ы — это кандидаты на удаление.


Дальше: Задача 19. Нода под давлением: кого вытеснят первым.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша