← 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:

ОбъектScopeНазначение
RoleNamespaceНабор разрешений внутри одного namespace
ClusterRoleClusterРазрешения на уровне кластера или для non-namespaced ресурсов
RoleBindingNamespaceПривязывает Role (или ClusterRole) к субъекту внутри namespace
ClusterRoleBindingClusterПривязывает ClusterRole к субъекту на уровне всего кластера

Субъект (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:

ClusterRoleЧто даёт
cluster-adminПолный доступ ко всему кластеру. Привязан к группе system:masters
adminПолный доступ внутри namespace, включая управление Role/RoleBinding, кроме quota
editЧтение и запись большинства ресурсов в namespace, кроме Role/RoleBinding
viewТолько чтение в namespace. Не видит содержимое Secret

Используй через 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

Privilege escalation prevention

RBAC встроенно защищается от того, чтобы пользователь выдал сам себе (или другим) больше прав, чем имеет. Два правила, которые enforce'ит API server:

  1. Создание/изменение Role или ClusterRole. Нельзя создать или обновить роль с правами, которых у тебя самого нет. Обойти можно, только если у субъекта явно есть verb escalate на roles/clusterroles.
  2. Создание/изменение RoleBinding или ClusterRoleBinding. Нельзя привязать роль, дающую права сверх твоих собственных. Обойти — только с verb bind на целевую роль.

Пример: пользователь с get pods не может создать Role с create pods, не может забиндить такую роль кому-либо и не может добавить create в существующую роль. Эскалация должна идти через администратора, у которого права уже есть.

escalate и bind — сами по себе опасные verbs: они снимают эту защиту. Выдавать их можно только доверенным контроллерам.

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

Опасные разрешения: least privilege на практике

Официальный гайд по RBAC good practices выделяет разрешения, которые дают эскалацию даже без прямого cluster-admin:

Ресурс / verbПочему опасно
secrets + list/watchвозвращают содержимое всех Secret (не только имена); get без resourceNames — тоже
pods/deployments + createкосвенный доступ к Secret, ConfigMap, PVC и любому SA в namespace через запуск Pod
persistentvolumes + createсоздание hostPath volume → доступ к ФС узла
nodes/proxy + getдоступ к Kubelet API: exec на любом Pod узла, в обход audit и admission
roles/clusterroles + escalate/bindобход защиты от privilege escalation
users/groups/serviceaccounts + impersonateполучить права другого субъекта
certificatesigningrequests + create и .../approval + updateвыпуск клиентских сертификатов с произвольным именем (в т.ч. system-компонентов)
serviceaccounts/token + createвыпуск токенов для чужих SA
mutating-/validatingwebhookconfigurations + create/updateинъекция вредоносного webhook, перехватывающего запросы к API
namespaces + updateснятие Pod Security labels → отключение стандартов безопасности

Общие практики least privilege:

  • Предпочитать RoleBinding (namespace-scoped) вместо ClusterRoleBinding.
  • Избегать wildcard * в resources/verbs/apiGroups.
  • Никогда не добавлять субъектов в группу system:masters — она обходит все RBAC-проверки и не отзывается (зашита в API server).
  • Не давать cluster-admin, кроме случаев крайней необходимости.
  • Ограничивать secrets через resourceNames.
  • Периодически аудитировать биндинги на избыточность и escalation-пути.

source: kubernetes.io/docs/concepts/security/rbac-good-practices/

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

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