RBAC: кто что может
Кто угодно с доступом к кластеру может удалить всё — если вы не настроили RBAC.
RBAC (Role-Based Access Control) — модель доступа Kubernetes, где правила (что можно делать с какими ресурсами) собираются в роли, а роли привязываются к пользователям, группам и сервис-аккаунтам.
По умолчанию свежий кластер уже включает RBAC, но это не значит, что он настроен правильно. Очень частая ситуация: разработчику выдают cluster-admin, потому что «так быстрее», и CI-пайплайн ходит в кластер под тем же всемогущим токеном. Один скомпрометированный токен — и атакующий хозяйничает во всём кластере. RBAC нужен, чтобы каждый субъект (человек или процесс) имел ровно те права, что ему действительно нужны, и ни одним больше.
Зачем это на практике
Представьте команду из трёх групп: разработчики деплоят приложения в свой namespace, дежурные смотрят логи во всём кластере, а CI применяет манифесты только в staging. Без RBAC все они либо ничего не могут, либо могут всё. С RBAC вы описываете три набора прав и спокойно спите: даже если токен CI утечёт, атакующий не выйдет за пределы staging и не доберётся до секретов в prod.
Четыре кирпичика RBAC
Модель строится из четырёх объектов. Два описывают что можно, два — кому это можно:
| Объект | Область | Назначение |
Role | один namespace | набор разрешённых действий над ресурсами namespace |
ClusterRole | весь кластер | права на кластерные ресурсы (nodes, PV) или общий шаблон |
RoleBinding | один namespace | привязывает Role или ClusterRole к субъектам в namespace |
ClusterRoleBinding | весь кластер | привязывает ClusterRole к субъектам во всём кластере |
Role: права в одном namespace
Опишем роль, которая разрешает только читать поды и их логи в namespace dev — ни создавать, ни удалять:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-reader
rules:
- apiGroups: [""] # "" — core API group (pods, services)
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
Поле verbs — это и есть разрешённые глаголы: get, list, watch, create, update, patch, delete. Здесь нет create и delete — значит, обладатель роли физически не сможет менять поды.
RoleBinding: кому выдать роль
Роль без привязки не делает ничего. Свяжем её с сервис-аккаунтом ci-bot:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-can-read-pods
namespace: dev
subjects:
- kind: ServiceAccount
name: ci-bot
namespace: dev
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Применяем оба манифеста обычной командой:
kubectl apply -f pod-reader.yaml -f ci-can-read-pods.yaml
ServiceAccount: личность пода
Люди заходят в кластер по сертификатам или OIDC, а вот процессы внутри подов ходят в API-сервер от имени ServiceAccount. Если под не указал свой SA, он получает default в своём namespace. Создаём отдельный аккаунт под конкретную задачу:
kubectl create serviceaccount ci-bot -n dev
И указываем его в поде, чтобы приложение работало именно с нашими ограниченными правами:
apiVersion: v1
kind: Pod
metadata:
name: deployer
namespace: dev
spec:
serviceAccountName: ci-bot
automountServiceAccountToken: true # токен монтируется в под
containers:
- name: app
image: my-deployer:1.4
Если приложению вообще не нужен доступ к API Kubernetes, поставьте automountServiceAccountToken: false — тогда токен не попадёт внутрь контейнера, и красть будет нечего.
Принцип минимальных привилегий
Главное правило безопасности доступа: выдавайте минимум, расширяйте по необходимости. Практические следствия:
- Начинайте с пустой роли и добавляйте глаголы, когда приложение реально упёрлось в отказ.
- Предпочитайте
Roleв namespace, а неClusterRoleна весь кластер. - Никогда не выдавайте
cluster-adminсервис-аккаунтам приложений и пайплайнов. - Избегайте wildcard:
resources: ["*"]иverbs: ["*"]сводят весь смысл RBAC к нулю.
Как это работает под капотом
RBAC — это аддитивная модель: разрешено только то, что явно дано хотя бы одним binding. Запрещающих правил в RBAC нет вообще — нельзя «забрать» доступ отдельным deny. Если субъект подпадает под несколько ролей, его итоговые права — объединение всех. Поэтому одна лишняя широкая роль перечёркивает десяток узких.
Когда приходит запрос к API-серверу, он проходит цепочку: сначала аутентификация (кто ты — сертификат, токен SA, OIDC), затем авторизация (RBAC-модуль ищет хоть один разрешающий rule), и только потом admission-контроль. RBAC отвечает строго за второй шаг — «можно ли этому субъекту такой глагол над таким ресурсом».
Частые ошибки
- cluster-admin «на время», который остаётся навсегда. Временный доступ почти всегда становится постоянным.
- RoleBinding на встроенную ClusterRole вроде
editилиadminбез понимания, что именно она открывает (а она открывает и работу с секретами). - Привязка к группе
system:authenticated— это буквально «любой, кто вошёл в кластер». - Забытый
automountServiceAccountToken: токенdefaultлежит в каждом поде и часто имеет больше прав, чем кажется.
Проверка прав: kubectl auth can-i
Не угадывайте, что разрешено, — спросите кластер напрямую. Команда kubectl auth can-i отвечает yes или no:
# Могу ли я (текущий пользователь) удалять поды в dev?
kubectl auth can-i delete pods -n dev
# А что может конкретный сервис-аккаунт? Подставляем его через --as
kubectl auth can-i list secrets -n dev \
--as=system:serviceaccount:dev:ci-bot
# Полный аудит: все действия, доступные субъекту
kubectl auth can-i --list -n dev \
--as=system:serviceaccount:dev:ci-bot
Вывод:
no no Resources Non-Resource URLs Resource Names Verbs pods [] [] [get list watch] pods/log [] [] [get list watch]
Флаг --as (impersonation) позволяет проверить чужие права, не зная их токена. Делайте такой аудит частью ревью манифестов: если --list показывает что-то лишнее, правьте роль до выката.
Итоги
- RBAC включён по умолчанию, но безопасность даёт только осознанная настройка.
Role/ClusterRoleописывают права,RoleBinding/ClusterRoleBinding— кому их дать.- Процессы в подах ходят в API под
ServiceAccount; давайте каждому свой, минимальный. - Модель аддитивная: лишняя широкая роль сводит на нет все узкие — избегайте wildcard и
cluster-admin. - Проверяйте реальные права через
kubectl auth can-iи--asещё до выката.