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 | Назначение |
|---|---|---|
Role | Namespace | Набор разрешений внутри одного namespace |
ClusterRole | Cluster | Разрешения на уровне кластера или для non-namespaced ресурсов |
RoleBinding | Namespace | Привязывает Role (или ClusterRole) к субъекту внутри namespace |
ClusterRoleBinding | Cluster | Привязывает 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 - resources —
pods,deployments,secrets,configmapsи т.д. - verbs —
get,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 нужна в двух случаях:
- Права на non-namespaced ресурсы:
nodes,persistentvolumes,namespaces,clusterroles,storageclasses - Права, которые хочется переиспользовать в нескольких 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:
- Создание/изменение Role или ClusterRole. Нельзя создать или обновить роль с правами, которых у тебя самого нет. Обойти можно, только если у субъекта явно есть verb
escalateнаroles/clusterroles. - Создание/изменение 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 logs → pods/log, exec → pods/exec, port-forward → pods/portforward, attach → pods/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/