← Back to notes

RBAC: управление доступом
в Kubernetes


RBAC — стандартный механизм авторизации в Kubernetes: кто может делать что с какими ресурсами. Включается флагом --authorization-mode=RBAC на kube-apiserver; в kubeadm, EKS, GKE, AKS, k3s — по умолчанию.

RBAC работает аддитивно: можно только разрешать, явного deny нет. Если ни одна роль не покрывает запрос — он запрещён. Least-privilege by default: новый ServiceAccount без привязок ничего не может.

Запрос к apiserver проходит три стадии: аутентификация (кто ты), авторизация (что можно), admission control (соответствует ли политикам). RBAC — только вторая стадия.

[source: kubernetes.io/docs/reference/access-authn-authz/rbac/]

Четыре объекта RBAC

Четыре объекта, разделённые по scope:

Субъект (subject) — кто получает права:

  • User — аутентифицирован через OIDC, X.509-сертификат, токен
  • Group — группа пользователей (system:masters, system:authenticated)
  • ServiceAccount — машинный аккаунт для Pod

User и Group — внешние идентичности (Kubernetes их не хранит). ServiceAccount — единственный нативный объект K8s API среди субъектов.

Структура правила (rule)

Три обязательных поля:

  • apiGroups"" для core (Pod, Service, ConfigMap, Secret), "apps" для Deployment/StatefulSet/DaemonSet, "batch" для Job/CronJob, "networking.k8s.io" для Ingress/NetworkPolicy
  • resourcespods, deployments, secrets, configmaps и т.д.
  • verbsget, list, watch, create, update, patch, delete, deletecollection

Опциональное resourceNames ограничивает доступ конкретными объектами (например, только Secret db-password).

Разница verbs: get — один объект по имени, list — список, watch — подписка на события. update — замена объекта целиком, patch — частичное обновление. deletecollection — удалить по label-селектору (отдельный verb от delete).

Role — права внутри namespace

Role — namespace-scoped объект. Права из Role применяются только в том namespace, где она создана.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: app
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create"]

pods/log, pods/exec, pods/portforward — sub-resources, задаются отдельно от pods.

ClusterRole — права на уровне кластера

ClusterRole нужна в двух случаях:

  1. Права на non-namespaced ресурсы: nodes, persistentvolumes, namespaces, clusterroles, storageclasses
  2. Права, которые хочется переиспользовать в нескольких namespace без дублирования
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-wide-reader
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps", "nodes", "namespaces"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets", "statefulsets", "daemonsets"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
  resources: ["jobs", "cronjobs"]
  verbs: ["get", "list", "watch"]

nodes — non-namespaced ресурс, его можно задать только в ClusterRole.

RoleBinding — привязка роли к субъекту

RoleBinding связывает роль с субъектом в namespace. Может ссылаться на Role или ClusterRole; во втором случае права применяются только в namespace этого RoleBinding — основной механизм переиспользования ролей.

Привязка dev-ivan к Role pod-reader в namespace app:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-binding
  namespace: app
subjects:
- kind: User
  name: dev-ivan
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Три типа субъектов в одном RoleBinding:

subjects:
# Пользователь
- kind: User
  name: dev-ivan
  apiGroup: rbac.authorization.k8s.io
# Группа
- kind: Group
  name: developers
  apiGroup: rbac.authorization.k8s.io
# ServiceAccount
- kind: ServiceAccount
  name: my-app-sa
  namespace: app

Все субъекты в одном RoleBinding получают одинаковые права.

RoleBinding на ClusterRole

Паттерн для multi-tenant: одна ClusterRole, RoleBinding в каждом namespace.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-alpha-view
  namespace: alpha
subjects:
- kind: Group
  name: team-alpha
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole   # ссылается на ClusterRole
  name: view          # встроенная ClusterRole
  apiGroup: rbac.authorization.k8s.io

Группа team-alpha получает view (read-only) только в namespace alpha.

ClusterRoleBinding — права на весь кластер

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-reader-binding
subjects:
- kind: User
  name: dev-ivan
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-wide-reader
  apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding даёт права во всех namespace и на cluster-scoped ресурсы. Только для системных компонентов, операторов, мониторинговых агентов.

Встроенные ClusterRole

Четыре заготовленные ClusterRole:

Используй через RoleBinding вместо кастомных ролей. Для "дай разработчику доступ в namespace" встроенных хватает.

Посмотреть содержимое:

kubectl describe clusterrole view
kubectl describe clusterrole edit
kubectl describe clusterrole admin

Aggregated ClusterRoles

admin, edit, view поддерживают агрегацию: другие ClusterRole расширяют их через label. Операторы добавляют права на свои CRD в стандартные роли без патчинга.

Пример: CRD-оператор добавляет ресурсы в view:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: myapp-viewer
  labels:
    rbac.authorization.k8s.io/aggregate-to-view: "true"
rules:
- apiGroups: ["myapp.example.com"]
  resources: ["widgets", "gadgets"]
  verbs: ["get", "list", "watch"]

view имеет aggregationRule с селектором rbac.authorization.k8s.io/aggregate-to-view: "true" — Kubernetes подтянет эти rules. Аналогичные label есть для edit и admin.

Проверить:

kubectl get clusterrole view -o yaml | grep aggregationRule -A 10

[source: kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles]

Диагностика: kubectl auth can-i

Проверка и отладка прав:

# Могу ли я создать Deployment в текущем namespace?
kubectl auth can-i create deployments

# Может ли dev-ivan читать Pod в namespace app?
kubectl auth can-i get pods --namespace app --as dev-ivan

# Может ли ServiceAccount my-sa в namespace app читать secrets?
kubectl auth can-i get secrets --namespace app \
  --as system:serviceaccount:app:my-sa

# Список всех разрешённых действий в namespace для пользователя
kubectl auth can-i --list --namespace app --as dev-ivan

# Проверить доступ к конкретному sub-resource
kubectl auth can-i create pods/exec --namespace app --as dev-ivan

Формат impersonation для SA: system:serviceaccount:<namespace>:<name>.

Ограничение: can-i проверяет authorization layer через SelfSubjectAccessReview и работает с настроенным authorizer chain. Admission Controllers (OPA/Gatekeeper, Kyverno, PodSecurity), ResourceQuota и LimitRange он не проверяет: запрос может пройти authorization и быть отклонён на admission.

kubectl auth reconcile

Для применения RBAC из GitOps:

# Проверить и применить RBAC-манифесты без лишних изменений
kubectl auth reconcile -f rbac-manifests/

# Посмотреть, что изменится (dry-run)
kubectl auth reconcile -f rbac-manifests/ --dry-run=client

reconcile идемпотентен: он добавляет недостающие rules, но не удаляет лишние.

Полный пример: read-only доступ для разработчика

Задача: дать dev-ivan право читать Pod и их логи в namespace app, запускать exec, но не изменять и не удалять ничего.

---
apiVersion: v1
kind: Namespace
metadata:
  name: app
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: app
  name: dev-readonly
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "services", "configmaps"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-ivan-readonly
  namespace: app
subjects:
- kind: User
  name: dev-ivan
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-readonly
  apiGroup: rbac.authorization.k8s.io

Проверка:

kubectl auth can-i get pods --namespace app --as dev-ivan      # yes
kubectl auth can-i delete pods --namespace app --as dev-ivan   # no
kubectl auth can-i get secrets --namespace app --as dev-ivan   # no
kubectl auth can-i create pods/exec --namespace app --as dev-ivan  # yes

Когда использовать

Role + RoleBinding — изолированный namespace: разработчики команды, CI-пайплайн проекта, приложение с доступом к своим ресурсам. По умолчанию.

ClusterRole + RoleBinding в разных namespace — один набор прав в нескольких namespace без дублирования.

ClusterRole + ClusterRoleBinding — мониторинг (Prometheus, Datadog), Kubernetes operators с CRD кластерного уровня, компоненты control plane.

Встроенные роли (view, edit, admin) — стандартный уровень доступа без кастомизации. Расширяются через Aggregated ClusterRoles для CRD.

Типичные ошибки

apiGroups: [""] для apps-ресурсов. Deployment/StatefulSet/DaemonSet/ReplicaSet — в apps, Job/CronJob — в batch. apiGroups: [""] с resources: ["deployments"] не сработает (без явной ошибки).

# Неправильно  deployments в core group не существует
rules:
- apiGroups: [""]
  resources: ["deployments"]
  verbs: ["get", "list"]

# Правильно
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list"]

Проверка: kubectl api-resources | grep deployment — столбец APIVERSION покажет apps/v1.

ClusterRoleBinding вместо RoleBinding. Случайно выдал права на весь кластер вместо namespace. Проверяй kind объекта и roleRef.

Забыли sub-resources. kubectl logspods/log, execpods/exec, port-forwardpods/portforward, attachpods/attach. Не включаются автоматически в права на pods.

roleRef immutable. Чтобы изменить — удали и создай заново. kubectl apply выдаст ошибку.

can-i отвечает yes, но доступ закрыт. Сработал Admission Controller (OPA/Gatekeeper, Kyverno) или PodSecurity.

Права на secrets без resourceNames. Кто может get secrets — видит все токены, пароли, TLS-ключи. Используй resourceNames для конкретного Secret.

rules:
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["db-password"]  # только этот конкретный Secret
  verbs: ["get"]

Альтернативы

ABAC — ранний механизм через файл политик на диске apiserver. Требует перезапуска при изменениях. В современных кластерах не используется.

Webhook Authorization — apiserver отправляет каждый запрос на внешний HTTP-эндпоинт. Для кастомной логики, недостижимой в RBAC: права от времени суток, внешней БД, атрибутов объекта.

OPA/Gatekeeper, Kyverno — дополнение к RBAC на уровне Admission. Политики по содержимому манифестов: запрет hostNetwork: true, registry whitelist, обязательные label. RBAC контролирует может ли субъект, Gatekeeper — соответствует ли объект.

[source: kubernetes.io/docs/reference/access-authn-authz/authorization/]


14: Справочник kubectl | 16: ServiceAccount

RBAC: управление доступом в Kubernetes | Aleksandr Suprun